Class: Dry::Configurable::Config

Inherits:
Object
  • Object
show all
Defined in:
lib/dry/configurable/config.rb

Overview

Config exposes setting values through a convenient API

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(settings, values: {}) ⇒ Config

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Config.



22
23
24
25
26
# File 'lib/dry/configurable/config.rb', line 22

def initialize(settings, values: {})
  @_settings = settings
  @_values = values
  @_configured = Set.new
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object (private)



233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/dry/configurable/config.rb', line 233

def method_missing(name, *args)
  setting_name = setting_name_from_method(name)
  setting = _settings[setting_name]

  super unless setting

  if name.end_with?("=")
    self[setting_name] = args[0]
  else
    self[setting_name]
  end
end

Instance Attribute Details

#_settingsObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



12
13
14
# File 'lib/dry/configurable/config.rb', line 12

def _settings
  @_settings
end

#_valuesObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



15
16
17
# File 'lib/dry/configurable/config.rb', line 15

def _values
  @_values
end

Instance Method Details

#[](name) ⇒ Object

Get config value by a key

Parameters:

  • name (String, Symbol)

Returns:

  • Config value



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/dry/configurable/config.rb', line 45

def [](name)
  name = name.to_sym

  unless (setting = _settings[name])
    raise ArgumentError, "+#{name}+ is not a setting name"
  end

  _values.fetch(name) {
    # Mutable settings may be configured after read
    _configured.add(name) if setting.cloneable?

    setting.to_value.tap { |value|
      _values[name] = value
    }
  }
end

#[]=(name, value) ⇒ Object

Set config value. Note that finalized configs cannot be changed.

Parameters:

  • name (String, Symbol)
  • value (Object)

Raises:



67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/dry/configurable/config.rb', line 67

def []=(name, value)
  raise FrozenConfigError, "Cannot modify frozen config" if frozen?

  name = name.to_sym

  unless (setting = _settings[name])
    raise ArgumentError, "+#{name}+ is not a setting name"
  end

  _configured.add(name)

  _values[name] = setting.constructor.(value)
end

#_dry_equalizer_hashObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



147
# File 'lib/dry/configurable/config.rb', line 147

alias_method :_dry_equalizer_hash, :hash

#configured?(key) ⇒ Bool

Returns true if the value for the given key has been set on this config.

For simple values, this returns true if the value has been explicitly assigned.

For cloneable (mutable) values, since these are captured on read, returns true if the value does not compare equally to its corresdponing default value. This relies on these objects having functioning ‘#==` checks.

Returns:

  • (Bool)


114
115
116
117
118
119
120
# File 'lib/dry/configurable/config.rb', line 114

def configured?(key)
  if _configured.include?(key) && _settings[key].cloneable?
    return _values[key] != _settings[key].to_value
  end

  _configured.include?(key)
end

#dup_for_settings(settings) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



36
37
38
# File 'lib/dry/configurable/config.rb', line 36

def dup_for_settings(settings)
  dup.tap { |config| config.instance_variable_set(:@_settings, settings) }
end

#finalize!(freeze_values: false) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/dry/configurable/config.rb', line 199

def finalize!(freeze_values: false)
  return self if frozen?

  values.each_value do |value|
    if value.is_a?(self.class)
      value.finalize!(freeze_values: freeze_values)
    elsif freeze_values
      value.freeze
    end
  end

  # Memoize the hash for the object when finalizing (regardless of whether values themselves
  # are to be frozen; the intention of finalization is that no further changes should be
  # made). The benefit of freezing the hash at this point is that it saves repeated expensive
  # computation (through Dry::Equalizer's hash implementation) if that hash is to be used
  # later in performance-sensitive situations, such as when serving as a cache key or similar.
  @__hash__ = _dry_equalizer_hash

  freeze
end

#hashObject



150
151
152
153
154
# File 'lib/dry/configurable/config.rb', line 150

def hash
  return @__hash__ if instance_variable_defined?(:@__hash__)

  _dry_equalizer_hash
end

#pristineObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



221
222
223
# File 'lib/dry/configurable/config.rb', line 221

def pristine
  self.class.new(_settings)
end

#to_dataData

Returns a frozen Data representation of the config’s resolved values.

The Data exposes each setting as a real method, sidestepping the #method_missing dispatch on the read path. Intended for performance-sensitive code that reads the same config repeatedly (e.g. per-request render hot paths). A new object is returned per call, so consumers should memoize the result.

Only available on a finalized config. Nested configs are converted recursively to nested Data instances. Values are captured by reference, so in-place mutation of a captured value remains visible through the Data; finalize with ‘freeze_values: true` if you want to prevent that.

The returned Data uses Ruby’s default structural ‘==`/`eql?`/`hash`. If you want to use it as an identity-based cache key (e.g. to skip walking N members on every lookup), memoize the reference yourself and either:

1. key it by `object_id` directly:

     @cached = view_class.config.to_data
     cache[@cached.object_id] = ...

2. use a `compare_by_identity` cache:

     cache = {}.compare_by_identity
     cache[@cached] = ...

Either avoids the contract-breaking ‘hash = object_id` override and keeps Data’s structural equality available for general use.

Returns:

  • (Data)

Raises:



190
191
192
193
194
195
196
# File 'lib/dry/configurable/config.rb', line 190

def to_data
  unless frozen?
    raise FrozenConfigError, "config must be finalized before #to_data can be called"
  end

  _settings.data_class.new(**to_data_attrs)
end

#to_hHash

Returns config values as a hash, with nested values also converted from Dry::Configurable::Config instances into hashes.

Returns:

  • (Hash)


142
143
144
# File 'lib/dry/configurable/config.rb', line 142

def to_h
  values.transform_values { |value| value.is_a?(self.class) ? value.to_h : value }
end

#update(values) ⇒ Config

Update config with new values

Parameters:

  • values (Hash, #to_hash)

    A hash with new values

Returns:



88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/dry/configurable/config.rb', line 88

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

#valuesHash

Returns the current config values.

Nested configs remain in their Dry::Configurable::Config instances.

Returns:

  • (Hash)


129
130
131
132
133
134
# File 'lib/dry/configurable/config.rb', line 129

def values
  # Ensure all settings are represented in values
  _settings.each { |setting| self[setting.name] unless _values.key?(setting.name) }

  _values
end