Skip to content

Instantly share code, notes, and snippets.

@Dalgona
Last active April 11, 2019 01:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Dalgona/1b6160674f8ed4d3b4a3970b6e107739 to your computer and use it in GitHub Desktop.
Save Dalgona/1b6160674f8ed4d3b4a3970b6e107739 to your computer and use it in GitHub Desktop.
Serum Plugin Spec (draft)

(DRAFT) Serum Plugin Specification

DOCUMENT HISTORY

  • 2019-02-26 11:32 — Initial draft
  • 2019-04-10 15:38 — Uploaded to Gist
  • 2019-04-10 16:11 — Split reading_files callback
  • 2019-04-11 10:55 — Added version requirement callbacks

Purpose

To allow experienced users and developers to make their own Serum plugins which can extend the functionality of Serum.

Functions

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.

Details

A Serum plugin is an Elixir module that implements Serum.Plugin behaviour. The Serum.Plugin behaviour module defines several callbacks which are called at some point of time:

Required Callbacks

All Serum plugin module must implement these four callbacks, otherwise the plugin may fail.

  • name() :: binary()

    Name of the plugin

  • version() :: binary()

    Version of the plugin. Must follow the semantic versioning scheme

  • elixir() :: binary()
    serum() :: binary()

    Version requirement of Elixir and Serum, respectively. Refer to this document for the string format

  • description() :: binary()

    Short description about what the plugin does

  • implements() :: [atom()]

    A list of names of optional callbacks that the plugin implements

Optional Callbacks

These optional callbacks have default implementations which simply do nothing and pass the input to the output as is. If some of these callbacks are to be implemented, the names of those callbacks must be present in implements/0, or they will never be called.

  • build_started(src :: binary(), dest :: binary()) :: Result.t()

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

  • reading_pages(files :: [binary()]) :: Result.t([binary()])
    reading_posts(files :: [binary()]) :: Result.t([binary()])
    reading_templates(files :: [binary()]) :: 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.

  • processing_page(file :: Serum.File.t()) :: Result.t(Serum.File.t())
    processing_post(file :: Serum.File.t()) :: Result.t(Serum.File.t())
    processing_template(file :: Serum.File.t()) :: Result.t(Serum.File.t())

    These three callbacks above are called before Serum processes each input file. Plugins can alter the raw contents of input files here.

  • processed_page(page :: Serum.Page.t()) :: Result.t(Serum.Page.t())
    processed_post(post :: Serum.Post.t()) :: Result.t(Serum.Post.t())
    processed_template(template :: Serum.Template.t()) :: Result.t(Serum.Template.t())
    processed_list(list :: Serum.PostList.t()) :: Result.t(Serum.PostList.t())

    These four callbacks above are called after Serum has processed each input file and produced the resulting struct. Plugins can alter the processed contents (an AST in case of a template) and metadata here.

  • rendered_fragment(frag :: Serum.Fragment.t()) :: 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.

  • rendered_page(file :: Serum.File.t()) :: 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.

  • wrote_file(file :: Serum.File.t()) :: Result.t()

    Called after writing each output to a file.

  • build_succeeded(src :: binary(), dest :: binary()) :: Result.t()

    Called if the whole build process has finished successfully.

  • build_failed(src :: binary(), dest :: binary(), result :: Result.t() | Result.t(term)) :: Result.t()

    Called if the build process has failed for some reason.

  • finalizing(src :: binary(), dest :: binary()) :: 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment