Defines a cookbook: one package's tree of steps and recipes.
Every cookbook is laid out the same way:
lib/composer/composer_lab.ex # the cookbook module
lib/composer/composer_lab/steps/astral/nav1.ex # a step (use Composer.Step)
lib/composer/composer_lab/steps/astral/_nav1/ # its templates
lib/composer/composer_lab/recipes/*.exs # recipe groups (see Composer.Recipe.Group)
lib/composer/composer_lab/manifest.exs # written by mix composer.cookbook.manifestA step's templates live in the directory named after its file (see
Composer.Templates). There is no cookbook-level templates/ directory.
and declared with:
defmodule Composer.ComposerLab do
use Composer.Cookbook,
summary: "Andy's composer steps",
homepage: "https://github.com/andyl/composer_lab"
endNaming
The cookbook name comes from the module (Composer.ComposerLab is composer_lab)
and must equal the package's OTP app name, so one package defines at most
one cookbook and Hex's package uniqueness keeps cookbook names unique.
The one exception is composer's own built-in cookbook, core.
These names are reserved and rejected at compile time: core, hex, local
and every top-level Composer.* module name (see reserved/0).
Compile-time checks
use Composer.Cookbook fails compilation, with a message that says how to
fix it, when:
- the module is nested (
Composer.Foo.Bar) or its name does not match the app - the name is reserved
- the module is not defined in
lib/composer/<name>.ex - a group file under
recipes/has an invalid name or does not parse - a
.exfile understeps/is not a step (a template stored as bare.exwould be compiled as part of the package; rename it.ex.eex)
Group files are external resources, and adding or removing a group or a
file under steps/ triggers a recompile. The .ex check is textual (the
file must use Composer.Step and be named for its path), since step
modules may not be compiled yet; mix composer.cookbook.lint checks the
compiled modules.
Runtime
A cookbook is described at run time by a %Composer.Cookbook{} struct.
kind is :code for a package's cookbook, :local for your recipes
(see Composer.Local) and :virtual for hex. Recipes and
templates are read from source_dir/1, the cookbook's tree in the
dependency's source, so composer is a development tool: running from a
release is not supported.
Summary
Functions
True when module is loaded and defines a cookbook.
Builds the struct for a cookbook module.
Returns the path of group group, or nil when it does not exist.
Returns the cookbook's group files as {group, path}, sorted by name.
Files with an invalid group name are left out.
The virtual hex cookbook.
Evaluates every group file of the cookbook. Returns the valid recipes,
sorted by id, and {path, reason} for each group, or recipe, that
failed to load.
Returns the module a cookbook named name is defined by, e.g.
Composer.ComposerLab for "composer_lab".
Returns the group file holding recipe id ("group/name"), or nil
when the group or the recipe does not exist.
Returns the cookbook's recipe ids ("group/name"), sorted.
The cookbook names no package may use.
Returns the directory the cookbook's recipes and templates are read from.
Finds a step by id.
Returns the cookbook's steps, sorted by id.
Types
Functions
True when module is loaded and defines a cookbook.
Builds the struct for a cookbook module.
Returns the path of group group, or nil when it does not exist.
Returns the cookbook's group files as {group, path}, sorted by name.
Files with an invalid group name are left out.
@spec hex() :: t()
The virtual hex cookbook.
@spec load_recipes(t()) :: {[Composer.Recipe.t()], [{Path.t(), term()}]}
Evaluates every group file of the cookbook. Returns the valid recipes,
sorted by id, and {path, reason} for each group, or recipe, that
failed to load.
Returns the module a cookbook named name is defined by, e.g.
Composer.ComposerLab for "composer_lab".
Returns the group file holding recipe id ("group/name"), or nil
when the group or the recipe does not exist.
Returns the cookbook's recipe ids ("group/name"), sorted.
Ids are read from each group file's syntax tree, without evaluating it.
A group file that cannot be read this way is skipped; load_recipes/1
reports it.
@spec reserved() :: [String.t()]
The cookbook names no package may use.
Returns the directory the cookbook's recipes and templates are read from.
For a package cookbook, in order: the dependency's source path, the project root when the cookbook belongs to the current project, then the directory recorded at compile time.
@spec step(t(), String.t()) :: {:ok, Composer.Step.Meta.t()} | :error
Finds a step by id.
@spec steps(t()) :: [Composer.Step.Meta.t()]
Returns the cookbook's steps, sorted by id.
The steps are the modules of the cookbook's app named
Composer.<Cookbook>.Steps.* that define __composer_step__/0. Only the
app's own module list is read; nothing is scanned.