lib/dry/configurable.rb



require 'thread_safe'
require 'dry/configurable/config'
require 'dry/configurable/version'

module Dry
  # A simple configuration mixin
  #
  # @example
  #
  #   class App
  #     extend Dry::Configurable
  #
  #     setting :database do
  #       setting :dsn, 'sqlite:memory'
  #     end
  #   end
  #
  #   App.confiure do |config|
  #     config.database.dsn = 'jdbc:sqlite:memory'
  #   end
  #
  #   App.config.database.dsn
  #     # => "jdbc:sqlite:memory'"
  #
  # @api public
  module Configurable
    # @private
    def self.extended(base)
      base.instance_variable_set(:@_config_mutex, Mutex.new)
      base.instance_variable_set(:@_settings_mutex, Mutex.new)
    end
    # Return configuration
    #
    # @return [Dry::Configurable::Config]
    #
    # @api public
    def config
      @_config_mutex.synchronize do
        return @_config if defined?(@_config)
        @_config = Config.new(*_settings.keys).new(*_settings.values) unless _settings.empty?
      end
    end
    # Return configuration
    #
    # @yield [Dry::Configuration::Config]
    #
    # @return [Dry::Configurable::Config]
    #
    # @api public
    def configure
      yield(config) if block_given?
    end
    # Add a setting to the configuration
    #
    # @param [Mixed] key
    #   The accessor key for the configuration value
    # @param [Mixed] default
    #   The default config value
    #
    # @yield
    #   If a block is given, it will be evaluated in the context of
    #   and new configuration class, and bound as the default value
    #
    # @return [Dry::Configurable::Config]
    #
    # @api public
    def setting(key, default = nil, &block)
      default = _config_for(&block) if block_given?
      _settings[key] = default
    end

    private

    # @private
    def _settings
      @_settings_mutex.synchronize { @_settings ||= ThreadSafe::Cache.new }
    end

    # @private
    def _config_for(&block)
      config_klass = Class.new { extend Dry::Configurable }
      config_klass.instance_eval(&block)
      config_klass.config
    end
  end
end