dry-configurable 0.12.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38b75c91290021054add38bdd9e3313f17aa133e219330a9b02a83227abd101c
4
- data.tar.gz: 4b808bd3880c35e2e80a702e4577f2b2da35ef2b31667f4314accc3cf0c20470
3
+ metadata.gz: 5d067b9cb78be3e3904b22ab5e73a6903cecb387c241d08c875f2a1eaf1002a4
4
+ data.tar.gz: c7f9be3367d11ea23c10a8a73d0a63d0fab54a1cf6cd2f5053e8845b808bd801
5
5
  SHA512:
6
- metadata.gz: efdd98ed5f60acf8090296954942f01c21702c29fa60c1edea21e0fbbb185955963b268191cb042ee33cc4651f4350419e7cbc2b7125c36103dce2733d137fa4
7
- data.tar.gz: 21d278a4f9f4a90d530145408585c30e004ce2830d5777a408bd9ea83bdfd5cba2ce58f1a1ca46f1212d0e8d5967891a25467f39e59a8af20291cf5ca1beff3f
6
+ metadata.gz: 45d5b855ac62fa249080b1c40ed9faf0644cf9daa3d3a18c8c3cc0780723006dd510d3b0cb156d2251962775f95396b591e96136d951e08e4679dd684118601d
7
+ data.tar.gz: fc7420686647324a2c671f183aff7b1fc69131f80db292d0847e53dc5744e16904f56dc74a35b6dadb6cce1f4927409a632d026d7127ccb5844d9b8ba67b4e98
data/CHANGELOG.md CHANGED
@@ -1,5 +1,124 @@
1
1
  <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
2
2
 
3
+ ## 0.16.1 2022-10-13
4
+
5
+
6
+ ### Changed
7
+
8
+ - Restored performance of config value reads (direct reader methods as well as aggregate methods like `#values` and `#to_h`) to pre-0.16.0 levels (#149 by @timriley)
9
+
10
+ [Compare v0.16.0...v0.16.1](https://github.com/dry-rb/dry-configurable/compare/v0.16.0...v0.16.1)
11
+
12
+ ## 0.16.0 2022-10-08
13
+
14
+
15
+ ### Added
16
+
17
+ - Support for custom config classes via `config_class:` option (#136 by @solnic)
18
+
19
+ ```ruby
20
+ extend Dry::Configurable(config_class: MyConfig)
21
+ ```
22
+
23
+ Your config class should inherit from `Dry::Configurable::Config`.
24
+ - Return `Dry::Core::Constants::Undefined` (instead of nil) as the value for non-configured settings via a `default_undefined: true` option (#141 by @timriley)
25
+
26
+ ```ruby
27
+ extend Dry::Configurable(default_undefined: true)
28
+ ```
29
+
30
+ You must opt into this feature via the `default_undefined: true` option. Non-configured setting values are still `nil` by default.
31
+
32
+ ### Fixed
33
+
34
+ - Remove exec bit from version.rb (#139 by @Fryguy)
35
+
36
+ ### Changed
37
+
38
+ - Improve memory usage by separating setting definitions from config values (#138 by @timriley)
39
+
40
+ Your usage of dry-configurable may be impacted if you have been accessing objects from `_settings` or the internals of `Dry::Configurable::Config`. `_settings` now returns `Dry::Configurable::Setting` instances, which contain only the details from the setting's definition. Setting _values_ remain in `Dry::Configurable::Config`.
41
+ - Use Zeitwerk to speed up load time (#135 by @solnic)
42
+
43
+ [Compare v0.15.0...v0.16.0](https://github.com/dry-rb/dry-configurable/compare/v0.15.0...v0.16.0)
44
+
45
+ ## 0.15.0 2022-04-21
46
+
47
+
48
+ ### Changed
49
+
50
+ - The `finalize!` method (as class or instance method, depending on whether you extend or include `Dry::Configurable` respectively) now accepts a boolean `freeze_values:` argument, which if true, will recursively freeze all config values in addition to the `config` itself. (#105 by @ojab)
51
+
52
+ ```ruby
53
+ class MyConfigurable
54
+ include Dry::Configurable
55
+
56
+ setting :db, default: "postgre"
57
+ end
58
+
59
+ my_obj = MyConfigurable.new
60
+ my_obj.finalize!(freeze_values: true)
61
+ my_obj.config.db << "sql" # Will raise FrozenError
62
+ ```
63
+ - `Dry::Configurable::Config#update` will set hashes as values for non-nested settings (#131 by @ojab)
64
+
65
+ ```ruby
66
+ class MyConfigurable
67
+ extend Dry::Configurable
68
+
69
+ setting :sslcert, constructor: ->(v) { v&.values_at(:pem, :pass)&.join }
70
+ end
71
+
72
+ MyConfigurable.config.update(sslcert: {pem: "cert", pass: "qwerty"})
73
+ MyConfigurable.config.sslcert # => "certqwerty"
74
+ ```
75
+ - `Dry::Configurable::Config#update` will accept any values implicitly convertible to hash via `#to_hash` (#133 by @timriley)
76
+
77
+ [Compare v0.14.0...v0.15.0](https://github.com/dry-rb/dry-configurable/compare/v0.14.0...v0.15.0)
78
+
79
+ ## 0.14.0 2022-01-14
80
+
81
+
82
+ ### Changed
83
+
84
+ - Settings defined after an access to `config` will still be made available on that `config`. (#130 by @timriley)
85
+ - Cloneable settings are cloned immediately upon assignment. (#130 by @timriley)
86
+ - Changes to config values in parent classes after subclasses have already been created will not be propogated to those subclasses. Subclasses created _after_ config values have been changed in the parent _will_ receive those config values. (#130 by @timriley)
87
+
88
+ [Compare v0.13.0...v0.14.0](https://github.com/dry-rb/dry-configurable/compare/v0.13.0...v0.14.0)
89
+
90
+ ## 0.13.0 2021-09-12
91
+
92
+
93
+ ### Added
94
+
95
+ - Added flags to determine whether to warn on the API usage deprecated in this release (see "Changed" section below). Set these to `false` to suppress the warnings. (#124 by @timriley)
96
+
97
+ ```ruby
98
+ Dry::Configurable.warn_on_setting_constructor_block false
99
+ Dry::Configurable.warn_on_setting_positional_default false
100
+ ```
101
+
102
+ ### Fixed
103
+
104
+ - Fixed `ArgumentError` for classes including `Dry::Configurable` whose `initializer` has required kwargs. (#113 by @timriley)
105
+
106
+ ### Changed
107
+
108
+ - Deprecated the setting constructor provided as a block. Provide it via the `constructor:` keyword argument instead. (#111 by @waiting-for-dev & @timriley)
109
+
110
+ ```ruby
111
+ setting :path, constructor: -> path { Pathname(path) }
112
+ ```
113
+ - Deprecated the setting default provided as the second positional argument. Provide it via the `default:` keyword argument instead. (#112 and #121 by @waiting-for-dev & @timriley)
114
+
115
+ ```ruby
116
+ setting :path, default: "some/default/path"
117
+ ```
118
+ - [BREAKING] Removed implicit `to_hash` conversion from `Config`. (#114 by @timriley)
119
+
120
+ [Compare v0.12.1...v0.13.0](https://github.com/dry-rb/dry-configurable/compare/v0.12.1...v0.13.0)
121
+
3
122
  ## 0.12.1 2021-02-15
4
123
 
5
124
 
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2021 dry-rb team
3
+ Copyright (c) 2015-2022 dry-rb team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ <!--- this file is synced from dry-rb/template-gem project -->
1
2
  [gem]: https://rubygems.org/gems/dry-configurable
2
3
  [actions]: https://github.com/dry-rb/dry-configurable/actions
3
4
  [codacy]: https://www.codacy.com/gh/dry-rb/dry-configurable
@@ -10,19 +11,19 @@
10
11
  [![CI Status](https://github.com/dry-rb/dry-configurable/workflows/ci/badge.svg)][actions]
11
12
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/0276a97990e04eb0ac722b3e7f3620b5)][codacy]
12
13
  [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/0276a97990e04eb0ac722b3e7f3620b5)][codacy]
13
- [![Inline docs](http://inch-ci.org/github/dry-rb/dry-configurable.svg?branch=master)][inchpages]
14
+ [![Inline docs](http://inch-ci.org/github/dry-rb/dry-configurable.svg?branch=main)][inchpages]
14
15
 
15
16
  ## Links
16
17
 
17
- * [User documentation](http://dry-rb.org/gems/dry-configurable)
18
+ * [User documentation](https://dry-rb.org/gems/dry-configurable)
18
19
  * [API documentation](http://rubydoc.info/gems/dry-configurable)
19
20
 
20
21
  ## Supported Ruby versions
21
22
 
22
23
  This library officially supports the following Ruby versions:
23
24
 
24
- * MRI >= `2.5`
25
- * jruby >= `9.2`
25
+ * MRI `>= 2.7.0`
26
+ * jruby `>= 9.3` (postponed until 2.7 is supported)
26
27
 
27
28
  ## License
28
29
 
@@ -1,35 +1,36 @@
1
1
  # frozen_string_literal: true
2
- # this file is managed by dry-rb/devtools project
3
2
 
4
- lib = File.expand_path('lib', __dir__)
3
+ # this file is synced from dry-rb/template-gem project
4
+
5
+ lib = File.expand_path("lib", __dir__)
5
6
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
- require 'dry/configurable/version'
7
+ require "dry/configurable/version"
7
8
 
8
9
  Gem::Specification.new do |spec|
9
- spec.name = 'dry-configurable'
10
+ spec.name = "dry-configurable"
10
11
  spec.authors = ["Andy Holland"]
11
12
  spec.email = ["andyholland1991@aol.com"]
12
- spec.license = 'MIT'
13
+ spec.license = "MIT"
13
14
  spec.version = Dry::Configurable::VERSION.dup
14
15
 
15
16
  spec.summary = "A mixin to add configuration functionality to your classes"
16
17
  spec.description = spec.summary
17
- spec.homepage = 'https://dry-rb.org/gems/dry-configurable'
18
+ spec.homepage = "https://dry-rb.org/gems/dry-configurable"
18
19
  spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-configurable.gemspec", "lib/**/*"]
19
- spec.bindir = 'bin'
20
+ spec.bindir = "bin"
20
21
  spec.executables = []
21
- spec.require_paths = ['lib']
22
+ spec.require_paths = ["lib"]
22
23
 
23
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
24
- spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-configurable/blob/master/CHANGELOG.md'
25
- spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-configurable'
26
- spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-configurable/issues'
24
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
25
+ spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-configurable/blob/main/CHANGELOG.md"
26
+ spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-configurable"
27
+ spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-configurable/issues"
27
28
 
28
- spec.required_ruby_version = ">= 2.5.0"
29
+ spec.required_ruby_version = ">= 2.7.0"
29
30
 
30
31
  # to update dependencies edit project.yml
31
- spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
32
- spec.add_runtime_dependency "dry-core", "~> 0.5", ">= 0.5.0"
32
+ spec.add_runtime_dependency "dry-core", "~> 1.0", "< 2"
33
+ spec.add_runtime_dependency "zeitwerk", "~> 2.6"
33
34
 
34
35
  spec.add_development_dependency "bundler"
35
36
  spec.add_development_dependency "rake"
@@ -1,11 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
4
-
5
- require 'dry/configurable/constants'
6
- require 'dry/configurable/dsl'
7
- require 'dry/configurable/methods'
8
- require 'dry/configurable/settings'
3
+ require "set"
9
4
 
10
5
  module Dry
11
6
  module Configurable
@@ -13,53 +8,54 @@ module Dry
13
8
  include Methods
14
9
 
15
10
  # @api private
16
- def inherited(klass)
11
+ def inherited(subclass)
17
12
  super
18
13
 
19
- parent_settings = (respond_to?(:config) ? config._settings : _settings)
14
+ subclass.instance_variable_set(:@__config_extension__, __config_extension__)
15
+
16
+ new_settings = settings.dup
17
+ subclass.instance_variable_set(:@_settings, new_settings)
20
18
 
21
- klass.instance_variable_set('@_settings', parent_settings)
19
+ # Only classes **extending** Dry::Configurable have class-level config. When
20
+ # Dry::Configurable is **included**, the class-level config method is undefined because it
21
+ # resides at the instance-level instead (see `Configurable.included`).
22
+ if respond_to?(:config)
23
+ subclass.instance_variable_set(:@config, config.dup_for_settings(new_settings))
24
+ end
22
25
  end
23
26
 
24
27
  # Add a setting to the configuration
25
28
  #
26
- # @param [Mixed] key
29
+ # @param [Mixed] name
27
30
  # The accessor key for the configuration value
28
31
  # @param [Mixed] default
29
- # The default config value
30
- #
32
+ # Default value for the setting
33
+ # @param [#call] constructor
34
+ # Transformation given value will go through
35
+ # @param [Boolean] reader
36
+ # Whether a reader accessor must be created
31
37
  # @yield
32
- # If a block is given, it will be evaluated in the context of
33
- # a new configuration class, and bound as the default value
38
+ # A block can be given to add nested settings.
34
39
  #
35
40
  # @return [Dry::Configurable::Config]
36
41
  #
37
42
  # @api public
38
- def setting(*args, &block)
39
- setting = __config_dsl__.setting(*args, &block)
43
+ def setting(*args, **options, &block)
44
+ setting = __config_dsl__.setting(*args, **options, &block)
40
45
 
41
- _settings << setting
46
+ settings << setting
42
47
 
43
48
  __config_reader__.define(setting.name) if setting.reader?
44
49
 
45
50
  self
46
51
  end
47
52
 
48
- # Return declared settings
49
- #
50
- # @return [Set<Symbol>]
51
- #
52
- # @api public
53
- def settings
54
- @settings ||= Set[*_settings.map(&:name)]
55
- end
56
-
57
- # Return declared settings
53
+ # Returns the defined settings for the class.
58
54
  #
59
55
  # @return [Settings]
60
56
  #
61
57
  # @api public
62
- def _settings
58
+ def settings
63
59
  @_settings ||= Settings.new
64
60
  end
65
61
 
@@ -69,12 +65,25 @@ module Dry
69
65
  #
70
66
  # @api public
71
67
  def config
72
- @config ||= Config.new(_settings)
68
+ @config ||= __config_build__
69
+ end
70
+
71
+ # @api private
72
+ def __config_build__(settings = self.settings)
73
+ __config_extension__.config_class.new(settings)
74
+ end
75
+
76
+ # @api private
77
+ def __config_extension__
78
+ @__config_extension__
73
79
  end
74
80
 
75
81
  # @api private
76
82
  def __config_dsl__
77
- @dsl ||= DSL.new
83
+ @__config_dsl__ ||= DSL.new(
84
+ config_class: __config_extension__.config_class,
85
+ default_undefined: __config_extension__.default_undefined
86
+ )
78
87
  end
79
88
 
80
89
  # @api private
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/configurable/setting'
4
- require 'dry/configurable/settings'
5
-
6
3
  module Dry
7
4
  module Configurable
8
5
  # Setting compiler used internally by the DSL
@@ -23,22 +20,18 @@ module Dry
23
20
  public_send(:"visit_#{type}", rest)
24
21
  end
25
22
 
26
- # @api private
27
- def visit_constructor(node)
28
- setting, constructor = node
29
- visit(setting).with(constructor: constructor)
30
- end
31
-
32
23
  # @api private
33
24
  def visit_setting(node)
34
- name, default, opts = node
35
- Setting.new(name, **opts, default: default)
25
+ name, opts = node
26
+ Setting.new(name, **opts)
36
27
  end
37
28
 
38
29
  # @api private
39
30
  def visit_nested(node)
40
31
  parent, children = node
41
- visit(parent).nested(call(children))
32
+ name, opts = parent[1]
33
+
34
+ Setting.new(name, **opts, children: Settings.new(call(children)))
42
35
  end
43
36
  end
44
37
  end
@@ -1,11 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/map'
4
-
5
- require 'dry/core/equalizer'
6
-
7
- require 'dry/configurable/constants'
8
- require 'dry/configurable/errors'
3
+ require "set"
9
4
 
10
5
  module Dry
11
6
  module Configurable
@@ -19,12 +14,29 @@ module Dry
19
14
  attr_reader :_settings
20
15
 
21
16
  # @api private
22
- attr_reader :_resolved
17
+ attr_reader :_values
18
+
19
+ # @api private
20
+ attr_reader :_configured
21
+ protected :_configured
23
22
 
24
23
  # @api private
25
- def initialize(settings)
26
- @_settings = settings.dup
27
- @_resolved = Concurrent::Map.new
24
+ def initialize(settings, values: {})
25
+ @_settings = settings
26
+ @_values = values
27
+ @_configured = Set.new
28
+ end
29
+
30
+ # @api private
31
+ private def initialize_copy(source)
32
+ super
33
+ @_values = source.__send__(:dup_values)
34
+ @_configured = source._configured.dup
35
+ end
36
+
37
+ # @api private
38
+ def dup_for_settings(settings)
39
+ dup.tap { |config| config.instance_variable_set(:@_settings, settings) }
28
40
  end
29
41
 
30
42
  # Get config value by a key
@@ -34,9 +46,19 @@ module Dry
34
46
  # @return Config value
35
47
  def [](name)
36
48
  name = name.to_sym
37
- raise ArgumentError, "+#{name}+ is not a setting name" unless _settings.key?(name)
38
49
 
39
- _settings[name].value
50
+ unless (setting = _settings[name])
51
+ raise ArgumentError, "+#{name}+ is not a setting name"
52
+ end
53
+
54
+ _values.fetch(name) {
55
+ # Mutable settings may be configured after read
56
+ _configured.add(name) if setting.cloneable?
57
+
58
+ setting.to_value.tap { |value|
59
+ _values[name] = value
60
+ }
61
+ }
40
62
  end
41
63
 
42
64
  # Set config value.
@@ -45,21 +67,34 @@ module Dry
45
67
  # @param [String,Symbol] name
46
68
  # @param [Object] value
47
69
  def []=(name, value)
48
- public_send(:"#{name}=", value)
70
+ raise FrozenConfigError, "Cannot modify frozen config" if frozen?
71
+
72
+ name = name.to_sym
73
+
74
+ unless (setting = _settings[name])
75
+ raise ArgumentError, "+#{name}+ is not a setting name"
76
+ end
77
+
78
+ _configured.add(name)
79
+
80
+ _values[name] = setting.constructor.(value)
49
81
  end
50
82
 
51
83
  # Update config with new values
52
84
  #
53
- # @param values [Hash] A hash with new values
85
+ # @param values [Hash, #to_hash] A hash with new values
54
86
  #
55
87
  # @return [Config]
56
88
  #
57
89
  # @api public
58
90
  def update(values)
59
91
  values.each do |key, value|
60
- case value
61
- when Hash
62
- self[key].update(value)
92
+ if self[key].is_a?(self.class)
93
+ unless value.respond_to?(:to_hash)
94
+ raise ArgumentError, "#{value.inspect} is not a valid setting value"
95
+ end
96
+
97
+ self[key].update(value.to_hash)
63
98
  else
64
99
  self[key] = value
65
100
  end
@@ -67,62 +102,113 @@ module Dry
67
102
  self
68
103
  end
69
104
 
70
- # Dump config into a hash
105
+ # Returns true if the value for the given key has been set on this config.
106
+ #
107
+ # For simple values, this returns true if the value has been explicitly assigned.
108
+ #
109
+ # For cloneable (mutable) values, since these are captured on read, returns true if the value
110
+ # does not compare equally to its corresdponing default value. This relies on these objects
111
+ # having functioning `#==` checks.
112
+ #
113
+ # @return [Bool]
114
+ #
115
+ # @api public
116
+ def configured?(key)
117
+ if _configured.include?(key) && _settings[key].cloneable?
118
+ return _values[key] != _settings[key].to_value
119
+ end
120
+
121
+ _configured.include?(key)
122
+ end
123
+
124
+ # Returns the current config values.
125
+ #
126
+ # Nested configs remain in their {Config} instances.
71
127
  #
72
128
  # @return [Hash]
73
129
  #
74
130
  # @api public
75
131
  def values
76
- _settings
77
- .map { |setting| [setting.name, setting.value] }
78
- .map { |key, value| [key, value.is_a?(self.class) ? value.to_h : value] }
79
- .to_h
132
+ # Ensure all settings are represented in values
133
+ _settings.each { |setting| self[setting.name] unless _values.key?(setting.name) }
134
+
135
+ _values
80
136
  end
81
- alias_method :to_h, :values
82
- alias_method :to_hash, :values
83
137
 
84
- # @api private
85
- def finalize!
86
- _settings.freeze
87
- freeze
138
+ # Returns config values as a hash, with nested values also converted from {Config} instances
139
+ # into hashes.
140
+ #
141
+ # @return [Hash]
142
+ #
143
+ # @api public
144
+ def to_h
145
+ values.to_h { |key, value| [key, value.is_a?(self.class) ? value.to_h : value] }
88
146
  end
89
147
 
90
148
  # @api private
91
- def pristine
92
- self.class.new(_settings.pristine)
149
+ alias_method :_dry_equalizer_hash, :hash
150
+
151
+ # @api public
152
+ def hash
153
+ return @__hash__ if instance_variable_defined?(:@__hash__)
154
+
155
+ _dry_equalizer_hash
156
+ end
157
+
158
+ # @api public
159
+ def finalize!(freeze_values: false)
160
+ return self if frozen?
161
+
162
+ values.each_value do |value|
163
+ if value.is_a?(self.class)
164
+ value.finalize!(freeze_values: freeze_values)
165
+ elsif freeze_values
166
+ value.freeze
167
+ end
168
+ end
169
+
170
+ # Memoize the hash for the object when finalizing (regardless of whether values themselves
171
+ # are to be frozen; the intention of finalization is that no further changes should be
172
+ # made). The benefit of freezing the hash at this point is that it saves repeated expensive
173
+ # computation (through Dry::Equalizer's hash implementation) if that hash is to be used
174
+ # later in performance-sensitive situations, such as when serving as a cache key or similar.
175
+ @__hash__ = _dry_equalizer_hash
176
+
177
+ freeze
93
178
  end
94
179
 
95
180
  # @api private
96
- def respond_to_missing?(meth, include_private = false)
97
- super || _settings.key?(resolve(meth))
181
+ def pristine
182
+ self.class.new(_settings)
98
183
  end
99
184
 
100
185
  private
101
186
 
102
- # @api private
103
- def method_missing(meth, *args)
104
- setting = _settings[resolve(meth)]
187
+ def method_missing(name, *args)
188
+ setting_name = setting_name_from_method(name)
189
+ setting = _settings[setting_name]
105
190
 
106
191
  super unless setting
107
192
 
108
- if setting.writer?(meth)
109
- raise FrozenConfig, 'Cannot modify frozen config' if frozen?
110
-
111
- _settings << setting.with(input: args[0])
193
+ if name.end_with?("=")
194
+ self[setting_name] = args[0]
112
195
  else
113
- setting.value
196
+ self[setting_name]
114
197
  end
115
198
  end
116
199
 
117
- # @api private
118
- def resolve(meth)
119
- _resolved.fetch(meth) { _resolved[meth] = meth.to_s.tr('=', '').to_sym }
200
+ def respond_to_missing?(meth, include_private = false)
201
+ _settings.key?(setting_name_from_method(meth)) || super
120
202
  end
121
203
 
122
- # @api private
123
- def initialize_copy(source)
124
- super
125
- @_settings = source._settings.dup
204
+ def setting_name_from_method(method_name)
205
+ method_name.to_s.tr("=", "").to_sym
206
+ end
207
+
208
+ def dup_values
209
+ _values.each_with_object({}) { |(key, val), dup_hsh|
210
+ dup_hsh[key] = _settings[key].cloneable? ? val.dup : val
211
+ }
126
212
  end
127
213
  end
128
214
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/constants'
4
-
5
3
  module Dry
6
4
  # Shared constants
7
5
  #