lib/opus/pipeline/stage_filter.ex

defmodule Opus.Pipeline.StageFilter do
  @moduledoc ~S"""
  Module to refine the stages to be run in a pipeline.

  Options

  * `:except`: A list of names, or an atom of stages to skip
  * `:only`:  A list of names, or an atom of stages to keep
  """

  import Enum, only: [reject: 2, filter: 2]

  @doc false
  def call(stages, opts) do
    stages
    |> stage_filter(:except, opts[:except])
    |> stage_filter(:only, opts[:only])
  end

  defp stage_filter(stages, _type, nil), do: stages
  defp stage_filter(stages, type, name) when is_atom(name), do: stage_filter(stages, type, [name])

  defp stage_filter(stages, :except, [_ | _] = names),
    do: do_stage_filter(stages, &reject(&1, fn {_, name, _} -> name in names end))

  defp stage_filter(stages, :only, [_ | _] = names) do
    do_stage_filter(stages, &filter(&1, fn {_, name, _} -> name in names end))
  end

  defp stage_filter(stages, _, _), do: stages

  defp do_stage_filter(stages, fun), do: fun.(stages)
end