CooklangEx

Hex.pmDocumentation

Elixir bindings for the canonical Cooklang parser, powered by cooklang-rs via Rustler NIFs.

Features

Installation

Add cooklang_ex to your list of dependencies in mix.exs:

def deps do
[
{:cooklang_ex, "~> 0.1.0"}
]
end

Requirements

Quick Start

# Parse a simple recipe
recipe_text = """
>> servings: 2
>> time: 15 minutes
Crack @eggs{3} into a #bowl{large} and whisk until fluffy.
Heat @butter{2%tbsp} in a #pan{non-stick} over medium heat.
Pour egg mixture into pan and cook for ~{3%minutes}, stirring gently.
Season with @salt{} and @black pepper{} to taste.
"""
{:ok, recipe} = CooklangEx.parse(recipe_text)
# Access parsed data
recipe.metadata
# => %{"servings" => "2", "time" => "15 minutes"}
recipe.ingredients
# => [
# %CooklangEx.Recipe.Ingredient{name: "eggs", quantity: %{value: 3.0, unit: nil}},
# %CooklangEx.Recipe.Ingredient{name: "butter", quantity: %{value: 2.0, unit: "tbsp"}},
# %CooklangEx.Recipe.Ingredient{name: "salt", quantity: nil},
# %CooklangEx.Recipe.Ingredient{name: "black pepper", quantity: nil}
# ]
recipe.cookware
# => [
# %CooklangEx.Recipe.Cookware{name: "bowl", quantity: %{value: "large"}},
# %CooklangEx.Recipe.Cookware{name: "pan", quantity: %{value: "non-stick"}}
# ]
recipe.timers
# => [%CooklangEx.Recipe.Timer{quantity: %{value: 3.0, unit: "minutes"}}]

Scaling Recipes

Scale recipes to different serving sizes:

recipe_text = """
>> servings: 4
Mix @flour{400%g} with @water{250%ml}.
Add @yeast{1%packet} and @salt{1%tsp}.
"""
# Scale from 4 servings to 8
{:ok, scaled} = CooklangEx.parse_and_scale(recipe_text, 8)
# Quantities are automatically doubled
hd(scaled.ingredients).quantity.value
# => 800.0 (was 400)

Cooklang Syntax Reference

Ingredients

@ingredient # Simple ingredient
@eggs{3} # With quantity
@flour{200%g} # With quantity and unit
@ground black pepper{} # Multi-word name

Cookware

#pan # Simple cookware
#bowl{large} # With size/description
#mixing bowl{} # Multi-word name

Timers

~{10%minutes} # Duration timer
~{30%seconds} # Another timer
~name{5%minutes} # Named timer

Metadata

>> servings: 4
>> source: https://example.com/recipe
>> time: 30 minutes

Comments

-- This is a comment
Add @salt{} -- inline comment

Steps

Steps are separated by blank lines:

First step here.
Second step here.
Third step here.

API Reference

CooklangEx.parse/2

Parse a Cooklang recipe string.

{:ok, recipe} = CooklangEx.parse(text)
{:ok, recipe} = CooklangEx.parse(text, all_extensions: false)

CooklangEx.parse!/2

Parse a recipe, raising on error.

recipe = CooklangEx.parse!(text)

CooklangEx.parse_and_scale/3

Parse and scale a recipe to target servings.

{:ok, recipe} = CooklangEx.parse_and_scale(text, 8)

CooklangEx.ingredients/1

Extract just the ingredients list.

{:ok, ingredients} = CooklangEx.ingredients(text)

CooklangEx.cookware/1

Extract just the cookware list.

{:ok, cookware} = CooklangEx.cookware(text)

CooklangEx.metadata/1

Extract just the metadata map.

{:ok, metadata} = CooklangEx.metadata(text)

Extensions

The parser supports several extensions to the base Cooklang specification. By default, all extensions are enabled. Disable them with:

CooklangEx.parse(text, all_extensions: false)

Extensions include:

See the cooklang-rs extensions documentation for details.

Release Process

Creating a new release is simple - just create and publish a GitHub release with a version tag:

  1. Create a new release on GitHub with a version tag (e.g., v0.1.0)
  2. Publish the release - The CI workflow automatically:
    • Updates the VERSION file
    • Runs validation and tests
    • Publishes to Hex.pm
    • Publishes documentation to HexDocs

The GitHub release tag is the source of truth for versioning. The VERSION file in the repository is automatically updated to match the release tag.

Development

# Clone the repo
git clone https://github.com/yourusername/cooklang_ex
cd cooklang_ex
# Optional: if you're using asdf, set up your versioning
cp .tool-versions.example .tool-versions
# Install dependencies
mix deps.get
# Compile (this will also compile the Rust NIF)
mix compile
# Run tests
mix test

License

MIT License - see LICENSE for details.

Acknowledgments