# MinijinjaEx
Elixir wrapper for [minijinja](https://github.com/mitsuhiko/minijinja), a minimal template engine written in Rust by Armin Ronacher.
Licensed under Apache License 2.0.
## Installation
Add to your `mix.exs`:
```elixir
def deps do
[
{:minijinja_ex, "~> 0.1"}
]
end
```
Precompiled binaries are available for:
- macOS arm64 (Apple Silicon)
- Linux arm64 (gnu)
- Linux x86_64 (gnu and musl)
Intel macOS users need to build from source. No Rust installation required for supported platforms.
### Force Build from Source
If you need to build from source (e.g., unsupported platform):
```bash
export MINIJINJA_EX_BUILD=1
mix deps.compile minijinja_ex
```
## Usage
### Direct Rendering
Render a template string without creating an environment:
```elixir
{:ok, result} = MinijinjaEx.render_string("Hello {{ name }}!", %{"name" => "World"})
# => "Hello World!"
# Raise on error
result = MinijinjaEx.render_string!("{{ x }}", %{"x" => 42})
# => "42"
```
### Environment-Based Rendering
Create an environment to manage multiple templates:
```elixir
env = MinijinjaEx.new_env()
{:ok, env} = MinijinjaEx.add_template(env, "greeting", "Hello {{ name }}!")
{:ok, env} = MinijinjaEx.add_template(env, "footer", "Copyright {{ year }}")
{:ok, result} = MinijinjaEx.render(env, "greeting", %{"name" => "Alice"})
# => "Hello Alice!"
```
### Configuration Options
```elixir
env = MinijinjaEx.new_env(
trim_blocks: true, # Remove first newline after block tags
lstrip_blocks: true, # Remove leading whitespace before block tags
keep_trailing_newline: true
)
```
### Pipe-Friendly API
```elixir
env = MinijinjaEx.new_env()
|> MinijinjaEx.add_template!("greeting", "Hello {{ name }}!")
|> MinijinjaEx.add_template!("footer", "Copyright {{ year }}")
|> MinijinjaEx.add_global!("site_name", "MyApp")
|> MinijinjaEx.set_trim_blocks(true)
```
### Global Variables
Add variables available in all templates:
```elixir
env = MinijinjaEx.new_env()
|> MinijinjaEx.add_global!("version", "1.0.0")
|> MinijinjaEx.add_global!("site", "MyApp")
{:ok, result} = MinijinjaEx.render_string(env, "{{ site }} v{{ version }}", %{})
# => "MyApp v1.0.0"
```
### Template Includes
```elixir
env = MinijinjaEx.new_env()
|> MinijinjaEx.add_template!("base", "Header\n{% include 'content' %}\nFooter")
|> MinijinjaEx.add_template!("content", "This is the content")
{:ok, result} = MinijinjaEx.render(env, "base", %{})
# => "Header\nThis is the content\nFooter"
```
## Template Syntax
Minijinja supports Jinja2-like syntax:
### Variables
```
{{ variable }}
{{ object.property }}
{{ items.0 }}
```
### Conditionals
```
{% if user.admin %}
Admin panel
{% elif user.mod %}
Moderator panel
{% else %}
User panel
{% endif %}
```
### Loops
```
{% for item in items %}
{{ item.name }}
{% endfor %}
{% for i in range(5) %}
{{ i }}
{% endfor %}
```
### Set Statements
```
{% set counter = 0 %}
{% set total = price * quantity %}
```
### Macros
```
{% macro render_item(name, price) %}
<div>{{ name }}: {{ price }}</div>
{% endmacro %}
{{ render_item("Widget", 99) }}
```
### Filters
```
{{ name|upper }}
{{ name|lower }}
{{ items|length }}
{{ items|join(',') }}
{{ items|sort }}
{{ items|reverse }}
{{ items|first }}
{{ items|last }}
{{ value|default('none') }}
```
## Error Handling
The API returns structured errors:
```elixir
{:error, %MinijinjaEx.SyntaxError{message: "syntax error: ..."}}
{:error, %MinijinjaEx.TemplateNotFound{message: "template 'foo' not found"}}
{:error, %MinijinjaEx.UnknownFilter{message: "unknown filter: 'bar'"}}
{:error, %MinijinjaEx.RenderError{message: "..."}}
```
Bang versions raise exceptions:
```elixir
MinijinjaEx.render_string!("{{ 1 + }}", %{})
# => raises MinijinjaEx.SyntaxError
MinijinjaEx.render!(env, "missing_template", %{})
# => raises MinijinjaEx.TemplateNotFound
```
Undefined variables render as empty strings (not errors):
```elixir
{:ok, ""} = MinijinjaEx.render_string("{{ undefined_var }}", %{})
```
## API Reference
### Environment
| Function | Description |
|----------|-------------|
| `new_env(opts)` | Create new environment with optional config |
| `add_template(env, name, source)` | Add template, returns `{:ok, env}` or `{:error, error}` |
| `add_template!(env, name, source)` | Add template, raises on error |
| `render(env, name, context)` | Render template by name |
| `render!(env, name, context)` | Render template, raises on error |
| `reload(env)` | Clear all templates |
### Direct Rendering
| Function | Description |
|----------|-------------|
| `render_string(template, context)` | Render string directly |
| `render_string!(template, context)` | Render string, raises on error |
| `render_string(env, template, context)` | Render string using env settings |
### Configuration
| Function | Description |
|----------|-------------|
| `set_trim_blocks(env, bool)` | Toggle trim_blocks |
| `set_lstrip_blocks(env, bool)` | Toggle lstrip_blocks |
| `set_keep_trailing_newline(env, bool)` | Toggle keep_trailing_newline |
| `add_global(env, name, value)` | Add global variable |
## License
Apache License 2.0
This project is a wrapper for minijinja by Armin Ronacher, also licensed under Apache 2.0.