### `configure` — Block-form configuration Source: https://context7.com/dry-rb/dry-configurable/llms.txt The `configure` method allows for block-based setup of configuration settings. It yields the config object and returns self. It raises `Dry::Configurable::FrozenConfigError` if the configuration has been finalized. ```APIDOC ## `configure` — Block-form configuration `configure` yields the `config` object and returns `self`, enabling a clean block-based setup. Raises `Dry::Configurable::FrozenConfigError` if the config has been finalized. ### Example ```ruby SearchService.configure do |config| config.endpoint = ENV.fetch("SEARCH_URL", "https://search.example.com") config.timeout = Integer(ENV.fetch("SEARCH_TIMEOUT", 5)) config.retries = 2 end ``` ### Error Handling ```ruby SearchService.finalize! SearchService.configure { |c| c.retries = 5 } # => Dry::Configurable::FrozenConfigError: Cannot modify frozen config ``` ``` -------------------------------- ### Convert Config to Frozen Data Struct with `to_data` Source: https://context7.com/dry-rb/dry-configurable/llms.txt Use `to_data` on a finalized config to get a frozen Data struct for efficient access. Consumers should memoize the result as a new object is returned on each call. ```ruby require "dry/configurable" class RenderConfig extend Dry::Configurable setting :template_path, default: "templates/" setting :cache_ttl, default: 300 setting :theme do setting :name, default: "default" setting :color, default: "#333" end end RenderConfig.finalize! # Memoize in a hot path @data = RenderConfig.config.to_data @data.template_path # => "templates/" (real method, no method_missing) @data.cache_ttl # => 300 @data.theme.name # => "default" @data.theme.color # => "#333" @data.frozen? # => true # Use object_id as cache key for identity-based lookup cache = {}.compare_by_identity cache[@data] = "cached_result" ``` -------------------------------- ### Test Interface: Resetting Configuration with `reset_config` Source: https://context7.com/dry-rb/dry-configurable/llms.txt Enable the test interface to use `reset_config`, which restores all settings to their default values between tests. Ensure `enable_test_interface` is called once, typically in test setup. ```ruby require "dry/configurable" class AppService extend Dry::Configurable setting :endpoint, default: "https://service.example.com" setting :timeout, default: 10 setting :pool do setting :size, default: 5 end end # In test setup (e.g., RSpec before(:suite)) AppService.enable_test_interface # In each test AppService.configure do |c| c.endpoint = "https://test.service.example.com" c.timeout = 1 c.pool.size = 2 end AppService.config.endpoint # => "https://test.service.example.com" # Reset between tests — restores all defaults AppService.reset_config AppService.config.endpoint # => "https://service.example.com" AppService.config.timeout # => 10 AppService.config.pool.size # => 5 ``` -------------------------------- ### Instance-level Configuration with include Source: https://context7.com/dry-rb/dry-configurable/llms.txt Use `include Dry::Configurable` to give each instance its own independent configuration object, while sharing setting definitions on the class. ```ruby require "dry/configurable" class DatabaseConnection include Dry::Configurable setting :adapter, default: "postgresql" setting :host, default: "localhost" setting :port, default: 5432 setting :timeout, default: 30 end production = DatabaseConnection.new production.configure do |c| c.host = "db.prod.example.com" c.timeout = 10 end development = DatabaseConnection.new development.configure do |c| c.adapter = "sqlite" c.host = "localhost" end production.config.host # => "db.prod.example.com" development.config.host # => "localhost" (independent copy) production.finalize! production.frozen? # => true production.config.frozen? # => true ``` -------------------------------- ### Define Mutable and Cloneable Settings with Dry-Configurable Source: https://context7.com/dry-rb/dry-configurable/llms.txt Demonstrates how to define settings with default values that are automatically mutable (cloned on inheritance) or explicitly controlled. Shows how changes to mutable settings in a subclass do not affect the parent class. ```ruby require "dry/configurable" class Router extend Dry::Configurable # Array default is automatically cloneable — each subclass/instance gets its own copy setting :middleware, default: [] # Explicitly marking a custom object as cloneable setting :routes, default: {}, mutable: true # Prevent implicit cloning for a Hash (unusual; shown for completeness) setting :static_map, default: {a: 1}, mutable: false end class ApiRouter < Router; end Router.config.middleware << :logging ApiRouter.config.middleware << :auth Router.config.middleware # => [:logging] ApiRouter.config.middleware # => [:auth] (independent copy) Router.config.routes[:home] = "/" ApiRouter.config.routes # => {} (independent) ``` -------------------------------- ### Configure settings using block-form Source: https://context7.com/dry-rb/dry-configurable/llms.txt Use `configure` to set up configuration values within a block. It yields the config object and returns self. Raises `FrozenConfigError` if the config is finalized. ```ruby require "dry/configurable" class SearchService extend Dry::Configurable setting :endpoint, default: "https://search.example.com" setting :timeout, default: 5 setting :retries, default: 3 end SearchService.configure do |config| config.endpoint = ENV.fetch("SEARCH_URL", "https://search.example.com") config.timeout = Integer(ENV.fetch("SEARCH_TIMEOUT", 5)) config.retries = 2 end SearchService.config.endpoint # => value from ENV or default SearchService.config.timeout # => 5 (or ENV override) # After finalize!, configure raises SearchService.finalize! SearchService.configure { |c| c.retries = 5 } # => Dry::Configurable::FrozenConfigError: Cannot modify frozen config ``` -------------------------------- ### Declaring Settings with `setting` Macro Source: https://context7.com/dry-rb/dry-configurable/llms.txt The `setting` macro defines configuration options. It supports defaults, constructors for value transformation, reader shortcuts, and nested settings. ```ruby require "dry/configurable" require "pathname" require "logger" class AppConfig extend Dry::Configurable # Plain setting with a default setting :environment, default: "development" # Constructor transforms the raw value on assignment setting :log_level, default: :info, constructor: ->(v) { v.to_sym } # Constructor that converts to a Pathname setting :root_path, default: ".", constructor: ->(v) { Pathname(v) } # reader: true creates a shortcut method directly on the class setting :secret_key, default: nil, reader: true # Nested settings group setting :mailer do setting :host, default: "smtp.example.com" setting :port, default: 587 setting :username, default: nil setting :password, default: nil end end AppConfig.config.environment # => "development" AppConfig.config.root_path # => # AppConfig.config.log_level = "warn" AppConfig.config.log_level # => :warn (constructor ran) AppConfig.secret_key # => nil (reader shortcut) AppConfig.config.mailer.host # => "smtp.example.com" AppConfig.config.mailer.port = 465 AppConfig.config.mailer.port # => 465 ``` -------------------------------- ### Class-level Configuration with extend Source: https://context7.com/dry-rb/dry-configurable/llms.txt Use `extend Dry::Configurable` to attach settings and a `config` accessor directly to the class, enabling global or app-level configuration. ```ruby require "dry/configurable" class MyApp extend Dry::Configurable setting :env, default: "development" setting :log_level, default: :info setting :database do setting :host, default: "localhost" setting :port, default: 5432 setting :name, default: "myapp_development" end end MyApp.config.env # => "development" MyApp.config.database.host # => "localhost" MyApp.configure do |config| config.env = "production" config.log_level = :warn config.database.host = "db.internal" config.database.port = 5433 end MyApp.config.env # => "production" MyApp.config.database.host # => "db.internal" ``` -------------------------------- ### `config` — Accessing and reading configuration values Source: https://context7.com/dry-rb/dry-configurable/llms.txt The `config` accessor provides access to a `Dry::Configurable::Config` instance. Settings can be read and written using method-style accessors or bracket notation. ```APIDOC ## `config` — Accessing and reading configuration values The `config` accessor returns a `Dry::Configurable::Config` instance. Settings can be read and written via method-style accessors or `[]`/`[]=` bracket notation. ### Method-style Access ```ruby Worker.config.queue # => "default" Worker.config.concurrency # => 5 ``` ### Bracket-style Access ```ruby Worker.config[:queue] # => "default" Worker.config["queue"] # => "default" ``` ### Writing Values ```ruby Worker.config.queue = "priority" Worker.config[:concurrency] = 10 ``` ### Viewing All Values ```ruby Worker.config.values # => {queue: "priority", concurrency: 10, retry_limit: 3} Worker.config.to_h # => {queue: "priority", concurrency: 10, retry_limit: 3} ``` ### Checking Configuration Status ```ruby Worker.config.configured?(:queue) # => true Worker.config.configured?(:retry_limit) # => false ``` ``` -------------------------------- ### `Config#update` — Bulk-updating config from a hash Source: https://context7.com/dry-rb/dry-configurable/llms.txt `update` allows for bulk configuration changes by accepting a Hash. It applies key-value pairs, runs constructors, and handles nested configurations recursively. It returns self, enabling chaining. ```APIDOC ## `Config#update` — Bulk-updating config from a hash `update` accepts a `Hash` (or any object responding to `#to_hash`) and applies each key-value pair to the config, running constructors and handling nested configs recursively. ### Example ```ruby ApiClient.config.update( base_url: "https://api.prod.example.com", timeout: 15, auth: { token: "abc123", scheme: "bearer" # constructor upcases to "Bearer" } ) ApiClient.config.base_url # => "https://api.prod.example.com" ApiClient.config.timeout # => 15 ApiClient.config.auth.token # => "abc123" ApiClient.config.auth.scheme # => "Bearer" ``` ### Chaining ```ruby ApiClient.config.update(timeout: 5).configured?(:timeout) # => true ``` ``` -------------------------------- ### Parameterized Extension with `default_undefined: true` Source: https://context7.com/dry-rb/dry-configurable/llms.txt Use `Dry.Configurable(default_undefined: true)` so that non-configured settings return `Dry::Core::Constants::Undefined` instead of `nil`. ```ruby require "dry/configurable" require "dry/core/constants" # default_undefined: true — non-configured settings return Dry::Core::Constants::Undefined class StrictApp extend Dry::Configurable(default_undefined: true) setting :api_key setting :timeout, default: 30 end StrictApp.config.api_key # => Dry::Core::Constants::Undefined (not nil) StrictApp.config.timeout # => 30 ``` -------------------------------- ### Access and read configuration values Source: https://context7.com/dry-rb/dry-configurable/llms.txt The `config` accessor returns a `Config` instance. Settings can be accessed and modified using method-style or bracket notation. Use `configured?` to check if a setting has been explicitly set. ```ruby require "dry/configurable" class Worker extend Dry::Configurable setting :queue, default: "default" setting :concurrency, default: 5 setting :retry_limit, default: 3 end # Method-style access Worker.config.queue # => "default" Worker.config.concurrency # => 5 # Bracket-style access (accepts String or Symbol) Worker.config[:queue] # => "default" Worker.config["queue"] # => "default" # Writer Worker.config.queue = "priority" Worker.config[:concurrency] = 10 Worker.config.values # => {queue: "priority", concurrency: 10, retry_limit: 3} Worker.config.to_h # => {queue: "priority", concurrency: 10, retry_limit: 3} # Check whether a setting has been explicitly configured Worker.config.configured?(:queue) # => true Worker.config.configured?(:retry_limit) # => false ``` -------------------------------- ### Parameterized Extension with Custom Config Class Source: https://context7.com/dry-rb/dry-configurable/llms.txt Create a parameterized extension using `Dry.Configurable` to pass options like `config_class`. The custom config class must inherit from `Dry::Configurable::Config`. ```ruby require "dry/configurable" require "dry/core/constants" # Custom config class — must inherit from Dry::Configurable::Config class MyConfig < Dry::Configurable::Config def database_url "#{self[:database].adapter}://#{self[:database].host}/#{self[:database].name}" end end class App extend Dry::Configurable(config_class: MyConfig) setting :database do setting :adapter, default: "postgresql" setting :host, default: "localhost" setting :name, default: "myapp" end end App.config.class # => MyConfig App.config.database_url # => "postgresql://localhost/myapp" ``` -------------------------------- ### Serialize configuration to a Hash Source: https://context7.com/dry-rb/dry-configurable/llms.txt The `to_h` method recursively converts the configuration object, including any nested `Config` objects, into a plain Ruby `Hash`. This is useful for serialization or inspection. ```ruby require "dry/configurable" class ReportConfig extend Dry::Configurable setting :format, default: :pdf setting :output do setting :directory, default: "/tmp/reports" setting :filename, default: "report" end setting :recipients, default: [] end ReportConfig.configure do |c| c.format = :csv c.output.directory = "/var/reports" c.recipients = ["alice@example.com", "bob@example.com"] end ReportConfig.config.to_h # => { # format: :csv, ``` -------------------------------- ### Bulk-update config from a hash Source: https://context7.com/dry-rb/dry-configurable/llms.txt Use `update` to apply multiple key-value pairs from a hash to the configuration. This method handles constructors and nested configurations recursively. It returns self, allowing for chaining. ```ruby require "dry/configurable" class ApiClient extend Dry::Configurable setting :base_url, default: "https://api.example.com" setting :auth do setting :token, default: nil setting :scheme, default: "Bearer", constructor: ->(v) { v.capitalize } end setting :timeout, default: 30 end # Bulk update from a hash (e.g., loaded from YAML or ENV) ApiClient.config.update( base_url: "https://api.prod.example.com", timeout: 15, auth: { token: "abc123", scheme: "bearer" # constructor upcases to "Bearer" } ) ApiClient.config.base_url # => "https://api.prod.example.com" ApiClient.config.timeout # => 15 ApiClient.config.auth.token # => "abc123" ApiClient.config.auth.scheme # => "Bearer" # update returns self, enabling chaining ApiClient.config.update(timeout: 5).configured?(:timeout) # => true ``` -------------------------------- ### Finalize and freeze configuration Source: https://context7.com/dry-rb/dry-configurable/llms.txt Call `finalize!` to freeze the configuration object and all nested configs, preventing further modifications. This method is idempotent. Use `freeze_values: true` to also freeze the values themselves. ```ruby require "dry/configurable" class AppSettings extend Dry::Configurable setting :secret, default: nil setting :database do setting :url, default: "postgres://localhost/myapp" setting :pool, default: 5 end end AppSettings.configure do |c| c.secret = ENV["APP_SECRET"] c.database.url = ENV["DATABASE_URL"] c.database.pool = 10 end # Freeze config only (values themselves remain mutable by default) AppSettings.finalize! AppSettings.config.frozen? # => true AppSettings.config.database.frozen? # => true # Freeze config AND all values recursively AppSettings2 = Class.new { extend Dry::Configurable; setting :name, default: "app".dup } AppSettings2.finalize!(freeze_values: true) AppSettings2.config.name.frozen? # => true # Any write attempt raises begin AppSettings.config.secret = "new-secret" rescue Dry::Configurable::FrozenConfigError => e puts e.message # => "Cannot modify frozen config" end ``` -------------------------------- ### `Config#to_h` — Serializing config to a plain Hash Source: https://context7.com/dry-rb/dry-configurable/llms.txt `to_h` recursively converts the configuration object, including any nested `Config` objects, into a standard Ruby Hash. ```APIDOC ## `Config#to_h` — Serializing config to a plain Hash `to_h` recursively converts the config (including nested `Config` objects) into a plain Ruby `Hash`. ### Example ```ruby ReportConfig.configure do |c| c.format = :csv c.output.directory = "/var/reports" c.recipients = ["alice@example.com", "bob@example.com"] end ReportConfig.config.to_h # => { # format: :csv, # output: { # directory: "/var/reports", # filename: "report" # }, # recipients: ["alice@example.com", "bob@example.com"] # } ``` ``` -------------------------------- ### Configuration Inheritance and Isolation in Subclasses Source: https://context7.com/dry-rb/dry-configurable/llms.txt Subclasses inherit a copy of the parent's settings and config values. Changes made after subclassing remain isolated, ensuring independent configurations. ```ruby require "dry/configurable" class BaseApp extend Dry::Configurable setting :log_level, default: :info setting :db do setting :pool, default: 5 end end class ProductionApp < BaseApp setting :workers, default: 4 # additional setting only in subclass end class StagingApp < BaseApp; end BaseApp.configure { |c| c.log_level = :warn } ProductionApp.configure do |c| c.log_level = :error c.db.pool = 20 c.workers = 8 end BaseApp.config.log_level # => :warn ProductionApp.config.log_level # => :error ProductionApp.config.db.pool # => 20 ProductionApp.config.workers # => 8 StagingApp.config.log_level # => :info (independent copy, unchanged) BaseApp.config.respond_to?(:workers) # => false (setting not on parent) ``` -------------------------------- ### `finalize!` — Freezing and locking configuration Source: https://context7.com/dry-rb/dry-configurable/llms.txt The `finalize!` method freezes the configuration object and any nested configurations, preventing further modifications. It is idempotent and should be called after all configuration is applied. An optional `freeze_values` argument can recursively freeze all setting values. ```APIDOC ## `finalize!` — Freezing and locking configuration `finalize!` freezes the config object (and nested configs) so no further changes can be made. Call it at application boot after all configuration is applied. It is idempotent — subsequent calls are no-ops. ### Freezing Config ```ruby AppSettings.finalize! AppSettings.config.frozen? # => true AppSettings.config.database.frozen? # => true ``` ### Freezing Config and Values ```ruby AppSettings2 = Class.new { extend Dry::Configurable; setting :name, default: "app".dup } AppSettings2.finalize!(freeze_values: true) AppSettings2.config.name.frozen? # => true ``` ### Error on Write Attempt ```ruby begin AppSettings.config.secret = "new-secret" rescue Dry::Configurable::FrozenConfigError => e puts e.message # => "Cannot modify frozen config" end ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.