View Source Pluggable.StepBuilder (pluggable v1.1.0)

Conveniences for building pipelines.

defmodule MyApp do
  use Pluggable.StepBuilder

  step SomeLibrary.Logger
  step :hello, upper: true

  # A function from another module can be plugged too, provided it's
  # imported into the current module first.
  import AnotherModule, only: [interesting_step: 2]
  step :interesting_step

  def hello(token, opts) do
    body = if opts[:upper], do: "WORLD", else: "world"
    send_resp(token, 200, body)
  end
end

Multiple steps can be defined with the step/2 macro, forming a pipeline. The steps in the pipeline will be executed in the order they've been added through the step/2 macro. In the example above, SomeLibrary.Logger will be called first and then the :hello function step will be called on the resulting token.

Options

When used, the following options are accepted by Pluggable.StepBuilder:

  • :init_mode - the environment to initialize the step's options, one of :compile or :runtime. Defaults :compile.

  • :log_on_halt - accepts the level to log whenever the request is halted

  • :copy_opts_to_assign - an atom representing an assign. When supplied, it will copy the options given to the Step initialization to the given token assign

step behaviour

Internally, Pluggable.StepBuilder implements the Pluggable behaviour, which means both the init/1 and call/2 functions are defined.

By implementing the Pluggable API, Pluggable.StepBuilder guarantees this module is a pluggable step and can be run via Pluggable.run/3 or used as part of another pipeline.

Overriding the default Pluggable API functions

Both the init/1 and call/2 functions defined by Pluggable.StepBuilder can be manually overridden. For example, the init/1 function provided by Pluggable.StepBuilder returns the options that it receives as an argument, but its behaviour can be customized:

defmodule StepWithCustomOptions do
  use Pluggable.StepBuilder
  step SomeLibrary.Logger

  def init(opts) do
    opts
  end
end

The call/2 function that Pluggable.StepBuilder provides is used internally to execute all the steps listed using the step macro, so overriding the call/2 function generally implies using super in order to still call the step chain:

defmodule StepWithCustomCall do
  use Pluggable.StepBuilder
  step SomeLibrary.Logger
  step SomeLibrary.AddMeta

  def call(token, opts) do
    token
    |> super(opts) # calls SomeLibrary.Logger and SomeLibrary.AddMeta
    |> assign(:called_all_steps, true)
  end
end

Halting a pluggable step pipeline

A pluggable step pipeline can be halted with Pluggable.Token.halt/1. The builder will prevent further steps downstream from being invoked and return the current token. In the following example, the SomeLibrary.Logger step never gets called:

defmodule StepUsingHalt do
  use Pluggable.StepBuilder

  step :stopper
  step SomeLibrary.Logger

  def stopper(token, _opts) do
    halt(token)
  end
end

Summary

Functions

Compiles a pluggable step pipeline.

A macro that stores a new step. opts will be passed unchanged to the new step.

Types

@type step() :: module() | atom()

Functions

Link to this function

compile(env, pipeline, builder_opts)

View Source
@spec compile(Macro.Env.t(), [{step(), Pluggable.opts(), Macro.t()}], Keyword.t()) ::
  {Macro.t(), Macro.t()}

Compiles a pluggable step pipeline.

Each element of the pluggable step pipeline (according to the type signature of this function) has the form:

{step_name, options, guards}

Note that this function expects a reversed pipeline (with the last step that has to be called coming first in the pipeline).

The function returns a tuple with the first element being a quoted reference to the token and the second element being the compiled quoted pipeline.

Examples

Pluggable.StepBuilder.compile(env, [
  {SomeLibrary.Logger, [], true}, # no guards, as added by the Pluggable.StepBuilder.step/2 macro
  {SomeLibrary.AddMeta, [], quote(do: a when is_binary(a))}
], [])
Link to this macro

step(step, opts \\ [])

View Source (macro)

A macro that stores a new step. opts will be passed unchanged to the new step.

This macro doesn't add any guards when adding the new step to the pipeline; for more information about adding steps with guards see compile/3.

Examples

step SomeLibrary.Logger               # step module
step :foo, some_options: true  # step function