module Di
Defined in:
di.crdi/errors.cr
di/provider.cr
di/registry.cr
di/scope.cr
di/version.cr
Constant Summary
-
VERSION =
{{ (`shards version`).chomp.stringify }} -
Full version string from shard.yml
-
VERSION_MAJOR =
0 -
VERSION_MINOR =
1 -
VERSION_PATCH =
2 -
VERSION_STATE =
nil
Class Method Summary
-
.get_all_providers(interface_type : String) : Array(Provider::Base)
Get all providers for an interface type from the current scope chain.
-
.get_provider(key : String) : Provider::Base
Get a provider from the current scope chain (or root registry).
-
.get_provider?(key : String) : Provider::Base | Nil
Get a provider from the current scope chain, returning nil if not found.
-
.healthy?(scope_name : Symbol) : Hash(String, Bool)
Check health of all resolved singletons in a named scope.
-
.healthy? : Hash(String, Bool)
Check health of all resolved singletons in the root registry.
-
.push_resolution(type_name : String, &)
Track resolution chain to detect circular dependencies at runtime.
-
.register_interface_provider(interface_type : String, impl_type : String, provider : Provider::Base) : Nil
Register an interface binding (multiple impls allowed under same interface type).
-
.register_named_interface(named_key : String, interface_type : String, impl_type : String, provider : Provider::Base) : Nil
Register a named interface binding atomically (named key + interface index).
-
.register_provider(key : String, provider : Provider::Base) : Nil
Register a provider in the current scope (or root registry).
-
.reset! : Nil
Clear all providers and scopes (test helper).
-
.scope(name : Symbol, &)
Create a named scope with parent inheritance.
-
.shutdown! : Nil
Shut down all singleton providers in reverse registration order.
Macro Summary
-
[](type, name = nil)
Resolve a service by type.
-
[]?(type, name = nil)
Resolve a service by type, returning nil if not registered.
-
invoke(type, name = nil)
Resolve a service by type.
-
invoke?(type, name = nil)
Resolve a service by type, returning nil if not registered.
-
provide(*deps, as _name = nil, transient _transient = false, &block)
Register a service provider.
Class Method Detail
Get all providers for an interface type from the current scope chain.
Get a provider from the current scope chain (or root registry). For interface types with multiple implementations, raises AmbiguousServiceError.
Get a provider from the current scope chain, returning nil if not found.
Check health of all resolved singletons in a named scope.
Includes inherited services from parent scopes.
Raises Di::ScopeNotFound if the scope is not active in the current fiber.
Check health of all resolved singletons in the root registry.
Returns a hash mapping provider keys to health status.
Only includes services that respond to .healthy? and have been resolved.
Track resolution chain to detect circular dependencies at runtime. Yields to block. Raises CircularDependency if type is already in chain.
Register an interface binding (multiple impls allowed under same interface type).
Register a named interface binding atomically (named key + interface index). Rolls back the named key if interface registration fails.
Register a provider in the current scope (or root registry). Sets the provider key for cycle detection before storing.
Clear all providers and scopes (test helper).
Resets the container to a clean state. Primarily for use in specs.
Raises Di::ScopeError if any scope is active in any fiber.
Create a named scope with parent inheritance.
Providers registered inside the block are scoped. The scope inherits all providers from the parent (or root if at top level). On block exit, shutdown is called on all scope-local singleton providers.
Example:
Di.scope(:request) do
Di.provide { CurrentUser.from_token(token) }
user = Di[CurrentUser]
end
Shut down all singleton providers in reverse registration order.
Calls .shutdown on services that respond to it. Transient services
and services without .shutdown are skipped.
Raises Di::ScopeError if any scope is active in any fiber.
Macro Detail
Resolve a service by type.
Returns the instance as exactly T — fully typed, no casting.
Singleton providers return the cached instance; transient providers
create a new instance on every call.
Example:
db = Di[Database]
primary = Di[Database, :primary]
Raises Di::ServiceNotFound if the type is not registered.
Resolve a service by type, returning nil if not registered.
Returns T? — the instance or nil. Does not raise.
Example:
db = Di[Database]?
replica = Di[Database, :replica]?
Resolve a service by type.
Deprecated: Use Di[Type] instead. This alias exists for backward
compatibility but the bracket syntax is preferred for idiomatic Crystal.
Example:
db = Di.invoke(Database) # deprecated
db = Di[Database] # preferred
primary = Di.invoke(Database, :primary) # deprecated
primary = Di[Database, :primary] # preferred
Raises Di::ServiceNotFound if the type is not registered.
Resolve a service by type, returning nil if not registered.
Deprecated: Use Di[Type]? instead. This alias exists for backward
compatibility but the bracket syntax is preferred for idiomatic Crystal.
Example:
db = Di.invoke?(Database) # deprecated
db = Di[Database]? # preferred
Register a service provider.
No block (auto-wire):
Di.provide UserServiceDi.provide UserService, as: :primary
Interface binding (2 types, no block):
Di.provide Printable, Square# register Square under Printable keyDi.provide Printable, Square, as: :primary
Block forms:
Di.provide { Database.new(url) }Di.provide(A) { |a| B.new(a) }Di.provide(A, B) { |a, b| C.new(a, b) }Di.provide({Database, :primary}) { |db| Repo.new(db) }
With dependency types, each is resolved and passed to block arguments in order. This works at top-level without macro-order issues.