Skip to content

module Athena::DependencyInjection #

Robust dependency injection service container framework.


VERSION = "0.4.0"#

Class methods#

.container : ADI::ServiceContainer#

Returns the ADI::ServiceContainer for the current fiber.

View source


add_compiler_pass(pass, type = nil, priority = nil)#

Adds a compiler pass, optionally of a specific type and priority (default 0).

Valid types include:

  • :before_optimization (default)
  • :optimization
  • :before_removing
  • :after_removing
  • :removing


This feature is intended for internal/advanced use and, for now, comes with limited public documentation.

View source

bind(key, value)#

Allows binding a value to a key in order to enable auto registration of that value.

Bindings allow scalar values, or those that could not otherwise be handled via service aliases, to be auto registered. This allows those arguments to be defined once and reused, as opposed to using named arguments to manually specify them for each service.

Bindings can also be declared with a type restriction to allow taking the type restriction of the argument into account. Typed bindings are always checked first as the most specific type is always preferred. If no typed bindings match the argument's type, then the last defined untyped bindings is used.

module ValueInterface; end

@[ADI::Register(_value: 1, name: "value_one")]
@[ADI::Register(_value: 2, name: "value_two")]
@[ADI::Register(_value: 3, name: "value_three")]
record ValueService, value : Int32 do
  include ValueInterface

# Untyped bindings
ADI.bind api_key, ENV["API_KEY"]
ADI.bind config, {id: 12_i64, active: true}
ADI.bind static_value, 123
ADI.bind odd_values, ["@value_one", "@value_three"]
ADI.bind value_arr, [true, true, false]

# Typed bindings
ADI.bind value_arr : Array(Int32), [1, 2, 3]
ADI.bind value_arr : Array(Float64), [1.0, 2.0, 3.0]

@[ADI::Register(public: true)]
record BindingClient,
  api_key : String,
  config : NamedTuple(id: Int64, active: Bool),
  static_value : Int32,
  odd_values : Array(ValueInterface)

@[ADI::Register(public: true)]
record IntArr, value_arr : Array(Int32)

@[ADI::Register(public: true)]
record FloatArr, value_arr : Array(Float64)

@[ADI::Register(public: true)]
record BoolArr, value_arr : Array(Bool)

ADI.container.binding_client # =>
# BindingClient(
#  @api_key="123ABC",
#  @config={id: 12, active: true},
#  @static_value=123,
#  @odd_values=[ValueService(@value=1), ValueService(@value=3)])

ADI.container.int_arr   # => IntArr(@value_arr=[1, 2, 3])
ADI.container.float_arr # => FloatArr(@value_arr=[1.0, 2.0, 3.0])
ADI.container.bool_arr  # => BoolArr(@value_arr=[true, true, false])
View source


Registers a configuration annotation with the provided name. Defines a configuration record with the provided args, if any, that represents the possible arguments that the annotation accepts. May also be used with a block to add custom methods to the configuration record.

# Defines an annotation without any arguments.
ADI.configuration_annotation Secure

# Defines annotation with a required and optional argument.
# The default value will be used if that key isn't supplied in the annotation.
ADI.configuration_annotation SomeAnn, id : Int32, debug : Bool = true

# A block can be used to define custom methods on the configuration object.
ADI.configuration_annotation CustomAnn, first_name : String, last_name : String do
  def name : String
    "#{@first_name} #{@last_name}"


The logic to actually do the resolution of the annotations must be handled in the owning shard. Athena::DependencyInjection only defines the common logic that each implementation can use. See ADI::AnnotationConfigurations for more information.

View source


Primary entrypoint for configuring ADI::Extension::Schemas.

View source

register_extension(name, schema)#

Registers an extension ADI::Extension::Schema with the provided name.

View source