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.
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, %{}, ®ister_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
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 can be found at https://hexdocs.pm/behave.