Hi Ihor and others,

I managend to create something that seems to work.  See the attached
demo.  I still did not look at AI's implementation.  So I am as naive as
possible and wrote every line of code myself and know what it does and
why it's there.  There's no input validation yet and neither there are
automated tests nor documentation.  At least the demo contains some
words of prose.

I changed the signature once more since I noticed while playing around
with it that my previous proposal looked confusing in some situations.
Named variables on the call are now conses so they distinguish better
from any interleaved positional arguments.

That means that the arity of all keywords, including :var, is now 1.
Everything that is not immediately preceeded a keyword is treated as a
positional argument and overrides named variables of the block in the
original order.

Ihor Radchenko <[email protected]> writes:

> Daniel Bausch <[email protected]> writes:
>
>> I got the papers and sent them back just today.
>
> Curious. I still do not see you on the copyright lists (under Daniel
> Bausch name and under your email).

I don't know.  I've replied with the scanned/signed document, but
received no further reply from the clerk yet.

Kind regards,
Daniel

#+property: header-args :exports both

* Clean-Room Implementation

#+begin_src elisp :exports both
(defun org-babel-call (name &rest args)
  (let ((arg args)
        (pargs '())  ; positional args
        (nargs '())  ; named args
        (hargs '())) ; additional header args
    (while arg
      (let ((carg (car arg))
            (cadrg (cadr arg)))
        (cond
          ((eq carg :var) 
           (push cadrg nargs)
           (setq arg (cddr arg)))
          ((and (symbolp carg) 
            (string= (substring (symbol-name carg) 0 1) ":")) 
           (push (cons carg cadrg) hargs)
           (setq arg (cddr arg)))
          (t
           (push carg pargs)
           (setq arg (cdr arg)))
        )
      )
    )
    (setq pargs (nreverse pargs))
    (setq nargs (nreverse nargs))
    (setq hargs (nreverse hargs))
    (save-excursion
      (org-babel-goto-named-src-block name)
      (let* ((info (org-babel-get-src-block-info))
             (vars (org-babel--get-vars (nth 2 info)))
             (pvars (seq-mapn (lambda (var parg) (cons :var (cons (car var) 
parg))) vars pargs))
             (nvars (seq-map (lambda (narg) (cons :var narg)) nargs))
             (params (org-babel-merge-params pvars nvars hargs '((:results . 
"none")))))
        (org-babel-execute-src-block nil info params 'babel-call)
      )
    )
  )
)
#+end_src

#+results:
: org-babel-call

* Say Hello

#+name: hello
#+begin_src elisp :var name="World" :exports both
(format "Hello %s!" name)
#+end_src

#+results: hello
: Hello World!

#+begin_src elisp
(org-babel-call "hello" "Org")
#+end_src

#+results:
: Hello Org!

* New calling convention: Loose CLI style with named variables as pairs

#+name: demo
#+begin_src bash :exports both :var var1=-1 :var var2=-2 :var var3=-3 :var 
var4=-4 :var var5=-5
echo "cwd=$(pwd)"
echo "var1=$var1"
echo "var2=$var2"
echo "var3=$var3"
echo "var4=$var4"
echo "var5=$var5"
#+end_src

#+results: demo
| cwd=/home/daniel/prog/org-babel-call |
| var1=-1                              |
| var2=-2                              |
| var3=-3                              |
| var4=-4                              |
| var5=-5                              |

Order of named assigments doesn't matter and positional arguments get
assigned in order regardless where they appear in the line.
Additional header arguments are forwarded.

#+begin_src elisp :exports both :var val1=1 :var val2=2 :var val3=3 :var val4=4 
:var val5=5
(org-babel-call "demo" val1 :var (cons "var4" val4) val2 val3 :var (cons "var5" 
val5) :dir "/tmp")
#+end_src

#+results:
| cwd=/tmp |
| var1=1   |
| var2=2   |
| var3=3   |
| var4=4   |
| var5=5   |

* Intuitive Recursion

Notice also that numbers stay numbers.  There's no coercion to
strings.

#+name: fib
#+begin_src elisp :var x=0
(if (< x 2) x (+ (org-babel-call "fib" (- x 2)) (org-babel-call "fib" (- x 1))))
#+end_src

#+results: fib
: 0

#+call: fib(1)

#+results:
: 1

#+call: fib(2)

#+results:
: 1

#+call: fib(3)

#+results:
: 2

#+call: fib(4)

#+results:
: 3

#+call: fib(5)

#+results:
: 5

#+call: fib(6)

#+results:
: 8

#+call: fib(7)

#+results:
: 13

* Orchestration

#+name: data
#+begin_example
john:
  first-name: John
  last-name: Doe
jane:
  first-name: Jane
  last-name: Doe
#+end_example

#+name: pydemo
#+begin_src python :var user="john" :var field="first-name" :var data=data
import yaml
d=yaml.safe_load(data)
return d[user][field]
#+end_src

#+results: pydemo
: John

#+name: full-name
#+begin_src elisp :var user="john"
(format "%s %s"
  (org-babel-call "pydemo" user "first-name")
  (org-babel-call "pydemo" user "last-name"))
#+end_src

#+results: full-name
: John Doe

#+call: full-name("jane")

#+results:
: Jane Doe

#+name: greet-user
#+begin_src elisp :var user="john"
(org-babel-call "hello" (org-babel-call "full-name" user))
#+end_src

#+results: greet-user
: Hello John Doe!

#+call: greet-user("jane")

#+results:
: Hello Jane Doe!

* Tables

| USER | FULL NAME |
|------+-----------|
| john | John Doe  |
| jane | Jane Doe  |
#+TBLFM: $2='(org-babel-call "full-name" $1)

is practically equivalent to

| USER | FULL NAME |
|------+-----------|
| john | John Doe  |
| jane | Jane Doe  |
#+TBLFM: $2='(org-sbe full-name (user $$1))

* Repeat

Calling a code block on repeat without a specific input element for
each invocation.

#+begin_src elisp :results list :var n=10
(seq-map (lambda (x) (format "fib(%d)=%d" x (org-babel-call "fib" x))) 
(number-sequence 0 (1- n)))
#+end_src

#+results:
- fib(0)=0
- fib(1)=1
- fib(2)=1
- fib(3)=2
- fib(4)=3
- fib(5)=5
- fib(6)=8
- fib(7)=13
- fib(8)=21
- fib(9)=34

Reply via email to