View Source Serum.Plugin behaviour (serum_md v1.6.0)

A behaviour that all Serum plugin module must implement.

This module allows experienced Serum users and developers to make their own Serum plugins which can extend the functionality of Serum.

A Serum plugin can...

  • Alter contents of input or output files,
  • Execute arbitrary codes during some stages of site building,
  • And optionally provide extra Mix tasks that extends Serum.

For Plugin Developers

In order for a Serum plugin to work, you must implement at least these four callbacks:

  • name/0
  • version/0
  • elixir/0
  • serum/0
  • description/0
  • implements/0

Also there are a number of other callbacks you can optionally implement. Read the rest of the documentation for this module to see which callbacks you can implement and what each callback should do.

For Plugin Users

To enable Serum plugins, add a plugins key to your serum.exs(if it does not exist), and put names of Serum plugin modules there.

%{
  plugins: [
    Awesome.Serum.Plugin,
    Great.Serum.Plugin
  ]
}

You can also restrict some plugins to run only in specific Mix environments. For example, if plugins are configured like the code below, only Awesome.Serum.Plugin plugin will be loaded when MIX_ENV is set to prod.

%{
  plugins: [
    Awesome.Serum.Plugin,
    {Great.Serum.Plugin, only: :dev},
    {Another.Serum.Plugin, only: [:dev, :test]}
  ]
}

The order of plugins is important, as Serum will call plugins one by one, from the first item to the last one. Therefore these two configurations below may produce different results.

Configuration 1:

%{
  plugins: [
    Awesome.Serum.Plugin,
    Another.Serum.Plugin
  ]
}

Configuration 2:

%{
  plugins: [
    Another.Serum.Plugin,
    Awesome.Serum.Plugin
  ]
}

Summary

Callbacks

Called if the build process has failed for some reason.

Called right after the build process has started. Some necessary OTP applications or processes should be started here.

Called if the whole build process has finished successfully.

Returns the short description of the plugin.

Returns the version requirement of Elixir.

Called right before Serum exits, whether the build has succeeded or not.

Returns a list of optional callbacks which the plugin implements.

Returns the name of the plugin.

Called after Serum has processed each input file and produced the resulting struct.

Called after Serum has processed each input file and produced the resulting struct.

Called after Serum has successfully processed all pages.

Called after Serum has processed each input file and produced the resulting struct.

Called after Serum has successfully processed all blog posts.

Called after Serum has processed each input file and produced the resulting struct.

Called before Serum processes each input file.

Called before Serum processes each input file.

Called before Serum processes each input file.

Called before reading input files.

Called before reading input files.

Called before reading input files.

Called after producing a HTML fragment for each page.

Called when Serum has rendered a full page and it's about to write to an output file.

Called while each fragment is being constructed.

Returns the version requirement of Serum.

Returns the version of the plugin.

Called after writing each output to a file.

Types

@type plugin_options() :: [only: atom() | [atom()], args: term()]
@type spec() :: atom() | {atom(), plugin_options()}
@type t() :: %Serum.Plugin{
  args: term(),
  description: binary(),
  implements: [atom()],
  module: atom(),
  name: binary(),
  version: binary()
}

Callbacks

Link to this callback

build_failed(src, dest, result)

View Source (optional)
@callback build_failed(
  src :: binary(),
  dest :: binary(),
  result :: Serum.Result.t() | Serum.Result.t(term())
) :: Serum.Result.t()

Called if the build process has failed for some reason.

Link to this callback

build_failed(src, dest, result, args)

View Source (optional)
@callback build_failed(
  src :: binary(),
  dest :: binary(),
  result :: Serum.Result.t() | Serum.Result.t(term()),
  args :: term()
) :: Serum.Result.t()
Link to this callback

build_started(src, dest)

View Source (optional)
@callback build_started(src :: binary(), dest :: binary()) :: Serum.Result.t()

Called right after the build process has started. Some necessary OTP applications or processes should be started here.

Link to this callback

build_started(src, dest, args)

View Source (optional)
@callback build_started(src :: binary(), dest :: binary(), args :: term()) ::
  Serum.Result.t()
Link to this callback

build_succeeded(src, dest)

View Source (optional)
@callback build_succeeded(src :: binary(), dest :: binary()) :: Serum.Result.t()

Called if the whole build process has finished successfully.

Link to this callback

build_succeeded(src, dest, args)

View Source (optional)
@callback build_succeeded(src :: binary(), dest :: binary(), args :: term()) ::
  Serum.Result.t()
@callback description() :: binary()

Returns the short description of the plugin.

You must implement this callback, or the plugin may fail.

@callback elixir() :: binary()

Returns the version requirement of Elixir.

Refer to this document for the string format.

You must implement this callback, or the plugin may fail.

Link to this callback

finalizing(src, dest)

View Source (optional)
@callback finalizing(src :: binary(), dest :: binary()) :: Serum.Result.t()

Called right before Serum exits, whether the build has succeeded or not.

This is the place where you should clean up any temporary resources created in build_started/2 callback.

Link to this callback

finalizing(src, dest, args)

View Source (optional)
@callback finalizing(src :: binary(), dest :: binary(), args :: term()) ::
  Serum.Result.t()
@callback implements() :: [atom() | {atom(), integer()}]

Returns a list of optional callbacks which the plugin implements.

Each list item can be in one of two forms:

  • {callback_name, arity}
  • callback_name - This is deprecated and left for compatibility. New Serum plugins must use the above format.

For example, if your plugin implements build_started/2 and finalizing/2, you must implement this callback so that it returns [build_started: 2, finalizing: 2].

You must implement this callback, or the plugin may fail.

@callback name() :: binary()

Returns the name of the plugin.

You must implement this callback, or the plugin may fail.

Link to this callback

processed_list(list)

View Source (optional)
@callback processed_list(list :: Serum.PostList.t()) :: Serum.Result.t(Serum.PostList.t())

Called after Serum has processed each input file and produced the resulting struct.

Plugins can alter the processed contents and metadata here.

Link to this callback

processed_list(list, args)

View Source (optional)
@callback processed_list(list :: Serum.PostList.t(), args :: term()) ::
  Serum.Result.t(Serum.PostList.t())
Link to this callback

processed_page(page)

View Source (optional)
@callback processed_page(page :: Serum.Page.t()) :: Serum.Result.t(Serum.Page.t())

Called after Serum has processed each input file and produced the resulting struct.

Plugins can alter the processed contents and metadata here.

Link to this callback

processed_page(page, args)

View Source (optional)
@callback processed_page(page :: Serum.Page.t(), args :: term()) ::
  Serum.Result.t(Serum.Page.t())
Link to this callback

processed_pages(pages)

View Source (optional)
@callback processed_pages(pages :: [Serum.Page.t()]) :: Serum.Result.t([Serum.Page.t()])

Called after Serum has successfully processed all pages.

Link to this callback

processed_pages(pages, args)

View Source (optional)
@callback processed_pages(pages :: [Serum.Page.t()], args :: term()) ::
  Serum.Result.t([Serum.Page.t()])
Link to this callback

processed_post(post)

View Source (optional)
@callback processed_post(post :: Serum.Post.t()) :: Serum.Result.t(Serum.Post.t())

Called after Serum has processed each input file and produced the resulting struct.

Plugins can alter the processed contents and metadata here.

Link to this callback

processed_post(post, args)

View Source (optional)
@callback processed_post(post :: Serum.Post.t(), args :: term()) ::
  Serum.Result.t(Serum.Post.t())
Link to this callback

processed_posts(posts)

View Source (optional)
@callback processed_posts(posts :: [Serum.Post.t()]) :: Serum.Result.t([Serum.Post.t()])

Called after Serum has successfully processed all blog posts.

Link to this callback

processed_posts(posts, args)

View Source (optional)
@callback processed_posts(posts :: [Serum.Post.t()], args :: term()) ::
  Serum.Result.t([Serum.Post.t()])
Link to this callback

processed_template(template)

View Source (optional)
@callback processed_template(template :: Serum.Template.t()) ::
  Serum.Result.t(Serum.Template.t())

Called after Serum has processed each input file and produced the resulting struct.

Plugins can alter the AST and its metadata here.

Link to this callback

processed_template(template, args)

View Source (optional)
@callback processed_template(template :: Serum.Template.t(), args :: term()) ::
  Serum.Result.t(Serum.Template.t())
Link to this callback

processing_page(file)

View Source (optional)
@callback processing_page(file :: Serum.File.t()) :: Serum.Result.t(Serum.File.t())

Called before Serum processes each input file.

Plugins can alter the raw contents of input files here.

Link to this callback

processing_page(file, args)

View Source (optional)
@callback processing_page(file :: Serum.File.t(), args :: term()) ::
  Serum.Result.t(Serum.File.t())
Link to this callback

processing_post(file)

View Source (optional)
@callback processing_post(file :: Serum.File.t()) :: Serum.Result.t(Serum.File.t())

Called before Serum processes each input file.

Plugins can alter the raw contents of input files here.

Link to this callback

processing_post(file, args)

View Source (optional)
@callback processing_post(file :: Serum.File.t(), args :: term()) ::
  Serum.Result.t(Serum.File.t())
Link to this callback

processing_template(file)

View Source (optional)
@callback processing_template(file :: Serum.File.t()) :: Serum.Result.t(Serum.File.t())

Called before Serum processes each input file.

Plugins can alter the raw contents of input files here.

Link to this callback

processing_template(file, args)

View Source (optional)
@callback processing_template(file :: Serum.File.t(), args :: term()) ::
  Serum.Result.t(Serum.File.t())
Link to this callback

reading_pages(files)

View Source (optional)
@callback reading_pages(files :: [binary()]) :: Serum.Result.t([binary()])

Called before reading input files.

Plugins can manipulate the list of files to be read and pass it to the next plugin.

Link to this callback

reading_pages(files, args)

View Source (optional)
@callback reading_pages(files :: [binary()], args :: term()) :: Serum.Result.t([binary()])
Link to this callback

reading_posts(files)

View Source (optional)
@callback reading_posts(files :: [binary()]) :: Serum.Result.t([binary()])

Called before reading input files.

Plugins can manipulate the list of files to be read and pass it to the next plugin.

Link to this callback

reading_posts(files, args)

View Source (optional)
@callback reading_posts(files :: [binary()], args :: term()) :: Serum.Result.t([binary()])
Link to this callback

reading_templates(files)

View Source (optional)
@callback reading_templates(files :: [binary()]) :: Serum.Result.t([binary()])

Called before reading input files.

Plugins can manipulate the list of files to be read and pass it to the next plugin.

Link to this callback

reading_templates(files, args)

View Source (optional)
@callback reading_templates(files :: [binary()], args :: term()) ::
  Serum.Result.t([binary()])
Link to this callback

rendered_fragment(frag)

View Source (optional)
@callback rendered_fragment(frag :: Serum.Fragment.t()) ::
  Serum.Result.t(Serum.Fragment.t())

Called after producing a HTML fragment for each page.

Plugins can modify the contents and metadata of each fragment here.

Link to this callback

rendered_fragment(frag, args)

View Source (optional)
@callback rendered_fragment(frag :: Serum.Fragment.t(), args :: term()) ::
  Serum.Result.t(Serum.Fragment.t())
Link to this callback

rendered_page(file)

View Source (optional)
@callback rendered_page(file :: Serum.File.t()) :: Serum.Result.t(Serum.File.t())

Called when Serum has rendered a full page and it's about to write to an output file.

Plugins can alter the raw contents of the page to be written.

Link to this callback

rendered_page(file, args)

View Source (optional)
@callback rendered_page(file :: Serum.File.t(), args :: term()) ::
  Serum.Result.t(Serum.File.t())
Link to this callback

rendering_fragment(html, metadata)

View Source (optional)
@callback rendering_fragment(html :: Floki.html_tree(), metadata :: map()) ::
  Serum.Result.t(Floki.html_tree())

Called while each fragment is being constructed.

Plugins can alter the HTML tree of its contents (which is generated by Floki). It is recommended to implement this callback if you want to modify the HTML document without worrying about breaking it.

Link to this callback

rendering_fragment(html, metadata, args)

View Source (optional)
@callback rendering_fragment(html :: Floki.html_tree(), metadata :: map(), args :: term()) ::
  Serum.Result.t(Floki.html_tree())
@callback serum() :: binary()

Returns the version requirement of Serum.

Refer to this document for the string format.

You must implement this callback, or the plugin may fail.

@callback version() :: binary()

Returns the version of the plugin.

The returned version string must follow the semantic versioning scheme.

You must implement this callback, or the plugin may fail.

Link to this callback

wrote_file(file)

View Source (optional)
@callback wrote_file(file :: Serum.File.t()) :: Serum.Result.t()

Called after writing each output to a file.

Link to this callback

wrote_file(file, args)

View Source (optional)
@callback wrote_file(file :: Serum.File.t(), args :: term()) :: Serum.Result.t()

Functions

Link to this function

build_failed(src, dest, result)

View Source
@spec build_failed(
  src :: binary(),
  dest :: binary(),
  result :: Serum.Result.t() | Serum.Result.t(term())
) :: Serum.Result.t()
Link to this function

build_started(src, dest)

View Source
@spec build_started(src :: binary(), dest :: binary()) :: Serum.Result.t()
Link to this function

build_succeeded(src, dest)

View Source
@spec build_succeeded(src :: binary(), dest :: binary()) :: Serum.Result.t()

Returns a specification to start this module under a supervisor.

See Supervisor.

@spec finalizing(src :: binary(), dest :: binary()) :: Serum.Result.t()
@spec processed_list(list :: Serum.PostList.t()) :: Serum.Result.t(Serum.PostList.t())
@spec processed_page(page :: Serum.Page.t()) :: Serum.Result.t(Serum.Page.t())
@spec processed_pages(pages :: [Serum.Page.t()]) :: Serum.Result.t([Serum.Page.t()])
@spec processed_post(post :: Serum.Post.t()) :: Serum.Result.t(Serum.Post.t())
@spec processed_posts(posts :: [Serum.Post.t()]) :: Serum.Result.t([Serum.Post.t()])
Link to this function

processed_template(template)

View Source
@spec processed_template(template :: Serum.Template.t()) ::
  Serum.Result.t(Serum.Template.t())
@spec processing_page(file :: Serum.File.t()) :: Serum.Result.t(Serum.File.t())
@spec processing_post(file :: Serum.File.t()) :: Serum.Result.t(Serum.File.t())
Link to this function

processing_template(file)

View Source
@spec processing_template(file :: Serum.File.t()) :: Serum.Result.t(Serum.File.t())
@spec reading_pages(files :: [binary()]) :: Serum.Result.t([binary()])
@spec reading_posts(files :: [binary()]) :: Serum.Result.t([binary()])
Link to this function

reading_templates(files)

View Source
@spec reading_templates(files :: [binary()]) :: Serum.Result.t([binary()])
@spec rendered_fragment(frag :: Serum.Fragment.t()) ::
  Serum.Result.t(Serum.Fragment.t())
@spec rendered_page(file :: Serum.File.t()) :: Serum.Result.t(Serum.File.t())
Link to this function

rendering_fragment(html, metadata)

View Source
@spec rendering_fragment(html :: Floki.html_tree(), metadata :: map()) ::
  Serum.Result.t(Floki.html_tree())
@spec wrote_file(file :: Serum.File.t()) :: Serum.Result.t()