With Docker:
$ docker run -v `pwd`:/data samoht/ramen
With opam:
$ opam install ramen
$ ramen
Check ramen --help
for more details.
The CLI help message for Ramen says:
Usage: ramen [--data=<path>] [--pages=<path>] [--site=<path>] [-v]
These three directories are:
site/
: the generated website, created by Ramen. Add images or stylesheet
here but do not edit the contents of processed files there.
Copy that directory to your live website to put your static website live.
pages/
: the base templates. All the templates in that directory
are processed by Ramen and the expanded results are copied into
site/
.
data/
: the data read by Ramen used to feed the templates in pages/
.
There are 2 kinds of data:
raw data: Ramen uses these to complete template variables. Example of raw data could either be a raw file or a header value.
collections: Ramen uses these to expand for loops. foo.bar
denotes
the entry bar
in the collection foo
. These are built from directories
in data/
or from structured files (with .yml
or .json
extensions).
Collection are ordered:
Ramen predefines the global
collection, with the following contents:
global | description |
---|---|
site.date |
the date of build. |
site.pages |
contents of the pages/ directory. |
site.page |
the current page being built. |
Every template in pages has the following structure:
var_1: value_1
var_2: value_2
---
body
The body can contain templates of the form:
variables: {{ var }}
: Ramen replaces these with their raw
values defined in the page header or in the data directory (see
bellow). Variables are alpha-numeric characters with -
and _
.
Full variables can contain dots, to explore collections. For instance,
if foo
has two keys a
and b
(as for instance their exists two files data/foo/a
and data/foo/b
) the contents of these could be
accessed in template bodies using foo.a
and foo.b
.
When reading files in the data/
directory, Ramen always removes
the file extensions to build the variable names:
the contents of foo/a.html
is available as foo.a
.
In some cases (see
bellow for details),
the contents is pre-processed.
Raw data can also contains the {{ .. }}
quotations. They are
expanded recursively by Ramen.
aliases: {{ let n = var in }}
binds n
to the contents of the variable
var
. This is useful to factorize some code.
loops: {{ for i in var do }} <body> {{ done }}
: Ramen
expands the body for each entry in the collection var
.
For instance, if data/foo
contains two files data/foo/a.md
and
data/foo/b.md
which contains toto
and titi
respectively, then:
{{ for i in foo do }}
Hello {{ i }}.
{{ done }}
is equivalent to:
Hello toto.
Hello titi.
When a collection is used as a parameter of a loop, two extra fields are
added in the context: first
and last
. These are useful to test for
start or end conditions, for instance:
{{ for i in foo do }}
{{ if (i = foo.first) }}
Hello first {{ i }}.
{{ else }}
Hello {{ i }}
{{ fi }}
{{ done }}
Moreover, every collection can be seen as a doubly-linked list, where elements
are linked by the prev
and next
fields. For instance, the previous code
snippet is equivalent to:
{{ for i in foo do }}
{{ if (!i.prev) }}
Hello first {{ i }}.
{{ else }}
Hello {{ i.prev.next }}
{{ fi }}
{{ done }}
The order in which the iteration is done is by default the order in which
the collection is built (lexical order, order in which items appears in a
file, etc). It is possible to control the iteration order by using the
built-in function rev(..)
and sort(..,<id>)
where id
is the key in
which to base the sort.
conditions: {{ if (cond_1) }} <body_1> ... {{ elif (cond_n) }} <body_n> {{ else }} <body_x> {{ fi }}
.
Ramen picks the first <body_i>
such that cond_i
is
satisfied or uses <body_x>
otherwise (or an empty string if none of the
conditions are true and the else clause is missing).
Conditions expressions the compososition of:
var
;var_1 = var_2
or var_1 = 'string'
var_1 != var_2
or var_1 != 'string'
( expr )
! expr
expr_1 && expr_2
expr_1 || expr_2
For instance:
{{ if (i.title && i = site.page) }}
<div class="nav active">{{i.title}}</div>
{{ elif (i.title) }}
<div class"nav">{{i.title}}<div>
{{ fi }}
dictionaries: {{ xxx.[VAR].yyy }}
evaluates to xxx.v.yyy
where v
is the contents of VAR
. This could be used in
conjunction with for loops to "join" various collections.
For example, if you have two collections books
and people
,
you can cross-reference them using:
{{for i in books do}}
<div class="book">
<div class="title">{{i.title}}</div>
<div class="author">{{people.[i.author].name}}</div>
</div>
{{done}}
fonctions: {{ VAR(k_1: v_1, ..., k_n: v_n) }}
this is similar
to evaluating VAR
in the context where k_1
,...,k_n
are bound
to v_1
,...v_n
. For instance, this could be used to parametrize
a template to be re-used in various contexts.
If data/v.md
contains:
entry: .
----
<b>{{entry.title}}</b>: {{entry.contents}}
then, assuming that foo
and bar
are collections with a title
and
contents
entries, v
can be used as follows:
<ul>
<li> {{ v(entry: foo) }} </li>
<li> {{ v(entry: bar) }} </li>
<ul>
The following file extensions are supported:
<file>.json
: the file is transformed into the collection <file>
.
<file>.md
: the file's body is converted from HTML to markdown and is
made available as <file>
.
If the file has some headers, they are available using <file>.<var>
.
<file>.yml
: the file is transformed into the collection <file>
. Note: only
very limited support for yaml at the moment (no nesting, only key-value).
every other files are considered as raw data: <file>.<ext>
corresponds
to binding where <file>
is bound to the contents of that file.
See the examples/ folder.