Visualize.Generators (Visualize v0.8.3)

Copy Markdown View Source

A host's generators: styles and colors a design names and the frame computes at render (spec/14 §3.13, D-177).

A design stores a call, generate(:name, args), where a style or a color goes; a host module defines the generator as ordinary Elixir:

defmodule MyApp.Generators do
  use Visualize.Generators

  defgenerator tenant_style(tenant_id, ctx) do
    MyApp.Tenants.theme(tenant_id, ctx.assigns).message_style
  end
end

use Visualize.Generators imports defgenerator/2 and compiles __generators__/0, the {name, arity} of every generator the module defines. A generator's last parameter is the context, %{theme: theme, vars: vars, assigns: assigns}; the others are the design's arguments, literal terms or a datum's readings of its field bindings.

The host registers the module — config :visualize, generators: [MyApp.Generators], or generators: [MyApp.Generators] on Visualize.Chart.from_map/2, Visualize.Chart.apply/2 and the other reads and renders — and a name no registered module defines is a validator fault when the chart is built. A generator in a style position returns a style (a name, a node or a list), one in a color position a typed color (Visualize.Color); any other result applies nothing and is logged. A generator that raises is not rescued.

Examples

iex> import Visualize.Generators, only: [generate: 2]
iex> generate(:tenant_style, [{:field, :tenant}])
{:generate, :tenant_style, [{:field, :tenant}]}

Summary

Types

A stored generator call (spec/14 §3.13).

Each generator {name, arity} by the module that defines it.

Functions

A generator: defgenerator name(arg, …, ctx) do … end is a public def of that head, recorded under the module's __generators__/0. The last parameter is the context. A generator of several clauses is defined clause by clause, as any function is, and listed once.

As generate/2 with no arguments.

The stored call {:generate, name, args} a design holds where a style or a color goes (spec/14 §3.13). args are literal terms or field bindings {:field, f}, read per datum. Raises ArgumentError for a name that is not an atom or arguments that are not a list.

The registry of modules then config :visualize, generators: (spec/14 §3.13): each generator {name, arity} by the module that defines it. Raises ArgumentError for a module without __generators__/0 and for a {name, arity} two modules define.

Types

call()

@type call() :: {:generate, atom(), [term()]}

A stored generator call (spec/14 §3.13).

registry()

@type registry() :: %{required({atom(), arity()}) => module()}

Each generator {name, arity} by the module that defines it.

Functions

defgenerator(head, body)

(macro)

A generator: defgenerator name(arg, …, ctx) do … end is a public def of that head, recorded under the module's __generators__/0. The last parameter is the context. A generator of several clauses is defined clause by clause, as any function is, and listed once.

generate(name)

@spec generate(atom()) :: call()

As generate/2 with no arguments.

generate(name, args)

@spec generate(atom(), [term()]) :: call()

The stored call {:generate, name, args} a design holds where a style or a color goes (spec/14 §3.13). args are literal terms or field bindings {:field, f}, read per datum. Raises ArgumentError for a name that is not an atom or arguments that are not a list.

registry(modules \\ [])

@spec registry([module()]) :: registry()

The registry of modules then config :visualize, generators: (spec/14 §3.13): each generator {name, arity} by the module that defines it. Raises ArgumentError for a module without __generators__/0 and for a {name, arity} two modules define.