From mboxrd@z Thu Jan 1 00:00:00 1970 From: Martin Alsinet Subject: Re: Hope ob-js can support :session feature Date: Sun, 24 Dec 2017 16:15:17 +0000 Message-ID: References: <0a1fd382-6c99-e69d-c998-b3157edab040@gmail.com> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="001a11c01b3e9fe1790561185b7c" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:59536) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eT8w1-0008JF-Hw for emacs-orgmode@gnu.org; Sun, 24 Dec 2017 11:15:36 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eT8vx-0003MW-B8 for emacs-orgmode@gnu.org; Sun, 24 Dec 2017 11:15:33 -0500 Received: from mail-ot0-f169.google.com ([74.125.82.169]:36403) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eT8vw-0003M6-Rj for emacs-orgmode@gnu.org; Sun, 24 Dec 2017 11:15:29 -0500 Received: by mail-ot0-f169.google.com with SMTP id d5so28658255oti.3 for ; Sun, 24 Dec 2017 08:15:28 -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 --001a11c01b3e9fe1790561185b7c Content-Type: text/plain; charset="UTF-8" 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 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] 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 > 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 >> 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 >>>> >>> >>> > --001a11c01b3e9fe1790561185b7c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hello stardiviner,

I actuall= y don't mind using absoute paths in my org files, and I think that usin= g something like that header var and expansion is more trouble than it is w= orth.
If I wanted to move the org file to another folder, I would= just do a replace-string=C2=A0of 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
// Mak= e a symbolic link of the current directory into ~/code
ln -s $PWD ~/code
#+END_SRC

And after running that blo= ck, I can just use require("~/code/src/tangle= d-file.js")=C2=A0in the js blocks and it would work just fine.<= /div>
I consider all the tangled js files in .= /src=C2=A0as 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 hea= der arguments.
Just my 2c.

Happy holiday= s


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 abs= olute 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 s= ubstitute 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=3D"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=3D"chris";
: console.log("Hi, ", name);

  
=
[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 fingerprint =3D 9BAA 92BC CDD= D B9EF 3B36=C2=A0 CB99 B8C4 B8E5 47C3 2433
Blog: http://stardiviner.github.io/
<= /div>

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= 9;s resolutions. I will try to explain it here anyway, maybe it can serve a= s a draft for a blog post.

When you hit C-c= inside of a javascript source block,=C2=A0ob-js=C2=A0takes the js c= ode 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 th= e 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=C2= =A0to run the js code with node as the executed command.
<= br>
That is the reason why you must use absolute paths in the req= uire, because when the code runs it is no longer in the same directory of t= he 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.

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

First, I wil= l define two functions to show an array of javascript objects as an org-mod= e 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 console.log("|---|");
=C2=A0 =C2=A0 table_row(Object.key= s(rows[0]));
=C2=A0 =C2=A0 consol= e.log("|---|");
=C2=A0 = =C2=A0 rows.map(row =3D> table_row(Object.keys(row).map(k =3D> row[k]= )));
=C2=A0 =C2=A0 console.log(&q= uot;|---|");
}
<= div>module.exports =3D table;
#+END_SRC

Notic= e 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 =3D=C2=A0[ { day: 'SUNDAY'= , accidents: 3986 },
=C2=A0 = {=C2=A0day= : 'MONDAY', accidents: 6109 },
=C2=A0 {=C2=A0day: 'SATURDAY', accidents: 6274 },
=C2=A0 {=C2=A0day: 'WEDNESDAY', acc= idents: 6453 },
=C2=A0 {=C2=A0day: 'THURSDAY', accidents: 6546 },
=
=C2=A0 {=C2=A0day: '= ;TUESDAY', accidents: 6557 },
=C2=A0 {=C2=A0day: 'FRIDAY', accidents: 6916= } ];

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

view_as_table(data);
#+END_SRC

Then I run org-babel-tangle=C2=A0to write the table.js file, and wh= en I hit C-c=C2=A0inside of this last block, it requires the tangled= table.js file, runs the function and we get the following results:

#+RESULTS:
:RESULTS:
|-----------+-----------|
| da= y =C2=A0 =C2=A0 =C2=A0 | accidents |
|-----------+-----------|
| S= UNDAY =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A03986 |
| MONDAY =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A06109 |
| SATURDAY =C2=A0| =C2=A0 =C2=A0 =C2=A0627= 4 |
| WEDNESDAY | =C2=A0 =C2=A0 = =C2=A06453 |
| THURSDAY =C2=A0| = =C2=A0 =C2=A0 =C2=A06546 |
| TUES= DAY =C2=A0 | =C2=A0 =C2=A0 =C2=A06557 |
| FRIDAY =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A06916 |
= |-----------+-----------|
:END:

About the ord= er of execution, if you used sessions in my example, you have to run the fi= rst block (which defines the function) before running the second (which use= s it), or it would fail because the table function has not been loaded.=C2= =A0

Now imagine a very long document with dozens o= f 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 fini= sh, I want to be able to open the org file, go to any section and running = =C2=A0any source code block without having to remember the sequence of depe= ndencies 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 force= s me to structure my blocks correctly, from a code architecture point of vi= ew.

I hope this makes it clearer for you.


Martin
<= /div>

On Fri, Dec 22, 2017 at 8:07 PM numbchild@gmail.com <numbchild@gmail.com&= gt; 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 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 fingerprint = =3D 9BAA 92BC CDDD B9EF 3B36=C2=A0 CB99 B8C4 B8E5 47C3 2433
Blog: http://stardiviner.gi= thub.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


--001a11c01b3e9fe1790561185b7c--