Metastatic.Semantic.Callbacks.BeamIntrospector (Metastatic v0.22.2)

View Source

Discovers behaviour callbacks from compiled BEAM modules.

Uses behaviour_info(:callbacks) at runtime to extract the list of callback functions defined by a behaviour module. This works for all OTP behaviours and any Elixir/Erlang module that defines @callback attributes, as long as the module is compiled and loaded.

This module is used exclusively by the Elixir and Erlang adapters.

Examples

iex> {:ok, callbacks} = BeamIntrospector.discover_callbacks(GenServer)
iex> {:handle_call, 3} in callbacks
true

iex> BeamIntrospector.discover_callbacks(NonExistentModule)
{:error, :not_loaded}

Summary

Types

A callback definition: {function_name, arity}

Functions

Discovers callbacks for a module and registers them in the Semantic.Callbacks registry.

Discovers all callbacks defined by a behaviour module.

Registers all known OTP behaviours from the Erlang/OTP and Elixir standard library.

Types

callback_def()

@type callback_def() :: {atom(), non_neg_integer()}

A callback definition: {function_name, arity}

register_opts()

@type register_opts() :: [
  language: :elixir | :erlang,
  framework: atom(),
  domain: atom() | nil
]

Options for discover_and_register/2

Functions

discover_and_register(module, opts)

@spec discover_and_register(module(), register_opts()) ::
  {:ok, non_neg_integer()} | {:error, atom()}

Discovers callbacks for a module and registers them in the Semantic.Callbacks registry.

Accepts a module atom and options specifying language, framework name, and optional domain. Both Elixir module names (GenServer) and bare Erlang module atoms (:gen_statem) are supported.

Options

  • :language - :elixir or :erlang (required)
  • :framework - framework atom for the callback spec (required)
  • :domain - domain atom or nil (default: nil)

Returns {:ok, count} with the number of callbacks registered, or an error tuple if the module could not be introspected.

Examples

iex> {:ok, count} = BeamIntrospector.discover_and_register(GenServer, language: :elixir, framework: :genserver)
iex> count >= 7
true

discover_callbacks(module)

@spec discover_callbacks(module()) :: {:ok, [callback_def()]} | {:error, atom()}

Discovers all callbacks defined by a behaviour module.

Calls module.behaviour_info(:callbacks) to retrieve the list of {function_name, arity} pairs. Returns {:error, :not_loaded} if the module is not available, or {:error, :not_a_behaviour} if it does not export behaviour_info/1.

Examples

iex> {:ok, callbacks} = BeamIntrospector.discover_callbacks(GenServer)
iex> {:init, 1} in callbacks
true

iex> BeamIntrospector.discover_callbacks(String)
{:error, :not_a_behaviour}

register_otp_behaviours()

@spec register_otp_behaviours() :: :ok

Registers all known OTP behaviours from the Erlang/OTP and Elixir standard library.

Discovers callbacks at runtime rather than hardcoding them, ensuring the registry stays in sync with the installed OTP/Elixir version.

Modules that are not available (e.g., optional applications) are silently skipped.