From mboxrd@z Thu Jan 1 00:00:00 1970 From: Martin Alsinet Subject: Re: Hope ob-js can support :session feature Date: Sat, 23 Dec 2017 03:06:27 +0000 Message-ID: References: <0a1fd382-6c99-e69d-c998-b3157edab040@gmail.com> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="001a113d083cb0c18f0560f93879" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:53977) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eSa94-0000Ke-AQ for emacs-orgmode@gnu.org; Fri, 22 Dec 2017 22:06:44 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eSa90-0001J6-U0 for emacs-orgmode@gnu.org; Fri, 22 Dec 2017 22:06:42 -0500 Received: from mail-ot0-f169.google.com ([74.125.82.169]:36391) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eSa90-0001HO-L7 for emacs-orgmode@gnu.org; Fri, 22 Dec 2017 22:06:38 -0500 Received: by mail-ot0-f169.google.com with SMTP id d5so26592811oti.3 for ; Fri, 22 Dec 2017 19:06:38 -0800 (PST) In-Reply-To: List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Sender: "Emacs-orgmode" To: "numbchild@gmail.com" Cc: emacs-orgmode --001a113d083cb0c18f0560f93879 Content-Type: text/plain; charset="UTF-8" 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 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] 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 > wrote: > >> Hello stardiviner, >> >> On Fri, Dec 22, 2017 at 6:57 AM stardiviner 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 >> > > --001a113d083cb0c18f0560f93879 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
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,=C2=A0o= b-js=C2=A0takes 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 Ma= c 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 she= ll-command-on-region=C2=A0to run the js code with node as the ex= ecuted command.

That is the reason why you must us= e 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 u= se require("./src/my-component.js"), require won't find the js file because it is in another directory.<= /div>

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 javas= cript objects as an org-mode table:

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

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

#+BEGIN_SRC js :resul= ts output raw drawer
var data =3D= =C2=A0[ { day: 'SUNDAY', accidents: 3986 },
<= font face=3D"monospace">=C2=A0 {=C2=A0day: 'MONDA= Y', accidents: 6109 },
=C2=A0= {=C2=A0da= y: 'SATURDAY', accidents: 6274 },
=C2=A0 {=C2=A0day: 'WEDNESDAY', accidents: 6453 },
=C2=A0 {=C2=A0day: 'THURSDAY'= , accidents: 6546 },
=C2=A0 {=C2= =A0day: 'TUESDAY', accidents: 6557 },<= /div>
=C2=A0 {=C2=A0day:= 'FRIDAY', accidents: 6916 } ];

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

vi= ew_as_table(data);
#+END_SRC

Then I run org-babel-tangle=C2=A0t= o write the table.js file, and when I hit C-c=C2=A0inside of this la= st block, it requires the tangled table.js file, runs the function and we g= et the following results:

#+RESULTS:
:RESULTS:=
|-----------+-----------|
<= div>| day =C2=A0 =C2=A0 =C2=A0 | accidents |
|-----------+-----------|
=
| SUNDAY =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A03= 986 |
| MONDAY =C2=A0 =C2=A0| =C2= =A0 =C2=A0 =C2=A06109 |
| SATURDA= Y =C2=A0| =C2=A0 =C2=A0 =C2=A06274 |
| WEDNESDAY | =C2=A0 =C2=A0 =C2=A06453 |
| THURSDAY =C2=A0| =C2=A0 =C2=A0 =C2=A06546 |
= | TUESDAY =C2=A0 | =C2=A0 =C2=A0 =C2=A06557 |
| FRIDAY =C2=A0 =C2=A0| =C2=A0 =C2=A0= =C2=A06916 |
|-----------+------= -----|
:END:

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

Now imagine a ve= ry long document with dozens of source blocks. In order to run the block nu= mber 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 se= quentially, from start to finish, I want to be able to open the org file, g= o to any section and running =C2=A0any 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 th= e 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:<= br>

Can you describe how do you do this in detailed?
Like:
> but since I am using docker containers to run node, I always mount t= he current directory as a volume in /app inside the container, so that work= s 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: =20 > With sessions you have to make sure to execute the blocks in the cor= rect order to build the "state" that your current block needs. =20 I think have to use `noweb` reference here.
=20 (If you have a blog article describe this whole JS literate programming s= etup, that will be useful.)
Finally, thanks you provide this paradigm.

=
[stardiviner]=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 <Hack this world!>=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 GPG key ID: 47C32433
IRC(freeenode): stardiviner = =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Twitter:=C2=A0 @numbchild
Key fi= ngerprint =3D 9BAA 92BC CDDD B9EF 3B36=C2=A0 CB99 B8C4 B8E5 47C3 2433
Bl= og: http://star= diviner.github.io/

On Sat, Dec 23, 2017 at 2:32 AM, Martin Alsi= net <martin@alsinet.com.ar> wrote:
Hello stardiviner,

On Fri, Dec 22, 2017 at 6:57 AM stardivine= r <numbchild@gm= ail.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-mod= e, and I have found a workaround using a combination of tangled files and r= equire.

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

Example:=C2=A0

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

function= columns(line){
=C2=A0 =C2=A0 return line.map(s =3D> s.toLow= erCase());
}
parse_csv =3D function(filename, fn, limit){
=C2=A0 =C2=A0 fs.readFile(filename, "= ;utf8", function (err, fileData) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 var opts =3D {columns: columns, trim: tr= ue};
=C2=A0 =C2=A0 =C2=A0 =C2=A0 = if (limit) {
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 opts.to<= /a> =3D limit;
=C2=A0 =C2=A0 });

<= div>
So, I tangle that source block into a js file, and then I can use = it from other blocks, without needing sessions at all:
=
With sessions you have to make sure to execute the blocks in the corre= ct order to build the "state" that your current block needs.=C2= =A0
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

--001a113d083cb0c18f0560f93879--