This commit is contained in:
2026-01-25 19:21:21 +01:00
parent 6ad1c86b95
commit 34353b8332

345
README.org Normal file
View File

@@ -0,0 +1,345 @@
#+TITLE: ob-elixir
#+AUTHOR: Luis Eduardo Bueso de Barrio
#+LANGUAGE: en
Org Babel support for evaluating Elixir code blocks in Emacs org-mode.
* Features
- Execute Elixir code directly in org-mode source blocks
- Support for =:results value= and =:results output=
- Variable passing with =:var= header argument
- Persistent IEx sessions with =:session=
- Mix dependency management via =#+BEGIN_DEPS= blocks
- Shared imports/aliases via =#+BEGIN_IMPORTS= blocks
- Module definitions with =:module= header argument
- Automatic conversion of Elixir lists to org tables
- Configurable error handling and warning display
* Requirements
- Emacs 27.1 or later
- Org-mode 9.4 or later
- Elixir installed and available in PATH
* Installation
** With straight.el
#+begin_src emacs-lisp
(straight-use-package
'(ob-elixir :type git :host github :repo "username/ob-elixir"))
#+end_src
** With use-package and straight.el
#+begin_src emacs-lisp
(use-package ob-elixir
:straight (:type git :host github :repo "username/ob-elixir"))
#+end_src
** Manual Installation
Clone the repository and add it to your load path:
#+begin_src emacs-lisp
(add-to-list 'load-path "/path/to/ob-elixir")
(require 'ob-elixir)
#+end_src
* Configuration
Enable Elixir in org-babel:
#+begin_src emacs-lisp
(org-babel-do-load-languages
'org-babel-load-languages
'((elixir . t)))
#+end_src
* Usage
** Basic Execution
Execute Elixir code with =C-c C-c=:
#+begin_example
,#+begin_src elixir
1 + 2
,#+end_src
,#+RESULTS:
: 3
#+end_example
** Results: Value vs Output
By default, blocks return the value of the last expression (=:results value=):
#+begin_example
,#+begin_src elixir :results value
Enum.map([1, 2, 3], fn x -> x * 2 end)
,#+end_src
,#+RESULTS:
| 2 | 4 | 6 |
#+end_example
Use =:results output= to capture printed output:
#+begin_example
,#+begin_src elixir :results output
IO.puts("Hello, World!")
IO.puts("Line 2")
,#+end_src
,#+RESULTS:
: Hello, World!
: Line 2
#+end_example
** Variables
Pass variables to Elixir code with =:var=:
#+begin_example
,#+begin_src elixir :var name="Elixir" count=3
String.duplicate(name, count)
,#+end_src
,#+RESULTS:
: ElixirElixirElixir
#+end_example
Variables are automatically converted:
- Elisp strings become Elixir strings
- Elisp numbers become Elixir numbers
- Elisp lists become Elixir lists
- Elisp vectors become Elixir tuples
- Elisp =t= becomes =true=, =nil= becomes =nil=
- Elisp symbols become atoms
** Sessions
Use =:session= to maintain state across blocks:
#+begin_example
,#+begin_src elixir :session my-session
x = 10
,#+end_src
,#+RESULTS:
: 10
,#+begin_src elixir :session my-session
x * 2
,#+end_src
,#+RESULTS:
: 20
#+end_example
Manage sessions with:
- =M-x ob-elixir-kill-session= - Kill a specific session
- =M-x ob-elixir-kill-all-sessions= - Kill all sessions
** Dependencies
Define Mix dependencies with =#+BEGIN_DEPS= blocks. Dependencies apply to all subsequent Elixir blocks in the document:
#+begin_example
,#+BEGIN_DEPS elixir
[
{:jason, "~> 1.4"},
{:decimal, "~> 2.0"}
]
,#+END_DEPS
,#+begin_src elixir
Jason.encode!(%{hello: "world"})
,#+end_src
,#+RESULTS:
: {"hello":"world"}
#+end_example
Dependencies are cached in =~/.cache/ob-elixir/= (configurable via =ob-elixir-deps-cache-dir=). The first execution fetches and compiles dependencies; subsequent executions reuse the cache.
Manage dependency projects with:
- =M-x ob-elixir-list-deps-projects= - List cached projects
- =M-x ob-elixir-cleanup-deps-projects= - Delete all cached projects
** Imports
Define shared imports, aliases, and requires with =#+BEGIN_IMPORTS= blocks:
#+begin_example
,#+BEGIN_IMPORTS elixir
import Enum, only: [map: 2, filter: 2]
alias String, as: S
,#+END_IMPORTS
,#+begin_src elixir
map([1, 2, 3], &(&1 * 2)) |> filter(&(&1 > 2))
,#+end_src
,#+RESULTS:
| 4 | 6 |
,#+begin_src elixir
S.upcase("hello")
,#+end_src
,#+RESULTS:
: HELLO
#+end_example
** Module Definitions
Define reusable modules with the =:module= header argument:
#+begin_example
,#+begin_src elixir :module MyMath
def add(a, b), do: a + b
def multiply(a, b), do: a * b
,#+end_src
,#+RESULTS:
: Module MyMath: functions defined
#+end_example
Multiple blocks with the same =:module= name merge their contents:
#+begin_example
,#+begin_src elixir :module MyMath
def subtract(a, b), do: a - b
,#+end_src
#+end_example
Use the module in subsequent blocks (requires explicit import):
#+begin_example
,#+BEGIN_IMPORTS elixir
import MyMath
,#+END_IMPORTS
,#+begin_src elixir
add(1, 2) |> multiply(3)
,#+end_src
,#+RESULTS:
: 9
#+end_example
** Tables
Elixir lists are automatically converted to org tables:
#+begin_example
,#+begin_src elixir
[
["Name", "Age"],
["Alice", 30],
["Bob", 25]
]
,#+end_src
,#+RESULTS:
| Name | Age |
| Alice | 30 |
| Bob | 25 |
#+end_example
Tuples are also supported:
#+begin_example
,#+begin_src elixir
{:ok, "success"}
,#+end_src
,#+RESULTS:
| ok | success |
#+end_example
* Customization
** Commands
- =ob-elixir-command= (default: ="elixir"=) - Command to execute Elixir code
- =ob-elixir-iex-command= (default: ="iex"=) - Command to start IEx sessions
- =ob-elixir-mix-command= (default: ="mix"=) - Command to run Mix
** Behavior
- =ob-elixir-signal-errors= (default: =t=) - When non-nil, Elixir errors are signaled as Emacs errors. When nil, errors are returned as result strings.
- =ob-elixir-show-warnings= (default: =t=) - When non-nil, Elixir warnings are included in output.
** Paths
- =ob-elixir-deps-cache-dir= (default: =~/.cache/ob-elixir/=) - Directory for caching temporary Mix projects created for dependencies.
** Example Configuration
#+begin_src emacs-lisp
(use-package ob-elixir
:after org
:config
(setq ob-elixir-signal-errors nil) ; Return errors as results
(setq ob-elixir-show-warnings nil) ; Hide warnings
(org-babel-do-load-languages
'org-babel-load-languages
'((elixir . t))))
#+end_src
* Development
** Running Tests
Using Make:
#+begin_src sh
make test
#+end_src
Using Eldev:
#+begin_src sh
eldev test
#+end_src
** Byte Compilation
#+begin_src sh
make compile
#+end_src
** Linting
#+begin_src sh
make lint
#+end_src
** Project Structure
#+begin_example
ob-elixir/
├── ob-elixir.el # Main source file
├── Makefile # Build and test commands
├── Eldev # Eldev configuration
├── test/ # Test suite
│ ├── test-ob-elixir.el
│ ├── test-ob-elixir-core.el
│ ├── test-ob-elixir-vars.el
│ ├── test-ob-elixir-results.el
│ ├── test-ob-elixir-errors.el
│ ├── test-ob-elixir-org.el
│ ├── test-ob-elixir-deps.el
│ ├── test-ob-elixir-imports.el
│ ├── test-ob-elixir-modules.el
│ └── test-ob-elixir-sessions.el
└── docs/ # Implementation documentation
#+end_example
* License
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.