Runtime introspection of guardedstruct DSL state.
Built on Spark.InfoGenerator, which auto-generates accessors for every
section option in the DSL (e.g. guardedstruct_enforce!/1,
guardedstruct_json!/1). On top of those, this module exposes ergonomic
helpers so callers don't have to walk __fields__/0 maps themselves.
Helper categories
- Field-level lookups —
field_kind/2,field_default/2,field_derives/2,field_validator/2,field_auto/2,enforce?/2,virtual?/2,dynamic?/2 - Collections by kind —
sub_fields/1,virtual_fields/1,dynamic_fields/1,conditional_fields/1,conditional_keys/1,pattern_keyed?/1 - Section-option shorthands —
enforce?/1,opaque?/1,authorized_fields?/1,json?/1,error?/1 - Navigation —
sub_module/2,conditional_children/2
Example
defmodule MyApp.User do
use GuardedStruct
guardedstruct enforce: true do
field :name, String.t()
virtual_field :password_confirm, String.t()
sub_field :address, struct() do
field :city, String.t()
end
end
end
GuardedStruct.Info.fields(MyApp.User) #=> [:name, :password_confirm, :address]
GuardedStruct.Info.virtual_fields(MyApp.User) #=> [:password_confirm]
GuardedStruct.Info.sub_fields(MyApp.User) #=> [:address]
GuardedStruct.Info.field_kind(MyApp.User, :name) #=> :field
GuardedStruct.Info.enforce?(MyApp.User, :name) #=> true
GuardedStruct.Info.sub_module(MyApp.User, :address) #=> MyApp.User.Address
Summary
Functions
True if the section was declared with authorized_fields: true.
Return the children variants of a conditional_field, or nil if the
name isn't a conditional. Each child is a meta map with :kind,
:name, and any associated options.
Names of all conditional_field entries on this module.
Names of conditionalfield entries, sourced from `_information/0's:conditional_keys(matchesconditional_fields/1` for normal modules).
Return the FULL introspection map for a module: every section option, every field's complete metadata, every derived flag, in one structure.
True if name is a dynamic_field.
Names of all dynamic_field entries on this module.
True if the section was declared with enforce: true.
True if the field is enforced (member of enforce_keys/0).
Return the list of enforced field names.
True if the section was declared with error: true.
Return the field metadata for a single name, or nil if absent.
True if the field exists on this module (or any sub_field cascade).
Return the {Mod, fun} auto: MFA, or nil if none.
Return the field's default:, or nil if none or field absent.
Return the original derive string for a field (the canonical
derives: option, falling back to the legacy derive:).
Return the kind of a field: :field, :sub_field, :virtual_field,
:dynamic_field, :conditional_field, or :pattern_field. nil if
the field doesn't exist.
Return the {Mod, fun} per-field validator MFA, or nil if none.
Return the user-declared field, sub_field, virtual_field, dynamic_field and conditional_field names in declaration order. Works on both the top-level module and any generated sub_field submodule.
Return the runtime field metadata — same shape as the generated module's
__fields__/0.
guardedstruct DSL entities
Only effective inside the GuardedStruct.AshResource extension. When true, injects GuardedStruct.AshResource.Change into the resource's top-level changes section so every :create and :update action automatically runs the GuardedStruct pipeline. Equivalent to writing changes do change GuardedStruct.AshResource.Change end by hand. No-op outside the Ash extension.
Only effective inside the GuardedStruct.AshResource extension. When true, injects GuardedStruct.AshResource.Change into the resource's top-level changes section so every :create and :update action automatically runs the GuardedStruct pipeline. Equivalent to writing changes do change GuardedStruct.AshResource.Change end by hand. No-op outside the Ash extension.
When true, derives a JSON encoder. Uses Jason.Encoder if :jason is in the user's deps; otherwise falls back to the built-in JSON.Encoder on Elixir 1.18+. No-op if neither is available.
When true, derives a JSON encoder. Uses Jason.Encoder if :jason is in the user's deps; otherwise falls back to the built-in JSON.Encoder on Elixir 1.18+. No-op if neither is available.
guardedstruct DSL options
True if the section was declared with json: true.
True if the section was declared with opaque: true.
True if this module was generated for a pattern-keyed map (its only
field was a regex). Pattern-keyed modules return a map from builder/1,
not a struct.
Names of all sub_field entries on this module.
Return the generated submodule for a sub_field, or nil if the name
isn't a sub_field. The submodule path is the parent module concatenated
with the camelized field name (or with the section's module: override).
True if name is a virtual_field.
Names of all virtual_field entries on this module.
Functions
True if the section was declared with authorized_fields: true.
Return the children variants of a conditional_field, or nil if the
name isn't a conditional. Each child is a meta map with :kind,
:name, and any associated options.
Names of all conditional_field entries on this module.
Names of conditionalfield entries, sourced from `_information/0's:conditional_keys(matchesconditional_fields/1` for normal modules).
Return the FULL introspection map for a module: every section option, every field's complete metadata, every derived flag, in one structure.
Works on both the top-level module and any generated sub_field submodule.
Section-option keys whose values were not declared are present as nil,
so the shape is uniform.
Returned map keys
:module— the module:path— module path from root (empty list for the top-level):key— the field name corresponding to this module (or:root):shape—:structor:pattern_map:pattern_keyed?— convenience boolean:patterns— for pattern-map shapes, the list of regex field names:keys— struct-bound key names (excludes virtuals):enforce_keys— names of enforced keys:conditional_keys— names of conditional_field entries:options— map of every section option (withnilfor absent values):fields— list of per-field meta maps (one per declared entity), each augmented with:enforce?(membership in enforce_keys) and, for sub_field entries,:sub_module(the generated submodule)
Example
Info.describe(MyApp.User)
#=> %{
# module: MyApp.User,
# path: [],
# key: :root,
# shape: :struct,
# pattern_keyed?: false,
# patterns: [],
# keys: [:id, :name, :address, ...],
# enforce_keys: [:name, :address],
# conditional_keys: [:billing],
# options: %{
# enforce: true, opaque: false, module: nil, error: false,
# authorized_fields: true, main_validator: nil,
# validate_derive: nil, sanitize_derive: nil, json: true
# },
# fields: [
# %{name: :id, kind: :field, enforce?: false, ...},
# %{name: :address, kind: :sub_field, enforce?: true,
# sub_module: MyApp.User.Address, ...},
# ...
# ]
# }
True if name is a dynamic_field.
Names of all dynamic_field entries on this module.
True if the section was declared with enforce: true.
True if the field is enforced (member of enforce_keys/0).
Return the list of enforced field names.
True if the section was declared with error: true.
Return the field metadata for a single name, or nil if absent.
True if the field exists on this module (or any sub_field cascade).
Return the {Mod, fun} auto: MFA, or nil if none.
Return the field's default:, or nil if none or field absent.
Return the original derive string for a field (the canonical
derives: option, falling back to the legacy derive:).
Return the kind of a field: :field, :sub_field, :virtual_field,
:dynamic_field, :conditional_field, or :pattern_field. nil if
the field doesn't exist.
Return the {Mod, fun} per-field validator MFA, or nil if none.
Return the user-declared field, sub_field, virtual_field, dynamic_field and conditional_field names in declaration order. Works on both the top-level module and any generated sub_field submodule.
Return the runtime field metadata — same shape as the generated module's
__fields__/0.
guardedstruct DSL entities
Only effective inside the GuardedStruct.AshResource extension. When true, injects GuardedStruct.AshResource.Change into the resource's top-level changes section so every :create and :update action automatically runs the GuardedStruct pipeline. Equivalent to writing changes do change GuardedStruct.AshResource.Change end by hand. No-op outside the Ash extension.
Only effective inside the GuardedStruct.AshResource extension. When true, injects GuardedStruct.AshResource.Change into the resource's top-level changes section so every :create and :update action automatically runs the GuardedStruct pipeline. Equivalent to writing changes do change GuardedStruct.AshResource.Change end by hand. No-op outside the Ash extension.
When true, derives a JSON encoder. Uses Jason.Encoder if :jason is in the user's deps; otherwise falls back to the built-in JSON.Encoder on Elixir 1.18+. No-op if neither is available.
When true, derives a JSON encoder. Uses Jason.Encoder if :jason is in the user's deps; otherwise falls back to the built-in JSON.Encoder on Elixir 1.18+. No-op if neither is available.
guardedstruct DSL options
Returns a map containing the and any configured or default values.
True if the section was declared with json: true.
True if the section was declared with opaque: true.
True if this module was generated for a pattern-keyed map (its only
field was a regex). Pattern-keyed modules return a map from builder/1,
not a struct.
Names of all sub_field entries on this module.
Return the generated submodule for a sub_field, or nil if the name
isn't a sub_field. The submodule path is the parent module concatenated
with the camelized field name (or with the section's module: override).
Info.sub_module(MyApp.User, :address)
#=> MyApp.User.Address
True if name is a virtual_field.
Names of all virtual_field entries on this module.