.. _tutorial:
Recipe Grid Tutorial
====================
This tutorial will give you an introduction to Recipe Grid including its recipe
description language and tools for compiling recipes into stand-alone HTML
pages or complete recipe websites.
Recipe description basics
-------------------------
.. highlight:: md
Recipes are not described directly in tabular form. Instead, these tables are
generated from a simple textual description of the recipe within a `Markdown
`_ document.
The following example shows a simple recipe Markdown file::
Boiled egg for 1
================
A fairly boring recipe...
boil for 3.5 minutes (
1 egg,
500ml water,
)
This is compiled into HTML using the :ref:`recipe-grid `
command:
.. code:: bash
$ recipe-grid path/to/my_recipe.md
Which produces a file called ``my_recipe.html`` which looks like this:
.. image:: /_static/boiled_egg_example.png
As you can see, the textual recipe description in the indented block in the
Markdown file has been converted into the tabular form (we'll look at this
syntax in greater detail shortly). Aside from these indented blocks, a recipe
is just an ordinary Markdown file which you can structure however you like.
.. note::
In Markdown indented blocks are usually used for code listings but are
co-opted by Recipe Grid for recipe descriptions. If you want to include an
ordinary code block in your recipe, you can do so using a Markdown 'fenced'
block like so::
Here is a code listing:
```
print("Hello, world!")
```
The :ref:`recipe-grid ` command has a few options which
allow us to automatically rescale the quantities in a recipe. In addition to
the :ref:`recipe-grid ` command (which compiles a single
recipe into a standalone HTML page) a other commands are provided to, for
example, produce a static 'recipe book' style website from a collection of
recipes. We'll return to look at these commands and options at the end of this
tutorial.
Recipe description syntax
-------------------------
The central feature of Recipe Grid is its recipe description language which is
compiled into the tabular form which appears in a compiled recipe. Lets take a
look at this language.
For brevity, in the examples below we'll just show the recipe descriptions. To
compile these you'll need to place them in an indented block in a Markdown file
and compile them using the ``recipe-grid`` command as illustrated above.
Ingredients and steps
`````````````````````
Recipe Grid recipes are described in terms of *ingredients* and *steps* which
are carried out on these ingredients.
An ingredient is usually defined by writing a quantity next to a name, for
example ``2 large eggs`` or ``1 tbsp of oil``.
.. note::
Quantities can be given as either decimal numbers or as fractions. For
example ``3.5`` and ``3 1/2`` could both be used to mean three-and-a-half.
A step is defined by a description, followed by a pair of parentheses
containing the inputs to that step. For example:
.. recipe::
:start-new-recipe:
:show-source:
fry(2 large eggs, 1 tbsp of oil)
A recipe typically consists of a hierarchy of steps and ingredients, for
example:
.. recipe::
:start-new-recipe:
:show-source:
put in rolls (
fry until soft (
slice(1 large onion),
1 tbsp of oil
),
boil(4 hot dog sausages),
sliced(4 hot dog rolls),
)
As in this example, you are free to split the inputs to a step over multiple
lines if this makes the recipe description easier to read.
.. note::
If your step or ingredient name contains any characters more exciting than
letters and numbers you must enclose it in single or double quotes. For
example:
.. recipe::
:start-new-recipe:
:show-source:
"fry (don't allow to burn)" ( 1 can of spam )
Listing ingredients separately
``````````````````````````````
Often when you're translating a traditional recipe into the recipe description
syntax you already have a list of quantities and ingredients. Rather than
manually transcribing these quantities, it is possible to copy-and-paste a list
of ingredients up-front and refer back to these later in the recipe
description. For example:
.. recipe::
:start-new-recipe:
:show-source:
400g of chopped tomatoes
1 tsp of mixed herbs
1 onion, finely chopped, fried
200g of mozzarella, grated
1 pizza base
top (
mozzarella,
boil down(chopped tomatoes, mixed herbs, onion),
pizza base,
)
When referring to an ingredient you only write the ingredient name, e.g. 'mixed
herbs': the quantity (e.g. '1 tsp') and simple prepositions (e.g. 'of') should
be omitted.
Additional simple steps, separated by commas, can be defined for ingredients
listed up-front, for example the onion has two steps listed: 'finely chopped'
and 'fried'. In the recipe description later on where we say 'onion' Recipe
Grid will insert both the ingredient and the steps we defined.
.. note::
The syntax above relies on Recipe Grid being able to distinguish quantities
and units from an ingredient's name. Recipe Grid knows about the following
common cooking units:
.. rgunitlist::
If you're dealing with an unusual unit which Recipe Grid might not know
about, or you just prefer to be explicit, you can surround the quantity and
unit with curly brackets, for example:
.. code:: text
{2 scoops} of ice cream
By contrast, if your ingredient name might be confused for a unit or
preposiition you can use quotes around the ingredient name, for example:
.. code:: text
2 "KG Spooner Brand Biscuits"
.. note::
In many of these examples we've included the preposition 'of' in ingredient
descriptions purely to make them read better. This is completely optional
as far as the recipe description language is concerned: '1 tsp of mixed
herbs' and '1 tsp mixed herbs' are equally valid.
Sub-recipes
```````````
Recipe Grid allows recipes to be broken up into sub-recipes which can make them
easier to write. For example, we can break the pizza sauce from the previous
recipe into its own sub-recipe like so:
.. recipe::
:start-new-recipe:
:show-source:
pizza sauce = boil down (
400g chopped tomatoes,
1 tsp mixed herbs,
fried(finely chopped(1 onion)),
)
top (
grated(200g mozzarella),
pizza sauce,
1 pizza base,
)
Notice that, once compiled, the sub recipe is seamlessly combined into the
final recipe.
Sometimes it is helpful if a sub recipe is named and called out in the final
recipe; particularly for more complex recipes, or recipes where some parts can
be prepared in advance. Replacing the ``=`` symbol with ``:=`` in our sub
recipe definition will cause Recipe Grid to highlight and label the sub recipe
in the generated table, for example, after modifying the example above we get:
.. recipe::
:start-new-recipe:
pizza sauce := boil down (
400g chopped tomatoes,
1 tsp mixed herbs,
fried(finely chopped(1 onion)),
)
top (
grated(200g mozzarella),
pizza sauce,
1 pizza base,
)
.. note::
The up-front ingredient syntax described in the previous section is
actually just a short-hand for creating a sub recipes. When a single
ingredient (with any number of steps acting on it) is defined on its own, a
sub recipe with the ingredient's name is automatically created.
Splitting recipe components up
``````````````````````````````
Sometimes recipes call for ingredients or sub recipes to be split into parts
which are then used separately. For example in the following recipe for
enchiladas, some of the sauce is mixed with the chicken and some is poured over
the top before baking.
.. recipe::
:start-new-recipe:
:show-source:
tomato sauce = boil down (
400g chopped tomatoes,
spices,
)
bake until golden (
pour over(
fill (
simmer for 5 minutes (
fry (
200g chicken,
sliced(1 onion),
),
2/3 of the tomato sauce,
),
4 tortilla wraps,
),
remaining tomato sauce,
100g grated cheese,
)
)
In this case, Recipe Grid splits the recipe into two tables: one for the tomato
sauce and one for the remainder of the recipe. In the main part of the recipe
the references to the tomato sauce contain links to the sub recipe.
References to sub recipes follow a similar form to ingredients: they begin with
a quantity (e.g. ``20g``) or proportion (e.g. ``1/2 of the`` or ``50%`` or
``remaining``) followed by an optional preposition (e.g. 'of the') and then
the name of the sub recipe being referenced.
Sub recipes with multiple outputs
`````````````````````````````````
Sometimes a step may produce multiple things. For example, after boiling some
vegetables you may wish to use both the vegetables and the water they were
boiled in. To do this, you can define a sub recipe to have multiple outputs
like so:
.. recipe::
:start-new-recipe:
:show-source:
boiled veg, veg water = drain reserving water(
boil(
carrots,
peas,
)
)
pour over (
make gravy (5 tsp of gravy browning, veg water),
boiled veg,
)
Mixing prose and recipe tables
``````````````````````````````
For particularly complicated recipes it is possible to split a recipe into sub
recipes which appear at different points in the document. To do this, simply
create multiple indented blocks in your markdown document which define sub
recipes which reference each other. For example::
Pizza for 2
===========
First you should make some pizza sauce:
pizza sauce = boil down (
400g chopped tomatoes,
1 tsp mixed herbs,
fried(finely chopped(1 onion)),
)
Then once you've done that you can go ahead and make some pizza:
top (
grated(200g mozzarella),
pizza sauce,
1 pizza base,
)
Will compile into:
.. image:: /_static/split_recipe_example.png
.. note::
You can only reference sub recipes defined earlier in the recipe
description, or in an earlier indented block. Forward references are not
allowed.
Scaling recipes
---------------
Recipe Grid can automatically rescale quantities in recipes. Using the
``recipe-grid`` command, this is achieved by adding the ``--scale`` argument
followed by a scaling factor. For example, to compile a recipe, halving all of
the quantities we would write:
.. code:: bash
$ recipe-grid --scale 1/2 path/to/recipe.md
.. note::
When the scaling factor is given as an integer or a fraction, quantities in
the recipe will be shown as fractions too (where the denominator is
sensible). Using a decimal number (e.g. ``0.5``) will cause all quantities
to be shown as decimal numbers.
When a recipe's main title ends with a phrase like ``for 3`` or ``serves 7``,
the ``--servings`` argument can be used instead, taking the desired number of
servings to make (saving hand-calculating the appropriate scaling factor).
.. code:: bash
$ recipe-grid --servings 3 path/to/recipe.md
In either case, when the recipe is compiled, a subtitle is added indicating any
scaling applied:
.. image:: /_static/scaling_example.png
Sometimes your recipe may contain numbers which ought to be scaled with the
ingredient quantities. For example, in a burger recipe you might have a step
which says 'divide into 4 patties'. To make a number scale with the recipe you
can enclose it in curly brackets, for example:
.. recipe::
:start-new-recipe:
:show-source:
grill for 10 minutes (
divide into {4} patties (
mash together(
450g minced beef,
finely chopped(1 onion),
1 tsp mixed herbs,
)
)
)
And then the same recipe scaled up by a factor of two gives:
.. recipe::
:start-new-recipe:
:scale: 2
grill for 10 minutes (
divide into {4} patties (
mash together(
450g minced beef,
finely chopped(1 onion),
1 tsp mixed herbs,
)
)
)
.. tip::
You can also use the curly bracket syntax in the rest of your Markdown
document, not just in indented recipe description blocks.
.. note::
Within a recipe block, to get a literal ``{`` or ``}`` character you can
enclose it in quotes (e.g. ``"{"`` or ``"}"``). Within the rest of the
Markdown document, you can use a backslash to escape them (e.g. ``\{`` and
``\}``).
Linting
-------
Recipe Grid provides a linting tool, :ref:`recipe-grid-lint
`, which checks for common mistakes within recipes.
For example, given the following recipe::
Boiled egg for 1
================
A simple recipe, with a simple mistake...
2 eggs
500ml water
boil(egg, water)
The linter will spot that the eggs were never used: in the recipe we mistakenly
referenced 'egg' and not 'eggs'.
.. code:: text
$ recipe-grid-lint path/to/recipe.md
/path/to/recipe.md: Warning: Ingredient 'eggs' was defined but never used. [unused_ingredient]
When no issues are found, the command exits without printing anything.
Generating recipe book static websites
--------------------------------------
As well as compiling individual recipes into standalone HTML pages, Recipe Grid
can also compile collections of recipes into a complete recipe book website
using the :ref:`recipe-grid-site ` command. The generated
websites are completely static and may be used both on- and offline.
To generate a recipe website, recipes should be collected together with
filenames ending in ``.md``. If desired, recipes can be grouped into a
directories which and displayed as browsable categories in the generated
website.
A ``README.md`` file may optionally be added to each directory and will be
shown on the relevant recipe browsing pages.
For example a site might have a directory tree as follows:
.. code:: text
+ README.md
+ pasta/
| + README.md
| + spaghetti.md
| + lasagne.md
+ indian/
| + dahl.md
| + curry.md
A recipe website is then generated using the :ref:`recipe-grid-site
` command as follows:
.. code:: bash
$ recipe-grid-site path/to/recipes/dir/ path/to/output/dir/
The generated website can then be opened in a browser and used locally or
uploaded to a static web hosting service and used online.
.. image:: /_static/site_example_home.png
.. image:: /_static/site_example_categories.png
.. image:: /_static/site_example_category.png
.. image:: /_static/site_example_recipe.png