ob-elixir
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 valueand:results output - Variable passing with
:varheader argument - Persistent IEx sessions with
:session - Mix dependency management via
#+BEGIN_DEPSblocks - Shared imports/aliases via
#+BEGIN_IMPORTSblocks - Module definitions with
:moduleheader 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
(straight-use-package
'(ob-elixir :type git :host github :repo "username/ob-elixir"))
With use-package and straight.el
(use-package ob-elixir
:straight (:type git :host github :repo "username/ob-elixir"))
Manual Installation
Clone the repository and add it to your load path:
(add-to-list 'load-path "/path/to/ob-elixir")
(require 'ob-elixir)
Configuration
Enable Elixir in org-babel:
(org-babel-do-load-languages
'org-babel-load-languages
'((elixir . t)))
Usage
Basic Execution
Execute Elixir code with C-c C-c:
#+begin_src elixir 1 + 2 #+end_src #+RESULTS: : 3
Results: Value vs Output
By default, blocks return the value of the last expression (:results value):
#+begin_src elixir :results value Enum.map([1, 2, 3], fn x -> x * 2 end) #+end_src #+RESULTS: | 2 | 4 | 6 |
Use :results output to capture printed output:
#+begin_src elixir :results output
IO.puts("Hello, World!")
IO.puts("Line 2")
#+end_src
#+RESULTS:
: Hello, World!
: Line 2
Variables
Pass variables to Elixir code with :var:
#+begin_src elixir :var name="Elixir" count=3 String.duplicate(name, count) #+end_src #+RESULTS: : ElixirElixirElixir
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
tbecomestrue,nilbecomesnil - Elisp symbols become atoms
Sessions
Use :session to maintain state across blocks:
#+begin_src elixir :session my-session x = 10 #+end_src #+RESULTS: : 10 #+begin_src elixir :session my-session x * 2 #+end_src #+RESULTS: : 20
Manage sessions with:
M-x ob-elixir-kill-session- Kill a specific sessionM-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_DEPS elixir
[
{:jason, "~> 1.4"},
{:decimal, "~> 2.0"}
]
#+END_DEPS
#+begin_src elixir
Jason.encode!(%{hello: "world"})
#+end_src
#+RESULTS:
: {"hello":"world"}
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 projectsM-x ob-elixir-cleanup-deps-projects- Delete all cached projects
Imports
Define shared imports, aliases, and requires with #+BEGIN_IMPORTS blocks:
#+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
Module Definitions
Define reusable modules with the :module header argument:
#+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
Multiple blocks with the same :module name merge their contents:
#+begin_src elixir :module MyMath def subtract(a, b), do: a - b #+end_src
Use the module in subsequent blocks (requires explicit import):
#+BEGIN_IMPORTS elixir import MyMath #+END_IMPORTS #+begin_src elixir add(1, 2) |> multiply(3) #+end_src #+RESULTS: : 9
Tables
Elixir lists are automatically converted to org tables:
#+begin_src elixir [ ["Name", "Age"], ["Alice", 30], ["Bob", 25] ] #+end_src #+RESULTS: | Name | Age | | Alice | 30 | | Bob | 25 |
Tuples are also supported:
#+begin_src elixir
{:ok, "success"}
#+end_src
#+RESULTS:
| ok | success |
Customization
Commands
ob-elixir-command(default:"elixir") - Command to execute Elixir codeob-elixir-iex-command(default:"iex") - Command to start IEx sessionsob-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
(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))))
Development
Running Tests
Using Make:
make test
Using Eldev:
eldev test
Byte Compilation
make compile
Linting
make lint
Project Structure
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
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.