Expresso.Placement (expresso v0.1.0)

Copy Markdown View Source

The places of the elements: which element can hold which child

The DSL accepts an element in more places than these rules give, because the macros of the outer entities stay in scope in each nested block. See "The definitions of the elements" in docs/architecture.md. Expresso.PlacementTransformer calls slide/1 for each slide, and it refuses an element in a wrong place. docs/reference/placement.md gives the rules.

A transformer adds children to two elements, and these children are in their place: the Expresso.Element.Lines of a code element and the Expresso.Element.TocEntry of a toc. Expresso.Overlay.Check reports a pause inside an element, so this module accepts a pause in each place.

Summary

Functions

Return the children that an element holds under a key, as a list of modules

Give an error for the first child of an element in a wrong place, at each depth

Give an error for the first element of a slide in a wrong place

Functions

children(parent, key)

@spec children(module(), atom()) :: [module()]

Return the children that an element holds under a key, as a list of modules

iex> Expresso.Element.Columns in Expresso.Placement.children(Expresso.Element.TextBox, :elements)
true
iex> Expresso.Placement.children(Expresso.Element.Callout, :elements) |> Enum.member?(Expresso.Element.Callout)
false

element(element)

@spec element(struct()) :: :ok | {:error, String.t()}

Give an error for the first child of an element in a wrong place, at each depth

Expresso.Element.Chart calls this function for each frame, because the transform of the chart reads the flows of a frame before Expresso.PlacementTransformer runs.

iex> alias Expresso.Builder
iex> {:error, message} = Expresso.Placement.element(%Expresso.Element.Frame{flows: [Builder.node("b")]})
iex> message
"a node is inside a frame, and a frame holds flow"

slide(slide)

@spec slide(Expresso.Slide.t()) :: :ok | {:error, String.t()}

Give an error for the first element of a slide in a wrong place

iex> alias Expresso.Builder
iex> Expresso.Placement.slide(Builder.slide("s", elements: [Builder.callout(:tip)]))
:ok
iex> slide = Builder.slide("s", elements: [Builder.callout(:tip, elements: [Builder.callout(:note)])])
iex> {:error, message} = Expresso.Placement.slide(slide)
iex> message =~ "a callout is inside a callout"
true