Spectral.TypeInfo (Spectral v0.9.2)

View Source

Elixir wrapper for the Erlang :spectra_type_info module.

Provides functions for creating and manipulating type information structures that contain types, records, and function specifications.

Type Info Structure

A type_info record (Erlang record from spectra library) has the structure:

{:type_info, types, records, functions}

Where:

  • types - Map of {type_name, arity} tuples to sp_type records
  • records - Map of record names (atoms) to sp_rec records
  • functions - Map of {function_name, arity} tuples to function spec information

Usage

Typically, you'll get a typeinfo structure from a module's `_spectra_type_info/0` function and then query or modify it:

type_info = Person.__spectra_type_info__()

# Find a specific type
case Spectral.TypeInfo.find_type(type_info, :t, 0) do
  {:ok, type} -> IO.inspect(type)
  :error -> IO.puts("Type not found")
end

# Add a new type
new_type_info = Spectral.TypeInfo.add_type(type_info, :custom, 0, custom_type)

Type Keys

Types and functions are indexed by tuples of {name :: atom(), arity :: non_neg_integer()}. Records are indexed by their name (atom).

Summary

Functions

Adds a function specification to the type_info structure.

Adds a record to the type_info structure.

Adds a type to the type_info structure.

Finds a function specification in the type_info structure.

Finds a record in the type_info structure.

Finds a type in the type_info structure.

Returns the endpoint documentation attached to a function via the spectral/1 macro.

Returns the module associated with a type_info structure.

Gets a record from the type_info structure, raising if not found.

Gets a type from the type_info structure, raising if not found.

Creates a new type_info structure for the given module.

Types

function_key()

@type function_key() :: :spectra_type_info.function_key()

type_info()

@type type_info() :: :spectra_type_info.type_info()

type_key()

@type type_key() :: :spectra_type_info.type_key()

Functions

add_function(type_info, name, arity, func_spec)

@spec add_function(type_info(), atom(), arity(), [term()]) :: type_info()

Adds a function specification to the type_info structure.

Parameters

  • type_info - The type_info structure to add to
  • name - The function name (atom)
  • arity - The function arity (non-negative integer)
  • func_spec - The function spec to add (list of sp_function_spec records)

Returns

Updated type_info structure with the function spec added.

Examples

type_info = Spectral.TypeInfo.new(:nomodule, false)
updated = Spectral.TypeInfo.add_function(type_info, :my_func, 2, func_spec)

add_record(type_info, name, record)

@spec add_record(type_info(), atom(), term()) :: type_info()

Adds a record to the type_info structure.

Parameters

  • type_info - The type_info structure to add to
  • name - The record name (atom)
  • record - The sp_rec record to add

Returns

Updated type_info structure with the record added.

Examples

type_info = Spectral.TypeInfo.new(:nomodule, false)
updated = Spectral.TypeInfo.add_record(type_info, :my_record, some_record)

add_type(type_info, name, arity, type)

@spec add_type(type_info(), atom(), arity(), term()) :: type_info()

Adds a type to the type_info structure.

Parameters

  • type_info - The type_info structure to add to
  • name - The type name (atom)
  • arity - The type arity (non-negative integer)
  • type - The sp_type record to add

Returns

Updated type_info structure with the type added.

Examples

iex> type_info = Person.__spectra_type_info__()
iex> {:ok, person_type} = Spectral.TypeInfo.find_type(type_info, :t, 0)
iex> new_info = Spectral.TypeInfo.new(:nomodule, false)
iex> updated = Spectral.TypeInfo.add_type(new_info, :my_type, 0, person_type)
iex> {:ok, _type} = Spectral.TypeInfo.find_type(updated, :my_type, 0)
iex> :ok
:ok

find_function(type_info, name, arity)

@spec find_function(type_info(), atom(), arity()) :: {:ok, [term()]} | :error

Finds a function specification in the type_info structure.

Parameters

  • type_info - The type_info structure to search
  • name - The function name (atom)
  • arity - The function arity (non-negative integer)

Returns

  • {:ok, func_spec} - If the function spec is found (list of sp_function_spec records)
  • :error - If the function spec is not found

Examples

iex> type_info = Spectral.TypeInfo.new(:nomodule, false)
iex> Spectral.TypeInfo.find_function(type_info, :my_func, 2)
:error

find_record(type_info, name)

@spec find_record(type_info(), atom()) :: {:ok, term()} | :error

Finds a record in the type_info structure.

Parameters

  • type_info - The type_info structure to search
  • name - The record name (atom)

Returns

  • {:ok, record} - If the record is found
  • :error - If the record is not found

Examples

iex> type_info = Spectral.TypeInfo.new(:nomodule, false)
iex> Spectral.TypeInfo.find_record(type_info, :person)
:error

find_type(type_info, name, arity)

@spec find_type(type_info(), atom(), arity()) :: {:ok, term()} | :error

Finds a type in the type_info structure.

Parameters

  • type_info - The type_info structure to search
  • name - The type name (atom)
  • arity - The type arity (non-negative integer)

Returns

  • {:ok, type} - If the type is found
  • :error - If the type is not found

Examples

iex> type_info = Person.__spectra_type_info__()
iex> {:ok, type} = Spectral.TypeInfo.find_type(type_info, :t, 0)
iex> is_tuple(type)
true

iex> type_info = Spectral.TypeInfo.new(:nomodule, false)
iex> Spectral.TypeInfo.find_type(type_info, :nonexistent, 0)
:error

get_function_doc(type_info, name, arity)

@spec get_function_doc(type_info(), atom(), arity()) ::
  {:ok, map()} | {:error, :no_doc_found | :function_not_found}

Returns the endpoint documentation attached to a function via the spectral/1 macro.

When spectral/1 is placed before a @spec and function definition, the documentation map (with keys like :summary, :description, :deprecated) is stored in the function spec's metadata. This function retrieves it, using the first function spec when there are multiple specs (e.g., multiple clauses with different guards).

Parameters

  • type_info - The type_info structure to search
  • name - The function name (atom)
  • arity - The function arity (non-negative integer)

Returns

  • {:ok, doc} - If a doc was attached to the function (map with endpoint doc fields)
  • {:error, :no_doc_found} - If the function exists but has no spectral/1 annotation
  • {:error, :function_not_found} - If the function is not found in the type info

Example

type_info = MyController.__spectra_type_info__()
{:ok, doc} = Spectral.TypeInfo.get_function_doc(type_info, :show, 2)
# doc => %{summary: "Show resource", description: "Returns a resource by ID"}

get_module(type_info)

@spec get_module(type_info()) :: module()

Returns the module associated with a type_info structure.

Examples

iex> type_info = Person.__spectra_type_info__()
iex> Spectral.TypeInfo.get_module(type_info)
Person

get_record(type_info, name)

@spec get_record(type_info(), atom()) :: term()

Gets a record from the type_info structure, raising if not found.

Parameters

  • type_info - The type_info structure to search
  • name - The record name (atom)

Returns

The sp_rec record.

Raises

  • ErlangError with {:record_not_found, name} if the record doesn't exist

Examples

type_info = Person.__spectra_type_info__()
record = Spectral.TypeInfo.get_record(type_info, :person)

get_type(type_info, name, arity)

@spec get_type(type_info(), atom(), arity()) :: term()

Gets a type from the type_info structure, raising if not found.

Parameters

  • type_info - The type_info structure to search
  • name - The type name (atom)
  • arity - The type arity (non-negative integer)

Returns

The sp_type record.

Raises

  • ErlangError with {:type_not_found, name, arity} if the type doesn't exist

Examples

iex> type_info = Person.__spectra_type_info__()
iex> type = Spectral.TypeInfo.get_type(type_info, :t, 0)
iex> is_tuple(type)
true

new(module, implements_codec)

@spec new(module(), boolean()) :: type_info()

Creates a new type_info structure for the given module.

Pass implements_codec: true when the module implements Spectral.Codec. In practice you rarely need to call this directly — type info is normally obtained via Module.__spectra_type_info__/0.

Examples

iex> type_info = Spectral.TypeInfo.new(Person, false)
iex> Spectral.TypeInfo.get_module(type_info)
Person

sp_function_spec(args \\ [])

(macro)

sp_function_spec(record, args)

(macro)