### Quick Start Example Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Demonstrates how to set up a dependency container, create an auto-injection factory, and use it in a class for automatic dependency injection. ```ruby container = { database: Database.new, logger: Logger.new(STDOUT) } AutoInject = Dry.AutoInject(container) class UserRepository include AutoInject[:database, :logger] def find(id) logger.info("Finding user #{id}") database.query("SELECT * FROM users WHERE id = ?", id) end end repo = UserRepository.new ``` -------------------------------- ### Minimal Example Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Demonstrates the most basic setup for dry-auto_inject by creating a container, an injector, and using it within a class. Dependencies are automatically set as instance variables. ```ruby 1. Create a container container = { database: "postgresql://localhost", logger: Logger.new(STDOUT) } 2. Create the injector AutoInject = Dry.AutoInject(container) 3. Use in a class class UserService include AutoInject[:database, :logger] def find_user(id) logger.info("Finding user #{id}") # @database and @logger are automatically set end end 4. Instantiate service = UserService.new ``` -------------------------------- ### Setup with Dependency Definition Helper Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Illustrates a custom setup using a helper method to manage the container and injector. This pattern is useful for encapsulating application configuration. ```ruby module MyApp def self.setup @container = { database: Database.new, logger: Logger.new(STDOUT), cache: RedisCache.new } end def self.Inject(*keys) raise "App not configured" unless @container Dry.AutoInject(@container)[*keys] end end # Usage: MyApp.setup class UserService include MyApp.Inject(:database, :logger) end ``` -------------------------------- ### Service Class with Dependency Injection Example Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/types.md Provides a complete example of a `UserService` inheriting from `BaseService`, including dependencies via `AutoInject`, and demonstrating their usage. ```ruby class BaseService def setup_logging logger.info("Service initialized") end end class UserService < BaseService # Include injection module in subclass include AutoInject[:database, :logger] def initialize(database:, logger:) @database = database @logger = logger super() end def find_user(id) @database.query("SELECT * FROM users WHERE id = ?", id) end end # Usage: service = UserService.new service.database # => database from container service.logger # => logger from container ``` -------------------------------- ### Hash-based Container Setup Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Demonstrates setting up a simple hash as a dependency container for Dry::AutoInject. ```ruby container = { database: DatabaseConnection.new, logger: Logger.new(STDOUT), cache: RedisCache.new } AutoInject = Dry.AutoInject(container) ``` -------------------------------- ### DependencyMap Creation Examples Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/types.md Illustrates how DependencyMap instances are created internally by the AutoInject API. These examples show different ways to specify dependencies. ```ruby # These internally create DependencyMap instances: include AutoInject[:database, :logger] include AutoInject.args[:database, logger: "log_service"] include AutoInject.hash[:database, cache: "redis"] ``` -------------------------------- ### Custom Container Setup Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Illustrates creating a custom class to act as a dependency container for Dry::AutoInject. ```ruby class MyContainer def initialize @services = {} end def register(key, value) @services[key] = value end def [](key) @services[key] end end container = MyContainer.new container.register(:database, Database.new) container.register(:logger, Logger.new) AutoInject = Dry.AutoInject(container) ``` -------------------------------- ### Dry::Container Setup Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Shows how to use Dry::Container to register dependencies for Dry::AutoInject. ```ruby require 'dry/container' container = Dry::Container.new container.register(:database) { DatabaseConnection.new } container.register(:logger) { Logger.new(STDOUT) } container.register(:cache) { RedisCache.new } AutoInject = Dry.AutoInject(container) ``` -------------------------------- ### Dependency Resolution Examples Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Illustrates how to specify and resolve dependencies, including simple dependencies, aliased dependencies, and multiple dependencies with aliases. ```ruby # Simple dependency include AutoInject[:database] # => Fetches container[:database] automatically # Aliased dependency include AutoInject[db: "services.database"] # => Fetches container["services.database"] and assigns to @db # Multiple dependencies include AutoInject[:database, :logger, cache: "redis"] ``` -------------------------------- ### Example: Using Injector to Define Dependencies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/injector.md Demonstrates how to create an injector, select a strategy (kwargs), and define dependencies for a class. The specified dependencies will be automatically injected. ```ruby AutoInject = Dry.AutoInject({ database: Database.new, logger: Logger.new(STDOUT) }) # Get the kwargs strategy injector kwargs_injector = AutoInject.kwargs # Get an injection module for specific dependencies UserRepositoryInjection = kwargs_injector[:database, :logger] # Include it in a class class UserRepository include UserRepositoryInjection def find(id) # @database and @logger are automatically available end end ``` -------------------------------- ### Kwargs Strategy Example Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/strategies.md Injects dependencies as keyword arguments to the initializer. Dependencies are automatically fetched from the container if not provided. Useful for flexible initializers. ```ruby container = { database: Database.new, logger: Logger.new, cache: RedisCache.new } AutoInject = Dry.AutoInject(container) class UserService include AutoInject.kwargs[:database, :logger] def initialize(database:, logger:, cache: nil) @database = database @logger = logger @cache = cache end end service = UserService.new # @database and @logger are automatically injected # @cache remains nil (not in injected dependencies) service2 = UserService.new(logger: CustomLogger.new) # @logger is overridden with CustomLogger.new ``` -------------------------------- ### Basic Setup with Dry::Container Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Provides a common pattern for setting up a Ruby application with dry-auto_inject, including registering dependencies in a Dry::Container and creating a shared injection factory. ```ruby module MyApp require 'dry/container' container = Dry::Container.new # Register dependencies container.register(:database) { Database.new } container.register(:logger) { Logger.new(STDOUT) } container.register(:cache) { RedisCache.new } # Create injection factory AutoInject = Dry.AutoInject(container) # Helper method def self.Inject(*keys) AutoInject[*keys] end end ``` -------------------------------- ### Hash Strategy Example Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/strategies.md Injects dependencies as values within a single options hash passed to the initializer. User-provided options take precedence over container dependencies. ```ruby container = { database: Database.new, logger: Logger.new, cache: RedisCache.new } AutoInject = Dry.AutoInject(container) class UserService include AutoInject.hash[:database, :logger] def initialize(options = {}) @database = options[:database] @logger = options[:logger] @cache = options[:cache] end end # Called with no arguments service = UserService.new # options = { database: , logger: } # Called with custom options service = UserService.new( logger: CustomLogger.new, cache: RedisCache.new ) # options = { database: , logger: , cache: } ``` -------------------------------- ### Initialize DependencyMap with Simple Dependencies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/dependency_map.md Create a DependencyMap with basic dependencies where the local name matches the container key. This is useful for straightforward dependency injection setups. ```ruby map = DependencyMap.new(:database, :logger) # Creates mapping: { database: :database, logger: :logger } ``` -------------------------------- ### Args Strategy Example Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/strategies.md Injects dependencies as positional arguments at the beginning of the initializer's argument list. Useful for classes with traditional positional parameters. ```ruby container = { database: Database.new, logger: Logger.new, cache: RedisCache.new } AutoInject = Dry.AutoInject(container) class UserRepository include AutoInject.args[:database, :logger] def initialize(database, logger, options = {}) @database = database @logger = logger @options = options end end # Called with no arguments - both dependencies injected repo = UserRepository.new # @database and @logger are injected from container # Override the first dependency repo = UserRepository.new(CustomDatabase.new) # @database is CustomDatabase, @logger is from container # Override both and pass additional options repo = UserRepository.new(CustomDB.new, CustomLogger.new, { timeout: 30 }) ``` -------------------------------- ### Example of Args-Based Injection with Correct Arguments Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md This snippet demonstrates a successful use of `AutoInject.args` where the correct number of positional arguments are provided to the constructor. ```ruby AutoInject = Dry.AutoInject({ database: Database.new, logger: Logger.new }) class UserService include AutoInject.args[:database, :logger] def initialize(database, logger) @database = database @logger = logger end end # This works - exactly the right number of args service = UserService.new ``` -------------------------------- ### Attribute Access Example Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Shows how injected dependencies are made available as readable instance attributes, accessible via method calls or directly as instance variables. ```ruby class Service include AutoInject[:database, :logger] def work database # Access via method call (attr_reader) @database # Access via instance variable end end ``` -------------------------------- ### DependencyMap Internal Structure Example Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/types.md Shows the internal hash and names array returned by DependencyMap.to_h and DependencyMap.names, based on a given AutoInject definition. ```ruby # When you write: include AutoInject[ :database, log: :logger, cache: "services.cache" ] # The internal DependencyMap.to_h returns: { database: :database, log: :logger, cache: "services.cache" } # And DependencyMap.names returns: [:database, :log, :cache] ``` -------------------------------- ### Example: Dependency Aliasing with Injector Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/injector.md Shows how to use dependency aliasing by mapping a container key (e.g., "data_store") to a different local variable name (e.g., database) within a class. ```ruby class UserService # Map container key "data_store" to local variable "database" include AutoInject.kwargs[:logger, database: "data_store"] def initialize(logger:, database:) @logger = logger @database = database end end ``` -------------------------------- ### Restrict Available Injection Strategies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Shows how to create a limited strategy container to control which injection strategies are available. This example restricts the available strategies to `:kwargs` and `:args`, disabling the `:hash` strategy. ```ruby # Only allow kwargs and args strategies, disable hash LimitedStrategies = Dry::Core::Container.new LimitedStrategies.register(:kwargs, proc { Dry::AutoInject::Strategies::Kwargs }) LimitedStrategies.register(:args, proc { Dry::AutoInject::Strategies::Args }) LimitedStrategies.register(:default, proc { Dry::AutoInject::Strategies::Kwargs }) AutoInject = Dry.AutoInject(container, strategies: LimitedStrategies) # This works: class Service1 include AutoInject[:database] # Uses default (kwargs) end # This also works: class Service2 include AutoInject.args[:database] end # This raises NoMethodError - hash strategy not available: # class Service3 # include AutoInject.hash[:database] # end ``` -------------------------------- ### Validating Container Setup with Dry.AutoInject Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Provides a method to validate that all required dependencies are present in the container before creating an injector, raising an error if any are missing. ```ruby module AppSetup REQUIRED_DEPENDENCIES = [:database, :logger, :cache].freeze def self.create_injector(container) missing = REQUIRED_DEPENDENCIES.reject { |key| container.key?(key) } if missing.any? raise "Missing required dependencies: #{missing.join(', ')}" end Dry.AutoInject(container) end end # Usage: begin AutoInject = AppSetup.create_injector(container) rescue => e puts "Configuration error: #{e.message}" exit 1 end ``` -------------------------------- ### Example Triggering DuplicateDependencyError Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md Demonstrates how registering duplicate dependencies with implicit naming raises `DuplicateDependencyError`. Use unique names or explicit aliasing to prevent this. ```ruby AutoInject = Dry.AutoInject({ database: Database.new, data_store: Database.new }) # This raises DuplicateDependencyError because both resolve to "database" name # when using implicit naming begin class Service include AutoInject[:database, data_store: :database] end rescue Dry::AutoInject::DuplicateDependencyError => e puts e.message # => "name +database+ is already used" end ``` -------------------------------- ### Mixed Notation for Dependency Aliasing Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Shows how to mix implicit naming (where the identifier is also the local name) with explicit aliases using a hash. This example maps `:database` implicitly, and uses aliases for `"redis.cache"` and `"elasticsearch.client"`. ```ruby container = { database: DatabaseConnection.new, "redis.cache": RedisConnection.new, "elasticsearch.client": ElasticsearchClient.new } AutoInject = Dry.AutoInject(container) class Service # Mix implicit naming with explicit aliases include AutoInject[ :database, # local: @database, container: :database cache: "redis.cache", # local: @cache, container: "redis.cache" search: "elasticsearch.client" # local: @search, container: "elasticsearch.client" ] end ``` -------------------------------- ### Example Triggering DependencyNameInvalid Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md Demonstrates how invalid Ruby identifiers used as dependency names raise `DependencyNameInvalid`. Ensure dependency names follow Ruby identifier rules or use aliasing. ```ruby AutoInject = Dry.AutoInject({ "InvalidName" => "value", "123invalid" => "value", "invalid-name" => "value" }) # All of these raise DependencyNameInvalid begin DependencyMap.new("InvalidName") # Starts with uppercase rescue Dry::AutoInject::DependencyNameInvalid => e puts e.message # => "name +InvalidName+ is not a valid Ruby identifier" end begin DependencyMap.new("123invalid") # Starts with number rescue Dry::AutoInject::DependencyNameInvalid => e puts e.message # => "name +123invalid+ is not a valid Ruby identifier" end begin DependencyMap.new("invalid-name") # Contains hyphen rescue Dry::AutoInject::DependencyNameInvalid => e puts e.message # => "name +invalid-name+ is not a valid Ruby identifier" end ``` -------------------------------- ### Container Initialization Performance Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Highlights the performance best practice of creating the dependency injection container once at application startup rather than repeatedly. ```ruby # GOOD: Create container once at application startup class Application def initialize @container = build_container @AutoInject = Dry.AutoInject(@container) end def build_container { database: Database.new(ENV['DATABASE_URL']), logger: Logger.new(ENV['LOG_FILE']), cache: Redis.new } end attr_reader :AutoInject end ``` -------------------------------- ### Get Dependency Names Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/dependency_map.md Retrieve an array of symbols representing the local names of the dependencies. This is useful for understanding the structure of injected dependencies. ```ruby map = DependencyMap.new(:database, :logger, cache: "redis") map.names # => [:database, :logger, :cache] ``` -------------------------------- ### Validating Configuration at Startup Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md Illustrates how to validate the container configuration when initializing Dry.AutoInject to catch potential errors early. ```ruby begin AutoInject = Dry.AutoInject(container) rescue => e # Handle container creation errors raise "Failed to initialize AutoInject: #{e.message}" end ``` -------------------------------- ### Include Dependencies with AutoInject Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/INDEX.md Demonstrates how to include dependencies into a class using different AutoInject strategies: default (kwargs), args, and hash. ```ruby class MyClass include AutoInject[:database, :logger] # or include AutoInject.args[:database, :logger] # or include AutoInject.hash[:database, :logger] end ``` -------------------------------- ### Get Dependency Map as Hash Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/dependency_map.md Obtain the internal mapping of dependency names to their container identifiers as a hash. This provides direct access to how dependencies are resolved. ```ruby map = DependencyMap.new(:database, :logger, cache: "redis") map.to_h # => { database: :database, logger: :logger, cache: "redis" } ``` -------------------------------- ### Validate Required Dependencies at Startup Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Ensures that all necessary dependencies are present in the container before application startup. Raises an error listing any missing dependencies. ```ruby module MyApp def self.setup(container) required_deps = [:database, :logger, :cache] missing = required_deps.reject { |key| container.key?(key) } raise "Missing dependencies: #{missing.join(', ')}" if missing.any? @container = container @AutoInject = Dry.AutoInject(container) end end ``` -------------------------------- ### Constructor Initialization Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/strategies.md Initializes a strategy constructor with a container and dependency names. It prepares the dependency map for injection. ```ruby def initialize(container, *dependency_names) end ``` -------------------------------- ### Entry Point: Dry.AutoInject Factory Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Demonstrates creating an auto-injection factory configured for a given container. This factory is the entry point for defining injection strategies. ```ruby Dry.AutoInject(container, options = {}) -> Dry::AutoInject::Builder ``` -------------------------------- ### Inspect Dependency Map Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/dependency_map.md Get a string representation of the dependency map, showing the internal mapping. This is useful for debugging and understanding the map's current state. ```ruby map = DependencyMap.new(:database, :logger) map.inspect # => "{:database=>:database, :logger=>:logger}" ``` -------------------------------- ### Dependency Specification with Aliases Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Illustrates various ways to specify dependencies, including simple names, aliases, and mixing different specification notations. ```ruby # Simple dependencies include AutoInject[:database, :logger] # With aliases include AutoInject[:database, log: :logger, cache: "redis"] # Mixed notation include AutoInject.args[:database, db: "data_store"] ``` -------------------------------- ### Specify Basic Dependencies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Illustrates how to include dependencies by their container identifiers. Dependencies are automatically converted to local attribute names matching the identifier. ```ruby class Service include AutoInject[:database, :logger, :cache] end ``` -------------------------------- ### Registering a Strategy with a Proc Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/types.md Demonstrates how to register a strategy using a Proc, which allows for lazy loading of strategy classes. This is a standard practice for Dry::Core::Container. ```ruby Strategies.register :kwargs, proc { Strategies::Kwargs } ``` -------------------------------- ### Initialize Strategies Container Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/strategies.md This snippet shows how to extend `Core::Container::Mixin` to create the `Strategies` class, which acts as a container for registered injection strategies. ```ruby class Strategies extend Core::Container::Mixin end ``` -------------------------------- ### Module Inclusion for Dependency Injection Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Demonstrates how to include the auto-injection module in a class to automatically inject specified dependencies and wrap the initialize method. ```ruby class MyClass # Adds @database and @logger attributes # Wraps initialize to inject dependencies include AutoInject[:database, :logger] end ``` -------------------------------- ### Hash Strategy: Override Dependencies with Options Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Illustrates overriding dependencies and adding extra options when instantiating a Service using the :hash strategy. ```ruby class Service include AutoInject.hash[:database, :logger] def initialize(options = {}) @database = options[:database] @logger = options[:logger] end end # Use injected dependencies service = Service.new # Override with additional options service = Service.new(logger: CustomLogger.new, extra: 'value') ``` -------------------------------- ### Define and Use Custom Injection Strategy Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Demonstrates how to define a custom injection strategy by extending `Dry::AutoInject::Strategies::Constructor` and then using it with the `Dry.AutoInject` factory. This allows for custom initialization logic within the injected dependencies. ```ruby class CustomStrategy < Dry::AutoInject::Strategies::Constructor private def define_new class_mod.class_exec(container, dependency_map) do |container, dependency_map| define_method :new do |*args, &block| # Custom initialization logic super(*args, &block) end end end def define_initialize(klass) # Custom initialize logic end end # Create a custom strategies container CustomStrategies = Dry::Core::Container.new CustomStrategies.register(:custom, proc { CustomStrategy }) CustomStrategies.register(:default, proc { CustomStrategy }) # Use the custom strategies AutoInject = Dry.AutoInject(container, strategies: CustomStrategies) class MyClass # Uses custom strategy instead of kwargs include AutoInject[:database, :logger] end ``` -------------------------------- ### Initialize DependencyMap with Aliased Dependencies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/dependency_map.md Create a DependencyMap using aliases to map different local names to specific container keys. This is helpful when container keys are not descriptive or need to be disambiguated. ```ruby map = DependencyMap.new(:database, db: "data_store", cache: "redis") # Creates mapping: { database: :database, db: "data_store", cache: "redis" } ``` -------------------------------- ### Verifying Dependencies Before Inclusion Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md Provides a strategy to verify that all required dependency keys exist in the container before including them with AutoInject. ```ruby module MyApp AutoInject = Dry.AutoInject(container) def self.Inject(*keys) # Validate that all keys exist in container keys.each do |key| raise "Missing dependency: #{key}" unless container.key?(key) end AutoInject[*keys] end end ``` -------------------------------- ### Constructor Private Method: Define Initialize Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/strategies.md Private method stub that must be implemented by subclasses to define the `initialize` instance method with injection logic. ```ruby private def define_initialize(klass) raise NotImplementedError end ``` -------------------------------- ### Args Strategy: Override Dependencies by Position Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Shows how to override dependencies by their position when instantiating a Service using the :args strategy. ```ruby class Service include AutoInject.args[:database, :logger] def initialize(database, logger) @database = database @logger = logger end end # Use injected dependencies service = Service.new # Override by position service = Service.new(CustomDB.new) # Override all service = Service.new(CustomDB.new, CustomLogger.new) ``` -------------------------------- ### Minimal Custom Strategies Implementation Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/types.md Provides a minimal custom implementation for AutoInject strategies. It defines how to map strategy names to specific strategy classes and handles unknown strategy requests. ```ruby class CustomStrategies def [](name) case name when :custom MyCustomStrategy when :default MyDefaultStrategy else raise "Unknown strategy: #{name}" end end def key?(name) [:custom, :default].include?(name) end end AutoInject = Dry.AutoInject(container, strategies: CustomStrategies.new) ``` -------------------------------- ### Define Class with Positional Arguments Strategy Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/auto_inject.md Shows how to use the `args` method to include dependencies using the positional arguments injection strategy. Dependencies are available as instance variables. ```ruby class UserService # Use positional arguments strategy include AutoInject.args[:database, :cache] def get_user(id) # Dependencies are available as @database and @cache end end ``` -------------------------------- ### Service with Args Strategy Dependencies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Employs the Args strategy for dependency injection, where dependencies are passed as positional arguments to the initializer. ```ruby class Service include AutoInject.args[:database, :logger] def initialize(database, logger) @database = database @logger = logger end end # Use with defaults service = Service.new # Override by position service = Service.new(CustomDatabase.new) ``` -------------------------------- ### Document and Inject Dependencies into a Class Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Includes the necessary injection modules for specified dependencies (e.g., database, logger) into a class. These dependencies can then be accessed via instance variables. ```ruby class UserService # Injected dependencies: database (DB connection), logger (Logger instance) include MyApp.Inject(:database, :logger) def find(id) # Implementation uses @database and @logger end end ``` -------------------------------- ### Multiple Module Inclusion with AutoInject Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Shows how to include multiple modules and use dry-auto_inject within a class. This pattern allows for composing different functionalities and their required dependencies. ```ruby module Auditable def audit_log(action) logger.info("#{self.class}: #{action}") end end module Cacheable def cached_fetch(key) @cache.fetch(key) { yield } end end class UserService include Auditable include Cacheable include AutoInject[:database, :logger, :cache] def find_user(id) audit_log("find_user(#{id})") cached_fetch("user_#{id}") do @database.query("SELECT * FROM users WHERE id = ?", id) end end end ``` -------------------------------- ### Use Injected Service with Defaults or Overrides Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Instantiate a service with automatically injected dependencies. Dependencies can be overridden using keyword arguments if a different strategy is configured. ```ruby # Dependencies are automatically injected repo = UserRepository.new # Can be overridden if needed (with kwargs strategy) repo = UserRepository.new(logger: CustomLogger.new) ``` -------------------------------- ### Preventing Duplicate Dependency Errors with Aliasing Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md Illustrates the correct way to include dependencies when names might conflict, using aliasing to ensure unique local names. ```ruby include AutoInject[:database, db: "data_store"] # OK - unique names ``` -------------------------------- ### Composition Over Inheritance with AutoInject Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Demonstrates how to use Dry.AutoInject to inject dependencies like connection strings and loggers into a class, promoting composition over inheritance. ```ruby class DatabasePool include AutoInject[:connection_string, :logger] def initialize(connection_string:, logger:) @connection_string = connection_string @logger = logger @pool = [] end def acquire @pool.shift || create_connection end private def create_connection @logger.info("Creating new connection") Database.new(@connection_string) end end class UserRepository include AutoInject[:logger] def initialize(logger:, database_pool:) @logger = logger @database_pool = database_pool end def find(id) db = @database_pool.acquire begin db.query("SELECT * FROM users WHERE id = ?", id) ensure @database_pool.release(db) end end end # Usage: container = { logger: Logger.new, connection_string: "postgresql://...", database_pool: DatabasePool.new(...) } AutoInject = Dry.AutoInject(container) ``` -------------------------------- ### Alias Dependencies with Hash Notation Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Demonstrates mapping container identifiers to different local attribute names using a hash in the final argument. The hash key becomes the local attribute name, and the value is the container identifier. ```ruby class Service include AutoInject[:database, log: :logger, store: "redis.cache"] end ``` -------------------------------- ### Define Class with Default (kwargs) Injection Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/auto_inject.md Demonstrates how to include injected dependencies into a class using the default keyword arguments strategy. Dependencies are automatically assigned as instance variables. ```ruby # Create a simple container container = { database: "postgresql://localhost", cache: "redis://localhost", logger: Logger.new(STDOUT) } # Create the auto-injection factory AutoInject = Dry.AutoInject(container) # Define a class with injected dependencies using the default (kwargs) strategy class UserRepository include AutoInject[:database, :logger] def find(id) logger.info("Finding user #{id}") # database is available as an instance variable @database @database.query("SELECT * FROM users WHERE id = ?", id) end end # The class is instantiated without passing dependencies repo = UserRepository.new ``` -------------------------------- ### Multiple Forms of Dependency Aliasing Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/types.md Demonstrates various valid ways to specify dependency aliases within AutoInject, including symbol-to-symbol, symbol-to-string, and multiple aliases in a single call. ```ruby # All of these work: include AutoInject[:dep1, dep2: :dep2_in_container] include AutoInject[:dep1, dep2: "namespaced.dep2"] include AutoInject[alias_a: "container.a", alias_b: "container.b"] ``` -------------------------------- ### Handling ArgumentError in Initialization Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md Demonstrates how to catch and handle ArgumentErrors that occur when too many arguments are passed to a class initializer that uses dry-auto_inject. ```ruby begin service = UserService.new(CustomDB.new, CustomLogger.new, "extra") rescue ArgumentError => e puts e.message # => "wrong number of arguments (given 3, expected 2)" end ``` ```ruby begin UserService.new(db, logger, extra_arg) rescue ArgumentError => e puts "Invalid arguments: #{e.message}" end ``` -------------------------------- ### Module Definition for Injection Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/types.md Demonstrates how to obtain and include the injection module generated by AutoInject strategies in a class. ```ruby # Returns a Module subclass instance module = AutoInject[:database, :logger] # This module can be included in classes: class Service include module end # Or directly: class Service include AutoInject[:database, :logger] end ``` -------------------------------- ### Shorthand Dependency Injection with Kwargs Strategy Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/builder.md Use the [] method as a shorthand for the default kwargs strategy to specify dependencies for injection. ```ruby def [](*dependency_names) ``` ```ruby AutoInject = Dry.AutoInject(container) # Using [] directly (kwargs strategy) class UserRepository include AutoInject[:database, :logger] end ``` -------------------------------- ### Catching DuplicateDependencyError Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md Shows how to use a `begin...rescue` block to catch and handle `DuplicateDependencyError` when creating a `DependencyMap` with duplicate names. ```ruby begin DependencyMap.new(:database, :database) rescue Dry::AutoInject::DuplicateDependencyError => e puts "Duplicate dependency: #{e.message}" end ``` -------------------------------- ### Constructor Private Method: Define New Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/strategies.md Private method stub that must be implemented by subclasses to define the `new` class method with injection logic. ```ruby private def define_new raise NotImplementedError end ``` -------------------------------- ### Service with Kwargs Strategy Dependencies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Uses the default Kwargs strategy for dependency injection, where dependencies are passed as keyword arguments to the initializer. ```ruby class Service include AutoInject[:database, :logger] def initialize(database:, logger:) @database = database @logger = logger end end # Use with defaults service = Service.new # Override specific dependencies service = Service.new(logger: CustomLogger.new) ``` -------------------------------- ### Simplified Names from Namespaced Keys with AutoInject Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Illustrates how to map deeply nested or namespaced container keys to simpler local variable names during dependency injection. ```ruby # Container with deeply nested namespaces container = { "app.services.user.repository": UserRepository.new, "app.services.post.repository": PostRepository.new, "app.services.comment.repository": CommentRepository.new, "app.utilities.logger": Logger.new, "app.utilities.cache": Cache.new } AutoInject = Dry.AutoInject(container) class BlogService include AutoInject[ users: "app.services.user.repository", posts: "app.services.post.repository", comments: "app.services.comment.repository", logger: "app.utilities.logger", cache: "app.utilities.cache" ] def publish_post(title, content) post = @posts.create(title, content) @cache.invalidate("posts") @logger.info("Post published: #{post.id}") post end end ``` -------------------------------- ### Include Dependencies with Aliases Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/INDEX.md Shows how to include dependencies with custom aliases using AutoInject. This allows mapping dependency names to different attribute names within the class. ```ruby include AutoInject[:database, log: :logger, cache: "redis"] ``` -------------------------------- ### Accepting Additional Arguments in Initializer Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md Shows how to modify a class to accept additional arguments in its initialize method when using dry-auto_inject, preventing ArgumentErrors. ```ruby # Option 1: Accept additional arguments class UserService include AutoInject.args[:database, :logger] def initialize(database, logger, *extra_args) @database = database @logger = logger @extra = extra_args end end # Now this works: service = UserService.new(CustomDB.new, CustomLogger.new, "extra") ``` -------------------------------- ### inspect Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/dependency_map.md Returns a string representation of the dependency map, showing the internal mapping of dependency names to container identifiers. ```APIDOC ## inspect ### Description Returns a string representation of the dependency map, showing the internal mapping of dependency names to container identifiers. ### Return Type String containing the inspect output of the internal map. ### Example ```ruby map = DependencyMap.new(:database, :logger) map.inspect # => "{:database=>:database, :logger=>:logger}" ``` ``` -------------------------------- ### DependencyMap Constructor Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/dependency_map.md Initializes a new DependencyMap to track dependencies for injection. Dependencies are specified by their container identifiers, and aliases can be created using a final hash argument. ```APIDOC ## DependencyMap Constructor ### Description Creates a new DependencyMap that tracks which dependencies need to be injected. Dependencies are specified by their container identifiers, which are automatically converted to local variable names. The last argument can be a hash to create aliases, mapping local names to container identifiers that differ from the name. ### Parameters - **dependencies** (*Symbol, String, or Hash) - Required - List of dependency identifiers, optionally with aliases as a final hash ### Example ```ruby # Simple dependencies - names match container keys map = DependencyMap.new(:database, :logger) # Creates mapping: { database: :database, logger: :logger } # With aliasing - container key differs from local name map = DependencyMap.new(:database, db: "data_store", cache: "redis") # Creates mapping: { database: :database, db: "data_store", cache: "redis" } ``` ``` -------------------------------- ### Constructor for Dry::AutoInject::Builder Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/builder.md Initializes the builder with a container and optional configuration options. ```ruby def initialize(container, options = {}) ``` -------------------------------- ### Service with Hash Strategy Dependencies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Utilizes the Hash strategy for dependency injection, where dependencies are provided as options in a hash to the initializer. ```ruby class Service include AutoInject.hash[:database, :logger] def initialize(options = {}) @database = options[:database] @logger = options[:logger] end end # Use with defaults service = Service.new # Override with merged options service = Service.new(logger: CustomLogger.new, extra: 'config') ``` -------------------------------- ### Builder API for Injection Strategies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Shows how to use the builder object returned by Dry.AutoInject to specify different injection strategies like default (kwargs), args, and hash. ```ruby builder = Dry.AutoInject(container) # Default strategy (kwargs) builder[:dep1, :dep2] builder.kwargs[:dep1, :dep2] # Alternative strategies builder.args[:dep1, :dep2] builder.hash[:dep1, :dep2] ``` -------------------------------- ### Constructor Included Callback Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/strategies.md Callback method invoked when a strategy module is included in a class. It sets up dependency readers, the `new` method, and the `initialize` method. ```ruby def included(klass) end ``` -------------------------------- ### Generated Instance Methods and Variables Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/types.md Illustrates the `attr_reader` methods and instance variables automatically created by an included injection module. ```ruby # These are automatically created: attr_reader :database # For each dependency attr_reader :logger @database # Set to container[:database] @logger # Set to container[:logger] ``` -------------------------------- ### Shorthand Dependency Injection (`[]`) Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/builder.md A shorthand method for using the default injection strategy (kwargs) to specify dependencies. ```APIDOC ## Shorthand Dependency Injection (`[]`) ### Description A shorthand method for using the default injection strategy (kwargs) to specify dependencies. ### Method Signature `def []( *dependency_names )` ### Parameters #### Parameters - **dependency_names** (*Symbol, String, or Hash) - Names of dependencies to inject, or a hash for aliasing ### Return Type Returns a module that includes auto-injection with the specified dependencies using the default kwargs strategy. ### Description This is a shorthand for calling the `:default` strategy (which is `:kwargs`). Equivalent to calling `builder.kwargs[*dependency_names]`. ### Example ```ruby AutoInject = Dry.AutoInject(container) # Using [] directly (kwargs strategy) class UserRepository include AutoInject[:database, :logger] end ``` ``` -------------------------------- ### Single Inheritance with AutoInject Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Demonstrates how dependencies injected into a base class are automatically available to its subclasses. This promotes code reuse and consistent dependency management. ```ruby class BaseRepository include Dry.AutoInject({ database: Database.new, logger: Logger.new(STDOUT) })[:database, :logger] def execute_query(sql) logger.info("Executing: #{sql}") database.execute(sql) end end class UserRepository < BaseRepository def find_by_email(email) execute_query("SELECT * FROM users WHERE email = ?", email) end end # @database and @logger are inherited repo = UserRepository.new ``` -------------------------------- ### Keyword Arguments Injection Strategy (Default) Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/builder.md Selects the 'kwargs' strategy for injecting dependencies as keyword arguments. This is the default and most flexible strategy. ```ruby def kwargs ``` ```ruby class UserService include AutoInject.kwargs[:database, :logger] def initialize(database:, logger:) @database = database @logger = logger end end # Called as: service = UserService.new # Or with overrides: service = UserService.new(database: custom_db) ``` -------------------------------- ### Injector Constructor Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/injector.md Initializes the Injector with a container, strategy class, and a reference to the parent builder. ```ruby def initialize(container, strategy, builder:) ``` -------------------------------- ### Factory Pattern for Service Creation Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Implements a factory pattern using Dry::AutoInject to create service objects. The factory takes a container and provides methods to build specific services, injecting their required dependencies. ```ruby class ServiceFactory def initialize(container) @AutoInject = Dry.AutoInject(container) end def create_user_service Class.new do include @AutoInject[:database, :logger] def initialize(database:, logger:) @database = database @logger = logger end # ... implementation end.new end def create_post_service Class.new do include @AutoInject[:database, :cache] def initialize(database:, cache:) @database = database @cache = cache end # ... implementation end.new end end ``` -------------------------------- ### Dry::AutoInject::Builder Constructor Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/builder.md Initializes the Builder with a container and optional configuration options. ```APIDOC ## Dry::AutoInject::Builder Constructor ### Description Initializes the Builder with a container and optional configuration options. ### Parameters #### Parameters - **container** (Object) - Required - A container object that responds to `[]` indexing to retrieve dependencies - **options** (Hash) - Optional - Configuration options including custom `:strategies` ``` -------------------------------- ### Plugin System with Dry::AutoInject Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Builds a plugin system where plugins can register their services into a shared container. A manager then builds a unified AutoInject instance that includes dependencies from all loaded plugins. ```ruby class PluginManager def initialize(base_container) @container = base_container.dup @plugins = [] end def load_plugin(plugin_class) plugin = plugin_class.new(@container) plugin.register_services(@container) @plugins << plugin self end def build_injector Dry.AutoInject(@container) end end class AnalyticsPlugin def register_services(container) container[:analytics] = AnalyticsService.new container[:metrics] = MetricsCollector.new end end # Usage: manager = PluginManager.new(base_container) manager.load_plugin(AnalyticsPlugin) AutoInject = manager.build_injector ``` -------------------------------- ### Keyword Arguments Strategy (`kwargs`) Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/builder.md Selects the keyword arguments injection strategy (default), injecting dependencies as keyword arguments to the class initializer. ```APIDOC ## Keyword Arguments Strategy (`kwargs`) ### Description Selects the keyword arguments injection strategy (default), injecting dependencies as keyword arguments to the class initializer. ### Method Signature `def kwargs` ### Return Type Returns a `Dry::AutoInject::Injector` configured for the `:kwargs` strategy. ### Description The kwargs strategy injects dependencies as keyword arguments to the class initializer. This is the default strategy and the most flexible. Dependencies are filled in automatically if not provided explicitly. ### Example ```ruby class UserService include AutoInject.kwargs[:database, :logger] def initialize(database:, logger:) @database = database @logger = logger end end # Called as: service = UserService.new # Or with overrides: service = UserService.new(database: custom_db) ``` ``` -------------------------------- ### Handling Duplicate Dependencies with Dry.AutoInject Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Demonstrates that Dry.AutoInject raises a DuplicateDependencyError if the same dependency is listed multiple times during injection. ```ruby begin # This will raise DuplicateDependencyError class Service include AutoInject[:database, :database] end rescue Dry::AutoInject::DuplicateDependencyError => e puts "Configuration error: #{e.message}" end ``` -------------------------------- ### Define a Class with Injected Dependencies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/README.md Includes dependencies like database and logger using MyApp.Inject. These are automatically injected when the class is instantiated. ```ruby class UserRepository include MyApp.Inject(:database, :logger) def find(id) logger.info("Finding user #{id}") database.query(id) end end ``` -------------------------------- ### AutoInject Factory Function Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/INDEX.md The main entry point for creating an AutoInject instance. It takes a container and optional configuration options. ```ruby AutoInject = Dry.AutoInject(container, options = {}) ``` -------------------------------- ### Handling Reserved Method Names with Aliasing Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md Demonstrates how to use aliasing with Dry.AutoInject to inject dependencies whose keys conflict with Ruby's reserved method names. ```ruby # If you have a dependency that conflicts with a method name container = { "hash": HashStore.new, # 'hash' is a Ruby method "class": CustomClass.new # 'class' is a Ruby method } AutoInject = Dry.AutoInject(container) class Service # Use aliasing to avoid conflicts include AutoInject[ hash_store: "hash", class_provider: "class" ] def work @hash_store.set("key", "value") @class_provider.get_class end end ``` -------------------------------- ### Hash Strategy for Dependency Injection Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/USAGE_PATTERNS.md The Hash strategy injects dependencies as a hash of options. This is particularly useful for classes that require many configuration options during initialization. ```ruby class Application include AutoInject.hash[:database, :logger, :config] def initialize(options = {}) @database = options[:database] @logger = options[:logger] @config = options[:config] @additional_config = options.except(:database, :logger, :config) end end # Usage: app = Application.new app = Application.new( logger: CustomLogger.new, debug: true, version: "1.0" ) ``` -------------------------------- ### Service with Aliased Dependencies Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/types.md Shows a Service class using AutoInject with various forms of dependency aliasing. It includes simple mapping, aliasing a symbol to a different symbol, and aliasing a symbol to a string identifier. ```ruby class Service include AutoInject[ :database, # Simple - local name matches container key log: :logger, # Alias - map :logger to @log cache: "redis.cache" # String identifier with custom alias ] end ``` -------------------------------- ### Aliasing Long Container Keys Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/configuration.md Demonstrates using aliasing within the injection definition to map shorter local names to longer, more descriptive container keys. ```ruby class Service include AutoInject[ db: "services.database.primary", cache: "services.cache.redis", search: "services.search.elasticsearch" ] end ``` -------------------------------- ### Positional Arguments Strategy (`args`) Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/builder.md Selects the positional arguments injection strategy, injecting dependencies as positional arguments to the class initializer. ```APIDOC ## Positional Arguments Strategy (`args`) ### Description Selects the positional arguments injection strategy, injecting dependencies as positional arguments to the class initializer. ### Method Signature `def args` ### Return Type Returns a `Dry::AutoInject::Injector` configured for the `:args` strategy. ### Description The args strategy injects dependencies as positional arguments to the class initializer. Dependencies are filled in order at the beginning of the argument list, allowing additional arguments to be passed after. ### Example ```ruby class UserService include AutoInject.args[:database, :logger] def initialize(database, logger, options = {}) @database = database @logger = logger @options = options end end # Called as: service = UserService.new(options: { foo: 'bar' }) ``` ``` -------------------------------- ### Handling Aliasing Errors with Dependency Names Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/errors.md Demonstrates how to catch DependencyNameInvalid errors that occur when using aliasing for container keys that do not match Ruby identifiers. ```ruby begin # Use aliasing when container keys don't match Ruby identifiers class Service include AutoInject[valid_name: "container-key"] end rescue DependencyNameInvalid => e puts "Invalid dependency name: #{e.message}" end ``` -------------------------------- ### Injector Constructor Source: https://github.com/dry-rb/dry-auto_inject/blob/main/_autodocs/api-reference/injector.md Initializes the Injector with a container, strategy, and builder. This constructor is rarely called directly by users. ```APIDOC ## Constructor ```ruby def initialize(container, strategy, builder:) ``` ### Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | container | Object | Yes | The dependency container passed from the Builder | | strategy | Class | Yes | The injection strategy class to use (e.g., Strategies::Kwargs) | | builder | Dry::AutoInject::Builder | Yes | Reference back to the parent Builder instance | ### Description The Injector class is rarely instantiated directly by users. Instead, it is created when accessing a strategy from the Builder through method_missing. ```