03-variable-injection.md done

This commit is contained in:
2026-01-24 17:31:07 +01:00
parent 206ed0e9d2
commit af9cb22209
2 changed files with 171 additions and 1 deletions

View File

@@ -67,6 +67,95 @@ Can be a full path or command name if in PATH."
(with-eval-after-load 'org-src
(add-to-list 'org-src-lang-modes '("elixir" . elixir)))
;;; Type Conversion
(defun ob-elixir--escape-string (str)
"Escape special characters in STR for Elixir string literal."
(let ((result str))
;; Escape backslashes first
(setq result (replace-regexp-in-string "\\\\" "\\\\\\\\" result))
;; Escape double quotes
(setq result (replace-regexp-in-string "\"" "\\\\\"" result))
;; Escape newlines
(setq result (replace-regexp-in-string "\n" "\\\\n" result))
;; Escape tabs
(setq result (replace-regexp-in-string "\t" "\\\\t" result))
result))
(defun ob-elixir--elisp-to-elixir (value)
"Convert Elisp VALUE to Elixir literal syntax.
Handles:
- nil -> nil
- t -> true
- numbers -> numbers
- strings -> quoted strings
- symbols -> atoms
- lists -> Elixir lists
- vectors -> tuples"
(cond
;; nil
((null value) "nil")
;; Boolean true
((eq value t) "true")
;; Numbers
((numberp value)
(number-to-string value))
;; Strings
((stringp value)
(format "\"%s\"" (ob-elixir--escape-string value)))
;; Symbols become atoms (except special ones)
((symbolp value)
(let ((name (symbol-name value)))
(cond
((string= name "hline") ":hline")
((string-match-p "^[a-z_][a-zA-Z0-9_]*[?!]?$" name)
(format ":%s" name))
(t (format ":\"%s\"" name)))))
;; Vectors become tuples
((vectorp value)
(format "{%s}"
(mapconcat #'ob-elixir--elisp-to-elixir
(append value nil) ", ")))
;; Lists
((listp value)
(format "[%s]"
(mapconcat #'ob-elixir--elisp-to-elixir value ", ")))
;; Fallback
(t (format "%S" value))))
;;; Variable Handling
(defun ob-elixir--var-name (name)
"Convert NAME to a valid Elixir variable name.
Elixir variables must start with lowercase or underscore."
(let ((str (if (symbolp name) (symbol-name name) name)))
;; Ensure starts with lowercase or underscore
(if (string-match-p "^[a-z_]" str)
str
(concat "_" str))))
(defun org-babel-variable-assignments:elixir (params)
"Return list of Elixir statements assigning variables from PARAMS.
Each statement has the form: var_name = value"
(mapcar
(lambda (pair)
(let ((name (car pair))
(value (cdr pair)))
(format "%s = %s"
(ob-elixir--var-name name)
(ob-elixir--elisp-to-elixir value))))
(org-babel--get-vars params)))
;;; Execution
(defconst ob-elixir--value-wrapper
@@ -115,7 +204,11 @@ PARAMS is an alist of header arguments.
This function is called by `org-babel-execute-src-block'."
(let* ((result-type (cdr (assq :result-type params)))
(result-params (cdr (assq :result-params params)))
(result (ob-elixir--execute body result-type)))
;; Expand body with variable assignments
(full-body (org-babel-expand-body:generic
body params
(org-babel-variable-assignments:elixir params)))
(result (ob-elixir--execute full-body result-type)))
(org-babel-reassemble-table
(org-babel-result-cond result-params
result

View File

@@ -54,5 +54,82 @@
(should (or (string-match-p "%{a: 1, b: 2}" result)
(string-match-p "%{b: 2, a: 1}" result)))))
;;; Type Conversion Tests
(ert-deftest ob-elixir-test-convert-nil ()
"Test nil conversion."
(should (equal "nil" (ob-elixir--elisp-to-elixir nil))))
(ert-deftest ob-elixir-test-convert-true ()
"Test t conversion."
(should (equal "true" (ob-elixir--elisp-to-elixir t))))
(ert-deftest ob-elixir-test-convert-integer ()
"Test integer conversion."
(should (equal "42" (ob-elixir--elisp-to-elixir 42)))
(should (equal "-10" (ob-elixir--elisp-to-elixir -10))))
(ert-deftest ob-elixir-test-convert-float ()
"Test float conversion."
(should (equal "3.14" (ob-elixir--elisp-to-elixir 3.14))))
(ert-deftest ob-elixir-test-convert-string ()
"Test string conversion."
(should (equal "\"hello\"" (ob-elixir--elisp-to-elixir "hello"))))
(ert-deftest ob-elixir-test-convert-string-escaping ()
"Test string escaping."
(should (equal "\"say \\\"hi\\\"\""
(ob-elixir--elisp-to-elixir "say \"hi\"")))
(should (equal "\"line1\\nline2\""
(ob-elixir--elisp-to-elixir "line1\nline2"))))
(ert-deftest ob-elixir-test-convert-symbol ()
"Test symbol conversion to atom."
(should (equal ":foo" (ob-elixir--elisp-to-elixir 'foo)))
(should (equal ":ok" (ob-elixir--elisp-to-elixir 'ok))))
(ert-deftest ob-elixir-test-convert-list ()
"Test list conversion."
(should (equal "[1, 2, 3]" (ob-elixir--elisp-to-elixir '(1 2 3))))
(should (equal "[\"a\", \"b\"]" (ob-elixir--elisp-to-elixir '("a" "b")))))
(ert-deftest ob-elixir-test-convert-nested-list ()
"Test nested list conversion."
(should (equal "[[1, 2], [3, 4]]"
(ob-elixir--elisp-to-elixir '((1 2) (3 4))))))
(ert-deftest ob-elixir-test-convert-vector ()
"Test vector to tuple conversion."
(should (equal "{1, 2, 3}" (ob-elixir--elisp-to-elixir [1 2 3]))))
;;; Variable Injection Tests
(ert-deftest ob-elixir-test-variable-assignments ()
"Test variable assignment generation."
(let ((params '((:var . ("x" . 5))
(:var . ("name" . "Alice")))))
(let ((assignments (org-babel-variable-assignments:elixir params)))
(should (member "x = 5" assignments))
(should (member "name = \"Alice\"" assignments)))))
(ert-deftest ob-elixir-test-var-execution ()
"Test code execution with variables."
(skip-unless (executable-find ob-elixir-command))
(let* ((params '((:var . ("x" . 10))))
(var-lines (org-babel-variable-assignments:elixir params))
(full-body (concat (mapconcat #'identity var-lines "\n")
"\nx * 2")))
(should (equal "20" (ob-elixir--execute full-body 'value)))))
(ert-deftest ob-elixir-test-var-list ()
"Test passing list as variable."
(skip-unless (executable-find ob-elixir-command))
(let* ((params '((:var . ("data" . (1 2 3)))))
(var-lines (org-babel-variable-assignments:elixir params))
(full-body (concat (mapconcat #'identity var-lines "\n")
"\nEnum.sum(data)")))
(should (equal "6" (ob-elixir--execute full-body 'value)))))
(provide 'test-ob-elixir)
;;; test-ob-elixir.el ends here