ArchTest.Collector (ArchTest v0.2.0)

Copy Markdown View Source

Builds a module dependency graph using OTP's :xref tool.

The graph is a map of %{caller_module => [callee_module]} derived from BEAM files. Results are cached in :persistent_term for the duration of the test run.

No external dependencies are required — :xref and :beam_lib are standard OTP applications.

Summary

Functions

Returns all modules known in the graph.

Returns the dependency graph for the given OTP application (or all loaded modules if app is :all).

Builds a dependency graph from a specific BEAM directory path.

Returns all dependency cycles found in the given modules.

Returns the direct dependencies of module (modules it calls).

Returns all modules that directly depend on module (callers of it).

Computes transitive dependencies of module up to max_depth hops (default: unlimited).

Types

graph()

@type graph() :: %{required(module()) => [module()]}

Functions

all_modules(graph)

@spec all_modules(graph()) :: [module()]

Returns all modules known in the graph.

build_graph(app \\ :all, opts \\ [])

@spec build_graph(
  atom() | :all,
  keyword()
) :: graph()

Returns the dependency graph for the given OTP application (or all loaded modules if app is :all).

The graph is cached in :persistent_term after the first call. Pass force: true to bypass the cache and rebuild.

Options

  • :app — OTP app atom or :all (default :all)
  • :force — boolean, bypass cache (default false)

build_graph_from_path(ebin_path, opts \\ [])

@spec build_graph_from_path(
  String.t(),
  keyword()
) :: graph()

Builds a dependency graph from a specific BEAM directory path.

Useful for testing against a pre-compiled application without registering it as an OTP application.

Options

  • :force — boolean, bypass cache (default false)

Example

ebin = "test/support/fixture_app/_build/dev/lib/fixture_app/ebin"
graph = ArchTest.Collector.build_graph_from_path(ebin)

cycles(graph)

@spec cycles(graph()) :: [[module()]]

Returns all dependency cycles found in the given modules.

Each cycle is a list of modules forming a circular dependency chain.

dependencies_of(graph, module)

@spec dependencies_of(graph(), module()) :: [module()]

Returns the direct dependencies of module (modules it calls).

dependents_of(graph, target)

@spec dependents_of(graph(), module()) :: [module()]

Returns all modules that directly depend on module (callers of it).

transitive_dependencies_of(graph, module, max_depth \\ :infinity)

@spec transitive_dependencies_of(graph(), module(), pos_integer() | :infinity) :: [
  module()
]

Computes transitive dependencies of module up to max_depth hops (default: unlimited).