/behave

Behave allows you to check whether one Elixir Module implements a given Behaviour.

Primary LanguageElixirMIT LicenseMIT

Behave

Hex Version Hex Downloads License

Description

Behave allows you to check whether one Elixir Module implements a given Behaviour.

Elixir will show you at compile-time (via a warning) if you haven't implemented a required function in a Behaviour. However, there is no way to determine whether or not a given Module implements another Module's Behaviour.

I needed this so I could pass a list of Modules to a function and safely call a function on them, or log a warning if that function didn't exist.

Examples

defmodule BehaviourModule do
  @doc """
  Get registration information for a module.

  Should return 2-tuple containing name and configuration map.
  """
  @callback registration() :: {name :: term, configuration :: map()}
end

defmodule ImplementationModule do
  @behaviour BehaviourModule

  def registration do
    config = %{
      version: "4.2.0",
      log_level: :warn
    }

    {"module_name", config}
  end
end

defmodule NoImplementationModule do
  def install do
    # Doesn't matter
  end
end

defmodule Server do
  use GenServer

  require Behave
  require Logger

  def start_link(modules_to_register) do
    GenServer.start_link(__MODULE__, modules_to_register, name: __MODULE__)
  end

  def init(modules_to_register) do
    state = Enum.reduce(modules_to_register, %{}, &register_or_warn/2)

    {:ok, state}
  end

  defp register_or_warn(module, state) do
    case Behave.behaviour_implemented?(module, BehaviourModule) do
      {:error, :not_a_module, ^module} ->
        Logger.warn("Could not register (#{module}) because it is not a Module")

        state

      {:error, :behaviour_not_implemented} ->
        Logger.warn("Could not register (#{module}) because it doesn't implement #{BehaviourModule}")

        state

      :ok ->
        {name, config} = module.registration()

        Map.put(state, name, config)
    end
  end
end

Installation

If available in Hex, the package can be installed by adding behave to your list of dependencies in mix.exs:

def deps do
  [
    {:behave, "~> 0.1.0"}
  ]
end

Documentation

Documentation can be found at https://hexdocs.pm/behave.