132 lines
2.9 KiB
Ruby
132 lines
2.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "concurrent/map"
|
|
|
|
require "dry/core/equalizer"
|
|
|
|
require "dry/configurable/constants"
|
|
require "dry/configurable/errors"
|
|
|
|
module Dry
|
|
module Configurable
|
|
# Config exposes setting values through a convenient API
|
|
#
|
|
# @api public
|
|
class Config
|
|
include Dry::Equalizer(:values)
|
|
|
|
# @api private
|
|
attr_reader :_settings
|
|
|
|
# @api private
|
|
attr_reader :_resolved
|
|
|
|
# @api private
|
|
def initialize(settings)
|
|
@_settings = settings
|
|
@_resolved = Concurrent::Map.new
|
|
end
|
|
|
|
# Get config value by a key
|
|
#
|
|
# @param [String,Symbol] name
|
|
#
|
|
# @return Config value
|
|
def [](name)
|
|
name = name.to_sym
|
|
raise ArgumentError, "+#{name}+ is not a setting name" unless _settings.key?(name)
|
|
|
|
_settings[name].value
|
|
end
|
|
|
|
# Set config value.
|
|
# Note that finalized configs cannot be changed.
|
|
#
|
|
# @param [String,Symbol] name
|
|
# @param [Object] value
|
|
def []=(name, value)
|
|
public_send(:"#{name}=", value)
|
|
end
|
|
|
|
# Update config with new values
|
|
#
|
|
# @param values [Hash, #to_hash] A hash with new values
|
|
#
|
|
# @return [Config]
|
|
#
|
|
# @api public
|
|
def update(values)
|
|
values.each do |key, value|
|
|
if self[key].is_a?(self.class)
|
|
unless value.respond_to?(:to_hash)
|
|
raise ArgumentError, "#{value.inspect} is not a valid setting value"
|
|
end
|
|
|
|
self[key].update(value.to_hash)
|
|
else
|
|
self[key] = value
|
|
end
|
|
end
|
|
self
|
|
end
|
|
|
|
# Dump config into a hash
|
|
#
|
|
# @return [Hash]
|
|
#
|
|
# @api public
|
|
def values
|
|
_settings
|
|
.map { |setting| [setting.name, setting.value] }
|
|
.map { |key, value| [key, value.is_a?(self.class) ? value.to_h : value] }
|
|
.to_h
|
|
end
|
|
alias_method :to_h, :values
|
|
|
|
# @api private
|
|
def finalize!(freeze_values: false)
|
|
_settings.finalize!(freeze_values: freeze_values)
|
|
freeze
|
|
end
|
|
|
|
# @api private
|
|
def pristine
|
|
self.class.new(_settings.pristine)
|
|
end
|
|
|
|
# @api private
|
|
def respond_to_missing?(meth, include_private = false)
|
|
super || _settings.key?(resolve(meth))
|
|
end
|
|
|
|
private
|
|
|
|
# @api private
|
|
def method_missing(meth, *args)
|
|
setting = _settings[resolve(meth)]
|
|
|
|
super unless setting
|
|
|
|
if setting.writer?(meth)
|
|
raise FrozenConfig, "Cannot modify frozen config" if frozen?
|
|
|
|
_settings << setting.with(input: args[0])
|
|
else
|
|
setting.value
|
|
end
|
|
end
|
|
|
|
# @api private
|
|
def resolve(meth)
|
|
_resolved.fetch(meth) { _resolved[meth] = meth.to_s.tr("=", "").to_sym }
|
|
end
|
|
|
|
# @api private
|
|
def initialize_copy(source)
|
|
super
|
|
@_settings = source._settings.dup
|
|
end
|
|
end
|
|
end
|
|
end
|