emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Hope ob-js can support :session feature
@ 2017-12-22 11:57 stardiviner
  2017-12-22 18:32 ` Martin Alsinet
  0 siblings, 1 reply; 6+ messages in thread
From: stardiviner @ 2017-12-22 11:57 UTC (permalink / raw)
  To: emacs-orgmode

I know that ob-js "Session evaluation with node.js is not supported"

- [X] mozrepl (deprecated):
   "mozrepl" need package `moz'. https://github.com/bard/mozrepl/
- [X] node.js does not support :session

so might consider integrate indium https://github.com/NicolasPetton/Indium ?

I wish to do JavaScript Literate Programming in Org-mode.

So the :session header argument is very necessary.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Hope ob-js can support :session feature
  2017-12-22 11:57 Hope ob-js can support :session feature stardiviner
@ 2017-12-22 18:32 ` Martin Alsinet
  2017-12-23  1:07   ` numbchild
  0 siblings, 1 reply; 6+ messages in thread
From: Martin Alsinet @ 2017-12-22 18:32 UTC (permalink / raw)
  To: stardiviner; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 1918 bytes --]

Hello stardiviner,

On Fri, Dec 22, 2017 at 6:57 AM stardiviner <numbchild@gmail.com> wrote:

>
> I wish to do JavaScript Literate Programming in Org-mode.
>
> So the :session header argument is very necessary.
>
>
I do Literate Programming in Javascript with Org-mode, and I have found a
workaround using a combination of tangled files and require.

I separate the logic in source code blocks which then I tangle into js
files and I require those js files in other source blocks.

Example:

#+BEGIN_SRC js :tangle src/parser.js
const fs = require('fs');
const parse = require('csv-parse')

function columns(line){
    return line.map(s => s.toLowerCase());
}
parse_csv = function(filename, fn, limit){
    fs.readFile(filename, "utf8", function (err, fileData) {
        var opts = {columns: columns, trim: true};
        if (limit) {
            opts.to = limit;
        }
        parse(fileData, opts, (err, rows) => fn(rows));
    });
}
module.exports = parse_csv;
#+END_SRC

So, I tangle that source block into a js file, and then I can use it from
other blocks, without needing sessions at all:

#+BEGIN_SRC
const parser = require("/app/src/parser.js");
const inputFile = './data/records.csv';
parse_csv(inputFile, console.log);
#+END_SRC

The only drawback is that you have to use absolute paths requiring the js
files, but since I am using docker containers to run node, I always mount
the current directory as a volume in /app inside the container, so that
works out fine.
I also think that this way forces me to separate the code in modular
blocks, which is already a good practice in itself.
With sessions you have to make sure to execute the blocks in the correct
order to build the "state" that your current block needs.
This way source blocks function as standalone units that can be run at any
time, I just run *org-babel-tangle* and then hit *C-c *inside the js block.

I hope that helps you.


Martin

[-- Attachment #2: Type: text/html, Size: 3603 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Hope ob-js can support :session feature
  2017-12-22 18:32 ` Martin Alsinet
@ 2017-12-23  1:07   ` numbchild
  2017-12-23  3:06     ` Martin Alsinet
  0 siblings, 1 reply; 6+ messages in thread
From: numbchild @ 2017-12-23  1:07 UTC (permalink / raw)
  To: Martin Alsinet; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 3035 bytes --]

Can you describe how do you do this in detailed?
Like:
> but since I am using docker containers to run node, I always mount the
current directory as a volume in /app inside the container, so that works
out fine.
> I also think that this way forces me to separate the code in modular
blocks, which is already a good practice in itself.
How to do this? About this: > With sessions you have to make sure to
execute the blocks in the correct order to build the "state" that your
current block needs.
I think have to use `noweb` reference here.
(If you have a blog article describe this whole JS literate programming
setup, that will be useful.)
Finally, thanks you provide this paradigm.

[stardiviner]           <Hack this world!>      GPG key ID: 47C32433
IRC(freeenode): stardiviner                     Twitter:  @numbchild
Key fingerprint = 9BAA 92BC CDDD B9EF 3B36  CB99 B8C4 B8E5 47C3 2433
Blog: http://stardiviner.github.io/

On Sat, Dec 23, 2017 at 2:32 AM, Martin Alsinet <martin@alsinet.com.ar>
wrote:

> Hello stardiviner,
>
> On Fri, Dec 22, 2017 at 6:57 AM stardiviner <numbchild@gmail.com> wrote:
>
>>
>> I wish to do JavaScript Literate Programming in Org-mode.
>>
>> So the :session header argument is very necessary.
>>
>>
> I do Literate Programming in Javascript with Org-mode, and I have found a
> workaround using a combination of tangled files and require.
>
> I separate the logic in source code blocks which then I tangle into js
> files and I require those js files in other source blocks.
>
> Example:
>
> #+BEGIN_SRC js :tangle src/parser.js
> const fs = require('fs');
> const parse = require('csv-parse')
>
> function columns(line){
>     return line.map(s => s.toLowerCase());
> }
> parse_csv = function(filename, fn, limit){
>     fs.readFile(filename, "utf8", function (err, fileData) {
>         var opts = {columns: columns, trim: true};
>         if (limit) {
>             opts.to = limit;
>         }
>         parse(fileData, opts, (err, rows) => fn(rows));
>     });
> }
> module.exports = parse_csv;
> #+END_SRC
>
> So, I tangle that source block into a js file, and then I can use it from
> other blocks, without needing sessions at all:
>
> #+BEGIN_SRC
> const parser = require("/app/src/parser.js");
> const inputFile = './data/records.csv';
> parse_csv(inputFile, console.log);
> #+END_SRC
>
> The only drawback is that you have to use absolute paths requiring the js
> files, but since I am using docker containers to run node, I always mount
> the current directory as a volume in /app inside the container, so that
> works out fine.
> I also think that this way forces me to separate the code in modular
> blocks, which is already a good practice in itself.
> With sessions you have to make sure to execute the blocks in the correct
> order to build the "state" that your current block needs.
> This way source blocks function as standalone units that can be run at any
> time, I just run *org-babel-tangle* and then hit *C-c *inside the js
> block.
>
> I hope that helps you.
>
>
> Martin
>

[-- Attachment #2: Type: text/html, Size: 5468 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Hope ob-js can support :session feature
  2017-12-23  1:07   ` numbchild
@ 2017-12-23  3:06     ` Martin Alsinet
  2017-12-24  3:13       ` numbchild
  0 siblings, 1 reply; 6+ messages in thread
From: Martin Alsinet @ 2017-12-23  3:06 UTC (permalink / raw)
  To: numbchild@gmail.com; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 6740 bytes --]

Hello,

I don't have a blog yet, it is in my list of new year's resolutions. I will
try to explain it here anyway, maybe it can serve as a draft for a blog
post.

When you hit *C-c* inside of a javascript source block, *ob-js* takes the
js code from the js block and saves it into a temp file (in linux the temp
file will be in saved /tmp/random-name, while in Mac OS X it will be saved
in /var/folders/random-name). Then, it uses *org-babel-eval* to execute the
js code, which in turn creates a temp buffer, inserts the contents of the
temp file into the temp buffer and uses *shell-command-on-region* to run
the js code with *node* as the executed command.

That is the reason why you must use absolute paths in the require, because
when the code runs it is no longer in the same directory of the org file,
but in a temporary folder. If you use require("./src/my-component.js"),
require won't find the js file because it is in another directory.

Let's try an example (if you want you can send me one of your examples and
I can modify it to use my approach)

First, I will define two functions to show an array of javascript objects
as an org-mode table:

#+BEGIN_SRC js :tangle src/table.js
function table_row(cells){
    console.log("|" + cells.join("|") + "|");
}
function table(rows){
    console.log("|---|");
    table_row(Object.keys(rows[0]));
    console.log("|---|");
    rows.map(row => table_row(Object.keys(row).map(k => row[k])));
    console.log("|---|");
}
module.exports = table;
#+END_SRC

Notice the :tangle src/table.js property, which I will use to require it in
a later block:

#+BEGIN_SRC js :results output raw drawer
var data = [ { day: 'SUNDAY', accidents: 3986 },
  { day: 'MONDAY', accidents: 6109 },
  { day: 'SATURDAY', accidents: 6274 },
  { day: 'WEDNESDAY', accidents: 6453 },
  { day: 'THURSDAY', accidents: 6546 },
  { day: 'TUESDAY', accidents: 6557 },
  { day: 'FRIDAY', accidents: 6916 } ];

// here you have to use the full path to the table.js file
var view_as_table = require("/app/src/table.js");

view_as_table(data);
#+END_SRC

Then I run *org-babel-tangle* to write the table.js file, and when I hit
*C-c* inside of this last block, it requires the tangled table.js file,
runs the function and we get the following results:

#+RESULTS:
:RESULTS:
|-----------+-----------|
| day       | accidents |
|-----------+-----------|
| SUNDAY    |      3986 |
| MONDAY    |      6109 |
| SATURDAY  |      6274 |
| WEDNESDAY |      6453 |
| THURSDAY  |      6546 |
| TUESDAY   |      6557 |
| FRIDAY    |      6916 |
|-----------+-----------|
:END:

About the order of execution, if you used sessions in my example, you have
to run the first block (which defines the function) before running the
second (which uses it), or it would fail because the table function has not
been loaded.

Now imagine a very long document with dozens of source blocks. In order to
run the block number 23, you will have to run all the preceding blocks on
which that block depends. I don't like that, even if the document is meant
to be read sequentially, from start to finish, I want to be able to open
the org file, go to any section and running  any source code block without
having to remember the sequence of dependencies between them. Worst case,
all I have to do is run org-babel-tangle to update the tangled files. This
has also the added benefit that it forces me to structure my blocks
correctly, from a code architecture point of view.

I hope this makes it clearer for you.


Martin

On Fri, Dec 22, 2017 at 8:07 PM numbchild@gmail.com <numbchild@gmail.com>
wrote:

>
> Can you describe how do you do this in detailed?
> Like:
> > but since I am using docker containers to run node, I always mount the
> current directory as a volume in /app inside the container, so that works
> out fine.
> > I also think that this way forces me to separate the code in modular
> blocks, which is already a good practice in itself.
> How to do this? About this: > With sessions you have to make sure to
> execute the blocks in the correct order to build the "state" that your
> current block needs.
> I think have to use `noweb` reference here.
> (If you have a blog article describe this whole JS literate programming
> setup, that will be useful.)
> Finally, thanks you provide this paradigm.
>
> [stardiviner]           <Hack this world!>      GPG key ID: 47C32433
> IRC(freeenode): stardiviner                     Twitter:  @numbchild
> Key fingerprint = 9BAA 92BC CDDD B9EF 3B36  CB99 B8C4 B8E5 47C3 2433
> Blog: http://stardiviner.github.io/
>
> On Sat, Dec 23, 2017 at 2:32 AM, Martin Alsinet <martin@alsinet.com.ar>
> wrote:
>
>> Hello stardiviner,
>>
>> On Fri, Dec 22, 2017 at 6:57 AM stardiviner <numbchild@gmail.com> wrote:
>>
>>>
>>> I wish to do JavaScript Literate Programming in Org-mode.
>>>
>>> So the :session header argument is very necessary.
>>>
>>>
>> I do Literate Programming in Javascript with Org-mode, and I have found a
>> workaround using a combination of tangled files and require.
>>
>> I separate the logic in source code blocks which then I tangle into js
>> files and I require those js files in other source blocks.
>>
>> Example:
>>
>> #+BEGIN_SRC js :tangle src/parser.js
>> const fs = require('fs');
>> const parse = require('csv-parse')
>>
>> function columns(line){
>>     return line.map(s => s.toLowerCase());
>> }
>> parse_csv = function(filename, fn, limit){
>>     fs.readFile(filename, "utf8", function (err, fileData) {
>>         var opts = {columns: columns, trim: true};
>>         if (limit) {
>>             opts.to = limit;
>>         }
>>         parse(fileData, opts, (err, rows) => fn(rows));
>>     });
>> }
>> module.exports = parse_csv;
>> #+END_SRC
>>
>> So, I tangle that source block into a js file, and then I can use it from
>> other blocks, without needing sessions at all:
>>
>> #+BEGIN_SRC
>> const parser = require("/app/src/parser.js");
>> const inputFile = './data/records.csv';
>> parse_csv(inputFile, console.log);
>> #+END_SRC
>>
>> The only drawback is that you have to use absolute paths requiring the js
>> files, but since I am using docker containers to run node, I always mount
>> the current directory as a volume in /app inside the container, so that
>> works out fine.
>> I also think that this way forces me to separate the code in modular
>> blocks, which is already a good practice in itself.
>> With sessions you have to make sure to execute the blocks in the correct
>> order to build the "state" that your current block needs.
>> This way source blocks function as standalone units that can be run at
>> any time, I just run *org-babel-tangle* and then hit *C-c *inside the js
>> block.
>>
>> I hope that helps you.
>>
>>
>> Martin
>>
>
>

[-- Attachment #2: Type: text/html, Size: 12511 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Hope ob-js can support :session feature
  2017-12-23  3:06     ` Martin Alsinet
@ 2017-12-24  3:13       ` numbchild
  2017-12-24 16:15         ` Martin Alsinet
  0 siblings, 1 reply; 6+ messages in thread
From: numbchild @ 2017-12-24  3:13 UTC (permalink / raw)
  To: Martin Alsinet; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 8336 bytes --]

I come up with an idea, use babel header argument :var to pass in the
absolute path of tangled file.
And ob-js will expand and replace that :var variable inside of JavaScript
src block.
So that you don't need to repeatly manually typing the absolute path of the
tangled file. Maybe it only one for "require". One question is that I don't
know whether tangle to auto expand and substitute the :var.
After a quick test, seems it should be expanded but not indeed. Check out
the info node of `:no-expand`.
Here is my quick test:

* Test tangle will auto expand and substitute :var

#+begin_src js :tangle kk.js
console.log("hello, world!");
#+end_src

#+begin_src js :var name="chris" :tangle require-kk.js
// require("kk.js");
console.log("Hi, ", name);
#+end_src

#+RESULTS:
: Hi,  chris

#+NAME: check whether tangle expand and substitute :var
#+begin_src shell
cat require-kk.js
#+end_src

#+RESULTS: check whether tangle expand and substitute :var
: var name="chris";
: console.log("Hi, ", name);




[stardiviner]           <Hack this world!>      GPG key ID: 47C32433
IRC(freeenode): stardiviner                     Twitter:  @numbchild
Key fingerprint = 9BAA 92BC CDDD B9EF 3B36  CB99 B8C4 B8E5 47C3 2433
Blog: http://stardiviner.github.io/

On Sat, Dec 23, 2017 at 11:06 AM, Martin Alsinet <martin@alsinet.com.ar>
wrote:

> Hello,
>
> I don't have a blog yet, it is in my list of new year's resolutions. I
> will try to explain it here anyway, maybe it can serve as a draft for a
> blog post.
>
> When you hit *C-c* inside of a javascript source block, *ob-js* takes the
> js code from the js block and saves it into a temp file (in linux the temp
> file will be in saved /tmp/random-name, while in Mac OS X it will be saved
> in /var/folders/random-name). Then, it uses *org-babel-eval* to execute
> the js code, which in turn creates a temp buffer, inserts the contents of
> the temp file into the temp buffer and uses *shell-command-on-region* to
> run the js code with *node* as the executed command.
>
> That is the reason why you must use absolute paths in the require, because
> when the code runs it is no longer in the same directory of the org file,
> but in a temporary folder. If you use require("./src/my-component.js"),
> require won't find the js file because it is in another directory.
>
> Let's try an example (if you want you can send me one of your examples and
> I can modify it to use my approach)
>
> First, I will define two functions to show an array of javascript objects
> as an org-mode table:
>
> #+BEGIN_SRC js :tangle src/table.js
> function table_row(cells){
>     console.log("|" + cells.join("|") + "|");
> }
> function table(rows){
>     console.log("|---|");
>     table_row(Object.keys(rows[0]));
>     console.log("|---|");
>     rows.map(row => table_row(Object.keys(row).map(k => row[k])));
>     console.log("|---|");
> }
> module.exports = table;
> #+END_SRC
>
> Notice the :tangle src/table.js property, which I will use to require it
> in a later block:
>
> #+BEGIN_SRC js :results output raw drawer
> var data = [ { day: 'SUNDAY', accidents: 3986 },
>   { day: 'MONDAY', accidents: 6109 },
>   { day: 'SATURDAY', accidents: 6274 },
>   { day: 'WEDNESDAY', accidents: 6453 },
>   { day: 'THURSDAY', accidents: 6546 },
>   { day: 'TUESDAY', accidents: 6557 },
>   { day: 'FRIDAY', accidents: 6916 } ];
>
> // here you have to use the full path to the table.js file
> var view_as_table = require("/app/src/table.js");
>
> view_as_table(data);
> #+END_SRC
>
> Then I run *org-babel-tangle* to write the table.js file, and when I hit
> *C-c* inside of this last block, it requires the tangled table.js file,
> runs the function and we get the following results:
>
> #+RESULTS:
> :RESULTS:
> |-----------+-----------|
> | day       | accidents |
> |-----------+-----------|
> | SUNDAY    |      3986 |
> | MONDAY    |      6109 |
> | SATURDAY  |      6274 |
> | WEDNESDAY |      6453 |
> | THURSDAY  |      6546 |
> | TUESDAY   |      6557 |
> | FRIDAY    |      6916 |
> |-----------+-----------|
> :END:
>
> About the order of execution, if you used sessions in my example, you have
> to run the first block (which defines the function) before running the
> second (which uses it), or it would fail because the table function has not
> been loaded.
>
> Now imagine a very long document with dozens of source blocks. In order to
> run the block number 23, you will have to run all the preceding blocks on
> which that block depends. I don't like that, even if the document is meant
> to be read sequentially, from start to finish, I want to be able to open
> the org file, go to any section and running  any source code block without
> having to remember the sequence of dependencies between them. Worst case,
> all I have to do is run org-babel-tangle to update the tangled files. This
> has also the added benefit that it forces me to structure my blocks
> correctly, from a code architecture point of view.
>
> I hope this makes it clearer for you.
>
>
> Martin
>
> On Fri, Dec 22, 2017 at 8:07 PM numbchild@gmail.com <numbchild@gmail.com>
> wrote:
>
>>
>> Can you describe how do you do this in detailed?
>> Like:
>> > but since I am using docker containers to run node, I always mount the
>> current directory as a volume in /app inside the container, so that works
>> out fine.
>> > I also think that this way forces me to separate the code in modular
>> blocks, which is already a good practice in itself.
>> How to do this? About this: > With sessions you have to make sure to
>> execute the blocks in the correct order to build the "state" that your
>> current block needs.
>> I think have to use `noweb` reference here.
>> (If you have a blog article describe this whole JS literate programming
>> setup, that will be useful.)
>> Finally, thanks you provide this paradigm.
>>
>> [stardiviner]           <Hack this world!>      GPG key ID: 47C32433
>> IRC(freeenode): stardiviner                     Twitter:  @numbchild
>> Key fingerprint = 9BAA 92BC CDDD B9EF 3B36  CB99 B8C4 B8E5 47C3 2433
>> Blog: http://stardiviner.github.io/
>>
>> On Sat, Dec 23, 2017 at 2:32 AM, Martin Alsinet <martin@alsinet.com.ar>
>> wrote:
>>
>>> Hello stardiviner,
>>>
>>> On Fri, Dec 22, 2017 at 6:57 AM stardiviner <numbchild@gmail.com> wrote:
>>>
>>>>
>>>> I wish to do JavaScript Literate Programming in Org-mode.
>>>>
>>>> So the :session header argument is very necessary.
>>>>
>>>>
>>> I do Literate Programming in Javascript with Org-mode, and I have found
>>> a workaround using a combination of tangled files and require.
>>>
>>> I separate the logic in source code blocks which then I tangle into js
>>> files and I require those js files in other source blocks.
>>>
>>> Example:
>>>
>>> #+BEGIN_SRC js :tangle src/parser.js
>>> const fs = require('fs');
>>> const parse = require('csv-parse')
>>>
>>> function columns(line){
>>>     return line.map(s => s.toLowerCase());
>>> }
>>> parse_csv = function(filename, fn, limit){
>>>     fs.readFile(filename, "utf8", function (err, fileData) {
>>>         var opts = {columns: columns, trim: true};
>>>         if (limit) {
>>>             opts.to = limit;
>>>         }
>>>         parse(fileData, opts, (err, rows) => fn(rows));
>>>     });
>>> }
>>> module.exports = parse_csv;
>>> #+END_SRC
>>>
>>> So, I tangle that source block into a js file, and then I can use it
>>> from other blocks, without needing sessions at all:
>>>
>>> #+BEGIN_SRC
>>> const parser = require("/app/src/parser.js");
>>> const inputFile = './data/records.csv';
>>> parse_csv(inputFile, console.log);
>>> #+END_SRC
>>>
>>> The only drawback is that you have to use absolute paths requiring the
>>> js files, but since I am using docker containers to run node, I always
>>> mount the current directory as a volume in /app inside the container, so
>>> that works out fine.
>>> I also think that this way forces me to separate the code in modular
>>> blocks, which is already a good practice in itself.
>>> With sessions you have to make sure to execute the blocks in the correct
>>> order to build the "state" that your current block needs.
>>> This way source blocks function as standalone units that can be run at
>>> any time, I just run *org-babel-tangle* and then hit *C-c *inside the
>>> js block.
>>>
>>> I hope that helps you.
>>>
>>>
>>> Martin
>>>
>>
>>

[-- Attachment #2: Type: text/html, Size: 14833 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Hope ob-js can support :session feature
  2017-12-24  3:13       ` numbchild
@ 2017-12-24 16:15         ` Martin Alsinet
  0 siblings, 0 replies; 6+ messages in thread
From: Martin Alsinet @ 2017-12-24 16:15 UTC (permalink / raw)
  To: numbchild@gmail.com; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 9689 bytes --]

Hello stardiviner,

I actually don't mind using absoute paths in my org files, and I think that
using something like that header var and expansion is more trouble than it
is worth.
If I wanted to move the org file to another folder, I would just do a
*replace-string* of the old path with the new path and be done with it.

Another approach would be to put a block like the following at the top of
the file:
#+BEGIN_SRC sh
// Make a symbolic link of the current directory into ~/code
ln -s $PWD ~/code
#+END_SRC

And after running that block, I can just use
require("~/code/src/tangled-file.js") in the js blocks and it would work
just fine.
I consider all the tangled js files in ./src as throwaway code, meaning
that I can recreate them at any time, and I would never check them into a
repository.
I usually put them in ./src and add the src folder to my .gitignore.

I find both of these approaches simpler than tangling expanded header
arguments.
Just my 2c.

Happy holidays


Martin

On Sat, Dec 23, 2017 at 10:14 PM numbchild@gmail.com <numbchild@gmail.com>
wrote:

>
> I come up with an idea, use babel header argument :var to pass in the
> absolute path of tangled file.
> And ob-js will expand and replace that :var variable inside of JavaScript
> src block.
> So that you don't need to repeatly manually typing the absolute path of
> the tangled file. Maybe it only one for "require". One question is that I
> don't know whether tangle to auto expand and substitute the :var.
> After a quick test, seems it should be expanded but not indeed. Check out
> the info node of `:no-expand`.
> Here is my quick test:
>
> * Test tangle will auto expand and substitute :var
>
> #+begin_src js :tangle kk.js
> console.log("hello, world!");
> #+end_src
>
> #+begin_src js :var name="chris" :tangle require-kk.js
> // require("kk.js");
> console.log("Hi, ", name);
> #+end_src
>
> #+RESULTS:
> : Hi,  chris
>
> #+NAME: check whether tangle expand and substitute :var
> #+begin_src shell
> cat require-kk.js
> #+end_src
>
> #+RESULTS: check whether tangle expand and substitute :var
> : var name="chris";
> : console.log("Hi, ", name);
>
>
>
>
> [stardiviner]           <Hack this world!>      GPG key ID: 47C32433
> IRC(freeenode): stardiviner                     Twitter:  @numbchild
> Key fingerprint = 9BAA 92BC CDDD B9EF 3B36  CB99 B8C4 B8E5 47C3 2433
> Blog: http://stardiviner.github.io/
>
> On Sat, Dec 23, 2017 at 11:06 AM, Martin Alsinet <martin@alsinet.com.ar>
> wrote:
>
>> Hello,
>>
>> I don't have a blog yet, it is in my list of new year's resolutions. I
>> will try to explain it here anyway, maybe it can serve as a draft for a
>> blog post.
>>
>> When you hit *C-c* inside of a javascript source block, *ob-js* takes
>> the js code from the js block and saves it into a temp file (in linux the
>> temp file will be in saved /tmp/random-name, while in Mac OS X it will be
>> saved in /var/folders/random-name). Then, it uses *org-babel-eval* to
>> execute the js code, which in turn creates a temp buffer, inserts the
>> contents of the temp file into the temp buffer and uses
>> *shell-command-on-region* to run the js code with *node* as the executed
>> command.
>>
>> That is the reason why you must use absolute paths in the require,
>> because when the code runs it is no longer in the same directory of the org
>> file, but in a temporary folder. If you use
>> require("./src/my-component.js"), require won't find the js file because
>> it is in another directory.
>>
>> Let's try an example (if you want you can send me one of your examples
>> and I can modify it to use my approach)
>>
>> First, I will define two functions to show an array of javascript objects
>> as an org-mode table:
>>
>> #+BEGIN_SRC js :tangle src/table.js
>> function table_row(cells){
>>     console.log("|" + cells.join("|") + "|");
>> }
>> function table(rows){
>>     console.log("|---|");
>>     table_row(Object.keys(rows[0]));
>>     console.log("|---|");
>>     rows.map(row => table_row(Object.keys(row).map(k => row[k])));
>>     console.log("|---|");
>> }
>> module.exports = table;
>> #+END_SRC
>>
>> Notice the :tangle src/table.js property, which I will use to require it
>> in a later block:
>>
>> #+BEGIN_SRC js :results output raw drawer
>> var data = [ { day: 'SUNDAY', accidents: 3986 },
>>   { day: 'MONDAY', accidents: 6109 },
>>   { day: 'SATURDAY', accidents: 6274 },
>>   { day: 'WEDNESDAY', accidents: 6453 },
>>   { day: 'THURSDAY', accidents: 6546 },
>>   { day: 'TUESDAY', accidents: 6557 },
>>   { day: 'FRIDAY', accidents: 6916 } ];
>>
>> // here you have to use the full path to the table.js file
>> var view_as_table = require("/app/src/table.js");
>>
>> view_as_table(data);
>> #+END_SRC
>>
>> Then I run *org-babel-tangle* to write the table.js file, and when I hit
>> *C-c* inside of this last block, it requires the tangled table.js file,
>> runs the function and we get the following results:
>>
>> #+RESULTS:
>> :RESULTS:
>> |-----------+-----------|
>> | day       | accidents |
>> |-----------+-----------|
>> | SUNDAY    |      3986 |
>> | MONDAY    |      6109 |
>> | SATURDAY  |      6274 |
>> | WEDNESDAY |      6453 |
>> | THURSDAY  |      6546 |
>> | TUESDAY   |      6557 |
>> | FRIDAY    |      6916 |
>> |-----------+-----------|
>> :END:
>>
>> About the order of execution, if you used sessions in my example, you
>> have to run the first block (which defines the function) before running the
>> second (which uses it), or it would fail because the table function has not
>> been loaded.
>>
>> Now imagine a very long document with dozens of source blocks. In order
>> to run the block number 23, you will have to run all the preceding blocks
>> on which that block depends. I don't like that, even if the document is
>> meant to be read sequentially, from start to finish, I want to be able to
>> open the org file, go to any section and running  any source code block
>> without having to remember the sequence of dependencies between them. Worst
>> case, all I have to do is run org-babel-tangle to update the tangled files.
>> This has also the added benefit that it forces me to structure my blocks
>> correctly, from a code architecture point of view.
>>
>> I hope this makes it clearer for you.
>>
>>
>> Martin
>>
>> On Fri, Dec 22, 2017 at 8:07 PM numbchild@gmail.com <numbchild@gmail.com>
>> wrote:
>>
>>>
>>> Can you describe how do you do this in detailed?
>>> Like:
>>> > but since I am using docker containers to run node, I always mount the
>>> current directory as a volume in /app inside the container, so that works
>>> out fine.
>>> > I also think that this way forces me to separate the code in modular
>>> blocks, which is already a good practice in itself.
>>> How to do this? About this: > With sessions you have to make sure to
>>> execute the blocks in the correct order to build the "state" that your
>>> current block needs.
>>> I think have to use `noweb` reference here.
>>> (If you have a blog article describe this whole JS literate programming
>>> setup, that will be useful.)
>>> Finally, thanks you provide this paradigm.
>>>
>>> [stardiviner]           <Hack this world!>      GPG key ID: 47C32433
>>> IRC(freeenode): stardiviner                     Twitter:  @numbchild
>>> Key fingerprint = 9BAA 92BC CDDD B9EF 3B36  CB99 B8C4 B8E5 47C3 2433
>>> Blog: http://stardiviner.github.io/
>>>
>>> On Sat, Dec 23, 2017 at 2:32 AM, Martin Alsinet <martin@alsinet.com.ar>
>>> wrote:
>>>
>>>> Hello stardiviner,
>>>>
>>>> On Fri, Dec 22, 2017 at 6:57 AM stardiviner <numbchild@gmail.com>
>>>> wrote:
>>>>
>>>>>
>>>>> I wish to do JavaScript Literate Programming in Org-mode.
>>>>>
>>>>> So the :session header argument is very necessary.
>>>>>
>>>>>
>>>> I do Literate Programming in Javascript with Org-mode, and I have found
>>>> a workaround using a combination of tangled files and require.
>>>>
>>>> I separate the logic in source code blocks which then I tangle into js
>>>> files and I require those js files in other source blocks.
>>>>
>>>> Example:
>>>>
>>>> #+BEGIN_SRC js :tangle src/parser.js
>>>> const fs = require('fs');
>>>> const parse = require('csv-parse')
>>>>
>>>> function columns(line){
>>>>     return line.map(s => s.toLowerCase());
>>>> }
>>>> parse_csv = function(filename, fn, limit){
>>>>     fs.readFile(filename, "utf8", function (err, fileData) {
>>>>         var opts = {columns: columns, trim: true};
>>>>         if (limit) {
>>>>             opts.to = limit;
>>>>         }
>>>>         parse(fileData, opts, (err, rows) => fn(rows));
>>>>     });
>>>> }
>>>> module.exports = parse_csv;
>>>> #+END_SRC
>>>>
>>>> So, I tangle that source block into a js file, and then I can use it
>>>> from other blocks, without needing sessions at all:
>>>>
>>>> #+BEGIN_SRC
>>>> const parser = require("/app/src/parser.js");
>>>> const inputFile = './data/records.csv';
>>>> parse_csv(inputFile, console.log);
>>>> #+END_SRC
>>>>
>>>> The only drawback is that you have to use absolute paths requiring the
>>>> js files, but since I am using docker containers to run node, I always
>>>> mount the current directory as a volume in /app inside the container, so
>>>> that works out fine.
>>>> I also think that this way forces me to separate the code in modular
>>>> blocks, which is already a good practice in itself.
>>>> With sessions you have to make sure to execute the blocks in the
>>>> correct order to build the "state" that your current block needs.
>>>> This way source blocks function as standalone units that can be run at
>>>> any time, I just run *org-babel-tangle* and then hit *C-c *inside the
>>>> js block.
>>>>
>>>> I hope that helps you.
>>>>
>>>>
>>>> Martin
>>>>
>>>
>>>
>

[-- Attachment #2: Type: text/html, Size: 16967 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-12-24 16:15 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-22 11:57 Hope ob-js can support :session feature stardiviner
2017-12-22 18:32 ` Martin Alsinet
2017-12-23  1:07   ` numbchild
2017-12-23  3:06     ` Martin Alsinet
2017-12-24  3:13       ` numbchild
2017-12-24 16:15         ` Martin Alsinet

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).