dry-rb / dry-configurable Goto Github PK
View Code? Open in Web Editor NEWA simple mixin to make Ruby classes configurable
Home Page: https://dry-rb.org/gems/dry-configurable/
License: MIT License
A simple mixin to make Ruby classes configurable
Home Page: https://dry-rb.org/gems/dry-configurable/
License: MIT License
Way to reproduce:
class A
extend Dry::Configurable
setting :a
end
A.config
class A
setting :b
end
# => Dry::Configurable::AlreadyDefinedConfig (Cannot add setting +b+, A is already configured)
If I omit the A.config
in-between, there is no problem in adding setting :b
.
I don't think it is desirable. In my scenario it happens because I'm developing a library with a bunch of extensions. Some of these extensions reopen a class to add a new setting
. While surely it would be no problem in production (users will load all needed extensions at once, before any call to #config
) it is a problem for my test suite, as I pick extensions depending on the test file and some tests access #config
to make an assertion. I know I could remove the constant after each test, but anyway I don't think it is the desired behavior.
I'm just throwing this idea out there, but it would be nice to have a "before configuration changed" callback triggered when configuration is about to be changed.
This would give us a hook to validate the configuration before accepting it.
The upcoming 0.13.0 release will include a couple of large changes:
constructor:
argument insteaddefault:
argument, rather than a second positional argumentWhile we've strived for these changes to be backwards compatible, they may cause breakage in certain circumstances.
To this end, we need to make sure we coordinate this 0.13.0 release of dry-configurable with all the gems that use it within the dry-rb, rom-rb, and Hanami ecosystems. This issue will serve as this coordination point.
To make sure the new dry-configurable 0.13.0 release offers the appropriate level of backwards compatibility, we want to test all of its dependent gems across the dry-rb/rom-rb/hanami ecosystem.
The table below tracks the test we're (manually) running on each gem. The tests should exercise each of these cases:
The tests should pass in all cases.
Testing instructions are as follows:
git fetch --all --tags
to get all tagsgit checkout tags/v0.8.0
or git checkout master
0.12.1
or the master
branchDependent gem | dry-configurable 0.12.1 | dry-configurable 0.13.0 |
---|---|---|
dry-container @ v0.8.0 @ ruby 3.0 | ✅ | ✅ |
dry-container @ v0.8.0 @ ruby 2.7 | ✅ | ✅ |
dry-container @ master @ ruby 3.0 | n/a | ✅ |
dry-container @ master @ ruby 2.7 | n/a | ✅ |
dry-effects @ v0.1.5 @ ruby 3.0 | ✅ (see note) | ✅ |
dry-effects @ v0.1.5 @ ruby 2.7 | ✅ | ✅ |
dry-effects @ master @ ruby 3.0 | n/a | ✅ |
dry-effects @ master @ ruby 2.7 | n/a | ✅ |
dry-monitor @ v0.4.0 @ ruby 3.0 | ✅ | ✅ |
dry-monitor @ v0.4.0 @ ruby 2.7 | ✅ | ✅ |
dry-monitor @ dry-rb/dry-monitor#43 @ ruby 3.0 | n/a | ✅ |
dry-monitor @ dry-rb/dry-monitor#43 @ ruby 2.7 | n/a | ✅ |
dry-rails @ v.0.3.0 @ ruby 3.0 | ✅ (see note) | ✅ (with dry-system release-0.18 branch) |
dry-rails @ v.0.3.0 @ ruby 2.7 | ✅ | ✅ (with dry-system release-0.18 branch) |
dry-rails @ dry-rb/dry-rails#44 @ ruby 3.0 | n/a | ✅ (with dry-system release-0.18 branch) |
dry-rails @ dry-rb/dry-rails#44 @ ruby 2.7 | n/a | ✅ (with dry-system release-0.18 branch) |
✅ | n/a (see rows below, and original failure note) | |
n/a | n/a | |
dry-schema @ v.1.7.1 @ ruby 3.0 | ✅ | ✅ |
dry-schema @ v.1.7.1 @ ruby 2.7 | ✅ | ✅ |
dry-schema @ dry-rb/dry-schema#356 @ ruby 3.0 | n/a | |
dry-schema @ dry-rb/dry-schema#356 @ ruby 2.7 | n/a | |
✅ | n/a (see rows below, and original failure note) | |
n/a (see rows below) | n/a | |
dry-system @ dry-rb/dry-system#186 (fix for 0.19.1) @ ruby 3.0 | ✅ | ✅ |
dry-system @ dry-rb/dry-system#186 (fix for 0.19.1) @ ruby 2.7 | ✅ | ✅ |
dry-system @ master @ ruby 3.0 | n/a | ✅ |
dry-system @ master @ ruby 2.7 | n/a | ✅ |
dry-validation @ v1.6.0 @ ruby 3.0 | ✅ (see note) | ✅ |
dry-validation @ v1.6.0 @ ruby 2.7 | ✅ | ✅ |
dry-validation @ dry-rb/dry-validation#686 @ ruby 3.0 | n/a | ✅ |
dry-validation @ dry-rb/dry-validation#686 @ ruby 2.7 | n/a | ✅ |
hanami-view @ v2.0.0.alpha2 @ ruby 3.0 | ✅ | ✅ (with dry-system release-0.19 branch) |
hanami-view @ v2.0.0.alpha2 @ ruby 2.7 | ✅ | ✅ (with dry-system release-0.19 branch) |
hanami-view @ master @ ruby 3.0 | n/a | ✅ |
hanami-view @ master @ ruby 2.7 | n/a | ✅ |
hanami @ v2.0.0.alpha2 @ ruby 3.0 | ✅ | ✅ (with dry-system release-0.19 branch) |
hanami @ v2.0.0.alpha2 @ ruby 2.7 | ✅ | ✅ (with dry-system release-0.19 branch) |
hanami @ main @ ruby 3.0 | n/a | ✅ |
hanami @ main @ ruby 2.7 | n/a | ✅ |
This has some unrelated failures at the moment due to breaking changes in dry-system (e.g. moving of the default_namespace setting). I temporarily fixed these by pinning to an older dry-system just for the tests.
Specs here are failing because ActiveSupport's core extensions are not loaded and spec/dummy-6.x/dummy/config/environments/test.rb
uses 1.hour
, which results in this error:
An error occurred while loading spec_helper.
Failure/Error: "Cache-Control" => "public, max-age=#{1.hour.to_i}"
NoMethodError:
undefined method `hour' for 1:Integer
# ./spec/dummy-6.x/dummy/config/environments/test.rb:21:in `block in <top (required)>'
# ./spec/dummy-6.x/dummy/config/environments/test.rb:8:in `<top (required)>'
# ./spec/dummy-6.x/dummy/config/environment.rb:7:in `<top (required)>'
# ./spec/spec_helper.rb:19:in `require'
# ./spec/spec_helper.rb:19:in `<top (required)>'
A quick fix is to chuck require "active_support/all"
in spec_helper.rb
, just above the require to the dummy app's config/environment
.
This should be properly fixed in a separate PR.
8 failing tests, all with the same error:
no implicit conversion of Dry::Configurable::Config into Hash
This is because I removed that implicit hash conversion in #114.
We'll need to update dry-schema to do explicit hash conversion and release that first.
Now fixed in dry-rb/dry-system#186.
This fails with the following error:
Failure/Error: super(name, *args, &block)
ArgumentError:
wrong number of arguments (given 3, expected 1..2)
# ./lib/dry/system/container.rb:105:in `setting'
The problem is with the params signature of the Dry::System::Container.setting
override method, which I'm not entirely sure is even needed anymore. This will need a fix and a release to do more flexible argument forwarding before other gems depending on dry-system (i.e. hanami and dry-rails) can be compatible with the upcoming dry-configurable release.
A fix for this is already included in dry-rb/dry-system#179, which is merged into master, but alongside changes to use the latest dry-configurable setting
API.
Dry::System::Container.setting
override method (ideally something that has more flexible argument forwarding so that it works with both versions of dry-configurable) and release that as an independent patch release, separate from any of the other changes currently in dry-system master.
The tests all pass apart from this flaky spec that has seen been disabled.
Here's a list of PRs to dependent gems to have them use the API.
n.b. the dry-validation and dry-schema PRs had some attempts at special compatibility shim code that should no longer needed now that dry-configurable 0.13.0 offers better backwards compatibility. These shims should be removed before testing.
Once these are all merged (and all the tests in the previous section are completed), we can consider a release.
This section still needs more work, but it'll be something like this
x.[THIS ONE].y
(?? - I think minor is better than patch because that way we're less likely to foist a whole bunch of deprecation notices on our users unsuspectingly)Using the latest version of this gem, a simple require 'dry-configurable'
results in the following stacktrace:
irb(main):002:0> require 'dry-configurable'
Traceback (most recent call last):
16: from /usr/local/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
15: from (irb):1
14: from (irb):2:in `rescue in irb_binding'
13: from (irb):2:in `require'
12: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry-configurable.rb:3:in `<top (required)>'
11: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry-configurable.rb:3:in `require'
10: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable.rb:6:in `<top (required)>'
9: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable.rb:6:in `require'
8: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/class_methods.rb:6:in `<top (required)>'
7: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/class_methods.rb:6:in `require'
6: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/dsl.rb:4:in `<top (required)>'
5: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/dsl.rb:4:in `require'
4: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/flags.rb:5:in `<top (required)>'
3: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/flags.rb:6:in `<module:Dry>'
2: from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/flags.rb:11:in `<module:Configurable>'
1: from /usr/local/bundle/gems/dry-core-0.9.0/lib/dry/core/class_attributes.rb:65:in `defines'
NameError (uninitialized constant Dry::Core::ClassAttributes::IDENTITY)
Install the latest release of dry-configurable and require this gem.
The gem would load fine and not throw any errors.
When requiring dry-core
before, everything works fine:
irb(main):001:0> require 'dry-configurable'
/usr/local/bundle/gems/dry-core-0.9.0/lib/dry/core/class_attributes.rb:65:in `defines': uninitialized constant Dry::Core::ClassAttributes::IDENTITY (NameError)
def defines(*args, type: ::Object, coerce: IDENTITY) # rubocop:disable Metrics/PerceivedComplexity
^^^^^^^^
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/flags.rb:11:in `<module:Configurable>'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/flags.rb:6:in `<module:Dry>'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/flags.rb:5:in `<top (required)>'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/dsl.rb:4:in `require'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/dsl.rb:4:in `<top (required)>'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/class_methods.rb:6:in `require'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable/class_methods.rb:6:in `<top (required)>'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable.rb:6:in `require'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry/configurable.rb:6:in `<top (required)>'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry-configurable.rb:3:in `require'
from /usr/local/bundle/gems/dry-configurable-0.13.0/lib/dry-configurable.rb:3:in `<top (required)>'
from (irb):1:in `require'
from (irb):1:in `<main>'
from /usr/local/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>'
from /usr/local/bin/irb:25:in `load'
from /usr/local/bin/irb:25:in `<top (required)>'
... 15 levels...
irb(main):002:0> require 'dry-core'
=> true
irb(main):003:0> require 'dry-configurable'
=> true
#finalize!
freezes the main config, but internal configs are still not frozen.
require 'dry-configurable'
class App
extend Dry::Configurable
setting :database do
setting :dsn, 'sqlite:memory'
end
end
App.config.finalize!
App.config.database.dsn = 'wrong!'
p App.config.database.dsn # => wrong!
App.config.database = 'wrong!' # => Cannot modify frozen config
App.config
is immutable, so even nested values can't be changed.
After upgrading this library to 0.16.0 the config_file extension in Sinatra seems to break with
undefined method `foo' for Sinatra::Application:Class
when settings.foo
gets called.
This was working just fine on 0.15.0.
I thought it might be zeitwerk, but 0.15.0 + zeitwerk work just fine so I suspect it's the changes in version 0.16.0 (possibly related to zeitwerk). Also this only seems to be happening in our tests in RSpec, not in normal dev environment.
Install sinatra, sinatra-contrib and configure config_file extension. Let me know if you need a reproduction repository, I can prepare something later today or tomorrow.
settings.foo
from Sinatra should not crash.
When using dry-validation
0.9.5
with dry-configurable
0.2.0
I get an error.
It happens when trying to require dry-validation
.
I don't think I can provide any more inside but I can try to explain more if you want to.
***
is a path to spec file.
Here is the stacktrace:
bundler: failed to load command: rspec (/Users/x/.rbenv/versions/2.3.0/bin/rspec)
ArgumentError: unknown keywords: sanitizer, json, form
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-configurable-0.2.0/lib/dry/configurable.rb:83:in `setting'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry/validation/schema/class_interface.rb:25:in `<class:Schema>'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry/validation/schema/class_interface.rb:6:in `<module:Validation>'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry/validation/schema/class_interface.rb:5:in `<module:Dry>'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry/validation/schema/class_interface.rb:4:in `<top (required)>'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry/validation/schema.rb:17:in `require'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry/validation/schema.rb:17:in `<top (required)>'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry/validation.rb:5:in `require'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry/validation.rb:5:in `<top (required)>'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry-validation.rb:1:in `require'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/dry-validation-0.9.5/lib/dry-validation.rb:1:in `<top (required)>'
***_spec.rb:2:in `require'
***_spec.rb:2:in `<top (required)>'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.2/lib/rspec/core/configuration.rb:1435:in `load'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.2/lib/rspec/core/configuration.rb:1435:in `block in load_spec_files'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.2/lib/rspec/core/configuration.rb:1433:in `each'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.2/lib/rspec/core/configuration.rb:1433:in `load_spec_files'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.2/lib/rspec/core/runner.rb:100:in `setup'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.2/lib/rspec/core/runner.rb:86:in `run'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.2/lib/rspec/core/runner.rb:71:in `run'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.2/lib/rspec/core/runner.rb:45:in `invoke'
/Users/x/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.2/exe/rspec:4:in `<top (required)>'
/Users/x/.rbenv/versions/2.3.0/bin/rspec:22:in `load'
/Users/x/.rbenv/versions/2.3.0/bin/rspec:22:in `<top (required)>'
I'm not sure if this is exactly the problem of dry-configurable or karafka, but bumping the version from 0.15.0 to 0.16.x causes the issue.
I'm using dry-configurable and karafka 1.4x. After the update to 0.16.x, this is what I get when running bundle exec karafka server
:
/Users/karol/.rvm/gems/ruby-3.1.2/gems/karafka-1.4.13/lib/karafka/server.rb:6:in `<class:Server>': uninitialized constant Concurrent::Array (NameError)
@consumer_threads = Concurrent::Array.new
^^^^^^^
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/karafka-1.4.13/lib/karafka/server.rb:5:in `<module:Karafka>'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/karafka-1.4.13/lib/karafka/server.rb:3:in `<top (required)>'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/kernel.rb:27:in `require'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/kernel.rb:27:in `require'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/loader/helpers.rb:127:in `const_get'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/loader/helpers.rb:127:in `cget'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/loader.rb:239:in `block (2 levels) in eager_load'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/loader/helpers.rb:41:in `block in ls'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/loader/helpers.rb:27:in `each'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/loader/helpers.rb:27:in `ls'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/loader.rb:234:in `block in eager_load'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/loader.rb:219:in `synchronize'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.1/lib/zeitwerk/loader.rb:219:in `eager_load'
from <internal:kernel>:90:in `tap'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/karafka-1.4.13/lib/karafka.rb:70:in `<top (required)>'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/karafka-1.4.13/bin/karafka:3:in `require'
from /Users/karol/.rvm/gems/ruby-3.1.2/gems/karafka-1.4.13/bin/karafka:3:in `<top (required)>'
from /Users/karol/.rvm/gems/ruby-3.1.2/bin/karafka:25:in `load'
from /Users/karol/.rvm/gems/ruby-3.1.2/bin/karafka:25:in `<main>'
from /Users/karol/.rvm/gems/ruby-3.1.2/bin/ruby_executable_hooks:22:in `eval'
from /Users/karol/.rvm/gems/ruby-3.1.2/bin/ruby_executable_hooks:22:in `<main>'
Based on the changelog, it looks like Zeitwerk has been recently introduced so probably it's related to that, but don't know yet what exactly went wrong that causes the issue for concurrent-ruby.
In sub classes, if I extend Dry::Configurable again by mistake, the super class settings will be clear, such as the code following:
require 'dry-configurable'
# super class Daughter
class Daughter
extend Dry::Configurable
setting :name, 'Daughter'
setting :sex, 'female'
setting :age, 10
end
# sub class Cherry
class Cherry < Daughter
setting :name, 'Cherry'
end
# sub class Kimi, extend again by mistake
class Kimi < Daughter
extend Dry::Configurable
setting :name, 'Kimi'
end
and the result in console, it will:
>> Daughter.config.to_h
=> {:name=>"Daughter", :sex=>"female", :age=>10}
>> Cherry.config.to_h
=> {:name=>"Cherry", :sex=>"female", :age=>10}
>> Kimi.config.to_h
=> {:name=>"Kimi"}
the Kimi config, default settings 'sex', 'age' is cleared, and only name is valid.
the souce of self.extended is:
module Configurable
# @private
def self.extended(base)
base.class_eval do
@_config_mutex = ::Mutex.new
@_settings = ::Concurrent::Array.new
end
end
...
end
Describe the bug
Since upgrading to 0.11.3, config#update does not return self.
NoMethodError: undefined method `test' for {}:Hash
To Reproduce
require 'dry-configurable'
class App
include Dry::Configurable
setting :foo
end
app = App.new
config = app.config.update(foo: 'bar')
puts config.foo
# => undefined method `foo' for {:foo=>"bar"}:Hash
Expected behavior
Should return the config object as documented and as 0.8 did.
require 'dry-configurable'
class App
include Dry::Configurable
setting :foo
end
app = App.new
config = app.config.update(foo: 'bar')
puts config.foo
# => bar
Your environment
Would you be open to a PR to add a to_h
method to config allowing:
App.configure do |config|
config.database.dsn = 'jdbc:sqlite:memory'
end
App.config.to_h # => { dsn: 'jdbc:sqlite:memory' }
This would allow me to output all the configuration to the display without having to know all the keys.
By the way I could swear this used to be possible in an earlier version :)
EDIT: I think an earlier version might have used Struct
which provided the to_h
method.
This would better support the use case in dry-rb/dry-system#162 (see dry-rb/dry-system#162 (comment) for specific notes), in which all the settings from one class are "imported" into another for use there too.
Currently, this is done like so:
AnotherConfigurableThing._settings.each do |setting|
_settings << setting.dup
end
But it would be nicer to do it like this:
_settings.replace(AnotherConfigurableThing._settings.dup)
Describe the bug
This is a regression between versions 0.11.5 and 0.11.6. When you instantiate multiple instances of a class that include Dry::Configurable
, the default values specified in the setting
block are memoized between the instances.
I'm including a simplified reproduction script based on an issue with https://github.com/karafka/waterdrop/.
You can instantiate multiple WaterDrop consumers, each with different settings. WaterDrop has a default monitor
(based on dry-monitor
), which is instantiated by dry-configurable
.
We subscribe to each consumer's monitor so that we can publish instrumentation metrics:
listener = KafkaStatsdListener.new
publisher.monitor.subscribe(listener)
publisher2.monitor.subscribe(listener)
This works fine with 0.11.5, but with 0.11.6 the messages from the monitor are duplicated.
To Reproduce
require 'dry-configurable'
require 'dry/configurable/version'
MyMonitor = Class.new
class Producer
include Dry::Configurable
setting(:monitor, false) { |monitor| monitor || MyMonitor.new }
end
producer1 = Producer.new
producer2 = Producer.new
puts "dry-configurable version: #{Dry::Configurable::VERSION}"
puts producer1.config.monitor.object_id == producer2.config.monitor.object_id
Output:
dry-configurable version: 0.11.6
true
Expected behavior
dry-configurable version: 0.11.5
false
I have tried to come out with a code to fix it, but I have been unable to.
This is the failing case:
RSpec.describe Dry::Configurable do
context 'with nested configuration' do
let(:base_klass) do
Class.new do
extend Dry::Configurable
setting :nested do
setting :thing, 'from base klass'
end
end
end
let(:klass) do
Class.new(base_klass) do
configure do |k|
k.nested.thing = 'from klass'
end
end
end
let(:other_klass) do
Class.new(base_klass) do
configure do |k|
k.nested.thing = 'from other klass'
end
end
end
it 'subclasses do not clobber each other' do
expect(klass.config.nested.thing).to eq 'from klass'
expect(other_klass.config.nested.thing).to eq 'from other klass'
# the following fails, as it has been then changed by the configure block
# of other_klass.
expect(klass.config.nested.thing).to eq 'from klass'
end
it 'subclasses respect superclass own config' do
expect(base_klass.config.nested.thing).to eq 'from base klass'
expect(klass.config.nested.thing).to eq 'from klass'
# the following fails, as it has been then changed by the configure block
# of klass.
expect(base_klass.config.nested.thing).to eq 'from base klass'
end
end
end
(added in gist https://gist.github.com/saverio-kantox/67d424acb56908bace5fd67f003d5910 too)
Basically the last subclass that has its nested thing
touches, win, and all the others will get the same value.
Environment:
require 'dry-configurable'
class App
extend Dry::Configurable
setting :nested do
setting :foo, 'bar'
end
setting :deeply_nested do
setting :foo do
setting :bar, 'baz'
end
end
end
Expected behaviour:
App.config.finalize! # or App.finalize!
App.config.nested.foo = 'oops'
# => Dry::Configurable::FrozenConfig: Cannot modify frozen config
App.config.deeply_nested.foo.bar = 'oops'
# => Dry::Configurable::FrozenConfig: Cannot modify frozen config
Right now, however, no errors are raised and we can easily modify the config.
RIght now, the suggested way to test configurable classes looks like this:
require "dry/configurable/test_interface"
# this is your module/class that extended by Dry::Configurable
module AwesomeModule
enable_test_interface
end
before(:all) { AwesomeModule.reset_config }
# or
before(:each) { AwesomeModule.reset_config }
I don't like this approach for several reasons:
reset
and before
/after
hooksI suggest an interface that accepts a block, updates the config, then brings it back as it was.
around do |example|
stub_configurable(described_class, value_one: 1, nested_value: { key: :value }) do
example.run
end
end
If the param syntax is too complex, we can break it down to something like this:
around do |example|
stub_configurable(described_class) do |configurable|
configurable.config.value_one = 1
configurable.config.nested_value.key = :value
example.run
end
end
or just like this:
around do |example|
stub_configurable(described_class) do
described_class.config.value_one = 1
described_class.config.nested_value.key = :value
example.run
end
end
N/A
I'd like to understand a little bit more about the thread-safety claim, since a test program I wrote (inspired from https://www.yegor256.com/2018/11/06/ruby-threads.html) is returning a random sum on every program invocation, while without threads the result is stable.
Given this code:
class Program
extend Dry::Configurable
setting :counter
def self.call; new.call; end
def call
self.class.config.counter = 1
2.times.map do
Thread.new do
50.times do
number_value = self.class.config.counter
sleep(0.001)
self.class.config.counter = self.class.config.counter + number_value
end
end
end.each(&:join)
self.class.config.counter
end
end
Program.call
Return value should be 1267650600228229401496703205376
, which is what you get when you comment the Thread.new do
and end.each(&:join)
lines above, so no Threads are involved.
Return is random:
Program.call
=> 927372692193078999176
Program.call
=> 1052337743009943038933
Program.call
=> 927372692193078999176
Program.call
=> 1052338402766319185501
Program.call
=> 1116795285174159114038
Describe the bug
When using setting :settings, reader: true
I was previously able to access
the setting with:
config.settings.my_setting_name
Now it's:
config.settings[:settings].value.my_setting_name
To Reproduce
More information on Zulip: https://dry-rb.zulipchat.com/#narrow/stream/191662-general/topic/dry-system/near/188358017
Expected behavior
The previous behaviour.
Your environment
Sometimes you may want to pre-process a value, ie:
class Foo
extend Dry::Configurable
setting :path { |value| Pathname(value) }
end
As described in #27, @GustavoCaso is working on this in #28
Dry validation combined with dry-configurable:0.13.0
raises a Dry::Schema::MissingMessageError
exception when the validated attribute is an enum and the actual value isn't one of the listed enums.
This doesn't happen with versions < 0:.13, and although I can't be certain, it stands to reason that the issue is in this gem.
# frozen_string_literal: true
gem 'dry-configurable', '< 0.13' # passes
# gem 'dry-configurable', '= 0.13.0' # fails
require 'dry-validation'
require 'rspec/autorun'
module Types
include Dry::Types()
end
class Contract < Dry::Validation::Contract
params do
required(:arg).value(Types::Coercible::String.enum('foo', 'bar'))
end
end
describe 'dry-validation' do
let(:contract) { Contract.new }
let(:validation) { contract.(arg: nil) } # or arg: 'xxx'
subject(:error) { validation.errors.first }
it 'reports validation errors as messages' do
expect(error).not_to be_nil
expect(error.path).to eq [:arg]
expect(error.text).to eq 'must be one of: foo, bar'
end
end
relevant error output
Dry::Schema::MissingMessageError:
Message template for :arg under "" was not found. Searched in:
"en.dry_validation.errors.rules.arg.included_in?.arg."
"en.dry_validation.errors.rules.arg.included_in?"
"en.dry_validation.errors.included_in?.failure"
"en.dry_validation.errors.included_in?.value.arg"
"en.dry_validation.errors.included_in?.value.string.arg."
"en.dry_validation.errors.included_in?.value.string"
"en.dry_validation.errors.included_in?.arg."
"en.dry_validation.errors.included_in?"
No exception raised. See above.
Shouldn't be environment-specific, but anyhow:
I'm getting a weird exception from dry-web/system with 0.7.0:
/Users/solnic/.gem/ruby/2.4.1/gems/dry-configurable-0.7.0/lib/dry/configurable.rb:167:in `raise_frozen_config': Cannot modify frozen config (Dry::Configurable::FrozenConfig)
from /Users/solnic/.gem/ruby/2.4.1/gems/dry-configurable-0.7.0/lib/dry/configurable.rb:69:in `configure'
from /Users/solnic/.gem/ruby/2.4.1/gems/dry-system-0.7.3/lib/dry/system/container.rb:99:in `configure'
from /Users/solnic/.gem/ruby/2.4.1/gems/dry-web-0.7.1/lib/dry/web/container.rb:15:in `configure'
It doesn't modify any strings, it just calls configure
for the second time.
As the title says.
Example:
class App
extend Dry::Configurable
setting :logger
setting :production, if: -> { ENV['RACK_ENV'] == 'production' } do
end
end
App.configure do |config|
config.logger = { level: :debug }
config.production do
config.logger = { level: :info }
end
end
In some case, we need to call the 'config' method before setting some key-value pairs, such as following:
require 'dry-configurable'
class Daughter
extend Dry::Configurable
setting :name, 'Daughter'
setting :events, {aa: [1, 2, 3], bb: [4, 5, 6], cc: [7, 8, 9]}
end
# define class methods from the config.events
module ActionsDefinition
def self.included(base)
base.class_eval {
config.events.map { |event, params|
define_singleton_method(event) {
puts format('event: %{event}, params: %{params}', event: event, params: params)
}
}
}
end
end
class Eden < Daughter
include ActionsDefinition
setting :name, 'Eden'
end
the Eden config, set name to 'Eden' is invalid:
>> Eden.config.to_h
=> {:name=>"Daughter", :events=>{:aa=>[1, 2, 3], :bb=>[4, 5, 6], :cc=>[7, 8, 9]}}
the souce of self.config is:
def config
return @_config if defined?(@_config)
@_config_mutex.synchronize do
@_config ||= ::Dry::Configurable::Config.create(_settings) unless _settings.empty?
end
end
it seems that, after the 'config' method is called, the settings is freezed, right?
require "dry-configurable"
class A
include Dry::Configurable
end
A.new.setting :some_key, :some_value #=> NoMethodError: undefined method `<<' for nil:NilClass
Looks like it is unexpected behaviour
Describe the bug
Before the update to 0.11, a setting could be referenced via a string through config.[]
. Now it must be a symbol, otherwise the setting is not found.
I'd like to know if it's desired behavior. If not, I can send a patch myself.
To Reproduce
class A
extend Dry::Configurable
setting :foo, :bar
end
A.config[:foo]
# => :bar
A.config["foo"]
# => ArgumentError (+foo+ is not a setting name)
Expected behavior
A.config["foo"]
# => :bar
Your environment
Affects two gems I maintain:
waiting-for-dev/warden-jwt_auth#21
waiting-for-dev/devise-jwt#159
I've been working on extracting Dry::Types::Struct
to its own project. I made this change to the gemspec so I could use Dry::Struct::VERSION
:
diff --git i/dry-struct.gemspec w/dry-struct.gemspec
index a875711..038f209 100644
--- i/dry-struct.gemspec
+++ w/dry-struct.gemspec
@@ -1,5 +1,8 @@
# coding: utf-8
+root = File.expand_path(__dir__)
+require File.join(root, 'lib/dry/struct/version.rb')
+
Gem::Specification.new do |spec|
spec.name = 'dry-struct'
spec.version = '0.0.1'
This bundles fine but causes a strange issue when I run the tests:
$ bundle exec rspec
/Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-configurable-0.1.6/lib/dry/configurable.rb:53:in `initialize': wrong number of arguments (given 3, expected 0) (ArgumentError)
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-configurable-0.1.6/lib/dry/configurable.rb:53:in `new'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-configurable-0.1.6/lib/dry/configurable.rb:53:in `block in config'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-configurable-0.1.6/lib/dry/configurable.rb:51:in `synchronize'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-configurable-0.1.6/lib/dry/configurable.rb:51:in `config'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-container-0.3.4/lib/dry/container/mixin.rb:91:in `register'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-logic-0.3.0/lib/dry/logic/predicate_set.rb:9:in `predicate'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-logic-0.3.0/lib/dry/logic/predicates.rb:18:in `<module:Predicates>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-logic-0.3.0/lib/dry/logic/predicates.rb:9:in `<module:Logic>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-logic-0.3.0/lib/dry/logic/predicates.rb:8:in `<module:Dry>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-logic-0.3.0/lib/dry/logic/predicates.rb:7:in `<top (required)>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types/constraints.rb:2:in `require'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types/constraints.rb:2:in `<top (required)>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types/constrained.rb:2:in `require'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types/constrained.rb:2:in `<top (required)>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types/builder.rb:51:in `require'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types/builder.rb:51:in `<top (required)>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types/definition.rb:1:in `require'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types/definition.rb:1:in `<top (required)>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types.rb:13:in `require'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry/types.rb:13:in `<top (required)>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry-types.rb:1:in `require'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/dry-types-0.8.1/lib/dry-types.rb:1:in `<top (required)>'
from /Users/johnbackus/Projects/dry-struct/lib/dry/struct.rb:1:in `require'
from /Users/johnbackus/Projects/dry-struct/lib/dry/struct.rb:1:in `<top (required)>'
from /Users/johnbackus/Projects/dry-struct/lib/dry-struct.rb:1:in `require'
from /Users/johnbackus/Projects/dry-struct/lib/dry-struct.rb:1:in `<top (required)>'
from /Users/johnbackus/Projects/dry-struct/spec/spec_helper.rb:14:in `require'
from /Users/johnbackus/Projects/dry-struct/spec/spec_helper.rb:14:in `<top (required)>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1295:in `require'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1295:in `block in requires='
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1295:in `each'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1295:in `requires='
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration_options.rb:109:in `block in process_options_into'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration_options.rb:108:in `each'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration_options.rb:108:in `process_options_into'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration_options.rb:21:in `configure'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:105:in `setup'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:92:in `run'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:78:in `run'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:45:in `invoke'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/gems/rspec-core-3.4.4/exe/rspec:4:in `<top (required)>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/bin/rspec:22:in `load'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/bin/rspec:22:in `<main>'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `eval'
from /Users/johnbackus/.rvm/gems/ruby-2.3.0/bin/ruby_executable_hooks:15:in `<main>'
I haven't used dry-configurable before and I am only using it now because it is part of the code I am extracting from dry-types so sorry if this is a basic issue. I'm currently pretty stumped though since the version file itself is pretty simple:
module Dry
class Struct
VERSION = '0.0.1'.freeze
end
end
The only place that dry-configurable is used is in the extracted errors module:
module Dry
class Struct
extend Dry::Configurable
setting :namespace, self
Error = Class.new(TypeError)
class RepeatedAttributeError < ArgumentError
def initialize(key)
super("Attribute :#{key} has already been defined")
end
end
end
end
Here is the dry-* in question:
$ cat Gemfile.lock | grep 'dry-'
dry-struct (0.0.1)
dry-configurable (~> 0.1)
dry-equalizer (~> 0.2)
dry-logic (~> 0.2, >= 0.2.3)
dry-types (~> 0.8, >= 0.8.1)
dry-configurable (0.1.6)
dry-container (0.3.4)
dry-configurable (~> 0.1, >= 0.1.3)
dry-equalizer (0.2.0)
dry-logic (0.3.0)
dry-container (~> 0.2, >= 0.2.6)
dry-equalizer (~> 0.2)
dry-monads (0.0.2)
dry-types (0.8.1)
dry-configurable (~> 0.1)
dry-container (~> 0.3)
dry-equalizer (~> 0.2)
dry-logic (~> 0.3, >= 0.3.0)
dry-monads (>= 0.0.1)
dry-struct!
I tried pointing to dry-configurable master but the issue remained.
Describe the bug
We use dry-configurable
in our Rails project. In 0.9 we had no problems but since the upgrade to 0.11 we get the following error:
NameError: undefined method `config' for class `App'
After a little bit of digging I found out that it is only a problem the second time we define the class (That the class is redefined twice at all could be a Rails autoloading thing).
To Reproduce
require 'dry-configurable'
class App
include Dry::Configurable
setting :test
end
# => App
class App
include Dry::Configurable
setting :test
end
# => NameError: undefined method `config' for class `App'
# from .../ruby-2.6.5/gems/dry-configurable-0.11.3/lib/dry/configurable.rb:60:in `singleton class'
Expected behavior
(dry-configurable v0.9 behavior, also notice the different return value (nil instead of App))
require 'dry-configurable'
class App
include Dry::Configurable
setting :test
end
# => nil
class App
include Dry::Configurable
setting :test
end
# => nil
Your environment
v0.16.0
release affects "dry-validation"
.
Please, check this GitHub Actions run:
Open irb
for Ruby 3.1.
irb
Try to require "dry-validation"
.
require "dry-validation"
Check the following screenshot to see what happens:
"dry-validation"
version - v1.5.6
.
"dry-schema"
version - v1.10.6
.
"dry-configurable"
version - v0.16.0
.
As it was in v0.15.0
. A successful require
.
v0.1.0
of convenient_service (that may depend on dry-validation) at the beginning of November.I've found myself doing that a lot:
class Foo
extend Dry::Configurable
setting :something
def self.something
config.something
end
end
WDYT about this:
class Foo
extend Dry::Configurable
setting :something, reader: true
end
Describe the bug
dry-configurable does not work from a trap context
To Reproduce
Run the following script and press CTRL+C to stop it:
require 'dry/configurable'
class App
extend Dry::Configurable
setting :adapter, 'lol'
end
def trap_signal
trap("INT") do
p App.config.adapter
exit
end
end
trap_signal
sleep
Output:
^CTraceback (most recent call last):
14: from run.rb:18:in `<main>'
13: from run.rb:18:in `sleep'
12: from run.rb:11:in `block in trap_signal'
11: from dry-configurable-0.11.5/lib/dry/configurable/class_methods.rb:72:in `config'
10: from dry-configurable-0.11.5/lib/dry/configurable/class_methods.rb:72:in `new'
9: from dry-configurable-0.11.5/lib/dry/configurable/config.rb:26:in `initialize'
8: from dry-configurable-0.11.5/lib/dry/configurable/config.rb:26:in `dup'
7: from dry-configurable-0.11.5/lib/dry/configurable/config.rb:26:in `initialize_dup'
6: from dry-configurable-0.11.5/lib/dry/configurable/settings.rb:61:in `initialize_copy'
5: from dry-configurable-0.11.5/lib/dry/configurable/settings.rb:66:in `initialize_elements'
4: from dry-configurable-0.11.5/lib/dry/configurable/settings.rb:66:in `each_with_object'
3: from dry-configurable-0.11.5/lib/dry/configurable/settings.rb:66:in `each'
2: from dry-configurable-0.11.5/lib/dry/configurable/settings.rb:67:in `block in initialize_elements'
1: from concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb:18:in `[]='
concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb:18:in `synchronize': can't be called from trap context (ThreadError)
Expected behavior
The system should print the config value and exit
Your environment
Bypass
Spawning a thread to bypass the trap context works but it's rather clumsy:
p Thread.new { App.config.adapter }.join.value
I'm developing a gem that uses dry-configurable. In order to test it, I need to change some default settings in before
hooks. I found that changed settings persist in subsequent tests. For that reason, I think I would need some reset
method in order to apply it in after
hooks.
What do you think about it? Would it be difficult to implement or does it have any drawback?
(version 0.7.0)
Preprocessor is not used for initial nil value.
Example:
any_key
- with initial nil valueanother_key
- with explicit default valueclass A
extend Dry::Configurable
setting(:any_key) { |value| "empty value" }
setting(:another_key, 25) { |value| "#{value} number" }
end
A.config.any_key # => nil # [BUG] Initial `nil` value, not preprocessed.
A.config.any_key # => nil # still not using a pre-processor
A.config.any_key = 25
A.config.any_key # => "empty value"
A.config.any_key = nil
A.config.any_key # => "empty_value" (each next invocations uses a pre-processor after redifinition)
A.config.another_key # => "25 number"
Bug?
We already have a writer pre-processor:
setting(:file) { |value| Pathname(value) }
But now, I'm in a use case where a reader pre-processor could also be useful. In my case I would like to throw an error if an important setting is not set. I think it would be nice to do it in the configuration layer, because it is its outermost boundary.
I see that having a setting with both writer and reader pre-processors could look a bit clumsy:
setting(:file,
reader: ->(value) { value || raise('+file+ setting must be defined') }
) { |value| Pathname(value) }
If we are not in a "don't break backwards compatibility" phase, we could instead do:
setting(:file,
reader: ->(value) { value || raise('+file+ setting must be defined') },
writer: ->(value) { Pathname(value) })
Or, in order not to break compatibility, we could make a single block default to a writer pre-processor.
What do you think about it?
This is something @solnic mentioned a while ago as a change he'd like to see for 1.0.0. Opening this so we can have the discussion as whether this is something we still want.
Right now default:
value is evaluated at the time of declaration, so object is always created. For karafka logger
setting :logger, ::Karafka::Instrumentation::Logger.new
this caused issues with initialization on RO filesystem (1, 2) even if non-default logger was passed.
In waterdrop it's kinda workarounded via
setting(:logger, false) { |logger| logger || Logger.new($stdout, level: Logger::WARN) }
but it's unnecessary complication and with real constructor would be even less readable.
require 'dry-configurable'
RAISE_EXCEPTION = -> { raise }
class Config
include Dry::Configurable
setting :default_failure, default: RAISE_EXCEPTION.call
end
Some API that would allow to skip default value initialization if non-default one is passed
require 'dry-configurable'
RAISE_EXCEPTION = -> { raise }
class Config
include Dry::Configurable
setting :default_failure, default: -> { RAISE_EXCEPTION.call }
end
Config.new(default_failure: 'does not fail')
require 'dry-configurable'
class Application
extend Dry::Configurable
setting :class, 'SimpleStrategy'
end
Application.config
Traceback (most recent call last):
13: from tst.rb:11:in `<main>'
12: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable.rb:148:in `config'
11: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/config.rb:57:in `define!'
10: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/config.rb:57:in `synchronize'
9: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/config.rb:61:in `block in define!'
8: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/config.rb:148:in `set_values!'
7: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/settings.rb:63:in `each'
6: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/settings.rb:63:in `each'
5: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/settings.rb:63:in `block in each'
4: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/config.rb:155:in `block in set_values!'
3: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/config.rb:57:in `define!'
2: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/config.rb:57:in `synchronize'
1: from /home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/config.rb:61:in `block in define!'
/home/jtzero/.asdf/installs/ruby/2.6.1/lib/ruby/gems/2.6.0/gems/dry-configurable-0.8.3/lib/dry/configurable/config.rb:148:in `set_values!': undefined method `settings' for nil:NilClass (NoMethodError)
When the extension is included in a class more than once, you end up with a confusing exception.
To Reproduce
Class.new.include(Dry::Configurable).include(Dry::Configurable)
NameError: undefined method `config' for class `#<Class:0x00007fa984607810>'
Expected behavior
A more meaningful exception should be raised explaining that you should not include the same extension more than once.
Refs #88
I'm trying to declare a configuration with the following structure (in YAML notation)
...
endpoints:
- url: "https://host1.domain.com"
priority: 1
- url: "https://host2.domain.com"
priority: 2
...
Am I missing something or it's not possible to declare a setting
of an array type?
Something like this:
setting :endpoints do
setting :url
setting :priority
end
Thanks
First of all, I wanted to thank the core crew for the fantastic work. I am really enjoying using most of the dry-rb
gems in my most recent projects.
However, particularly with RSpec, and since the gem sets the <Module>.config
at the module level, I was unable to find an easy way to reset my config back its original state at the beginning of each test. I don't have the defaults specified everywhere, so some fields should become nil, and I couldn't find an easy way of doing that.
Any chance you can either suggest how I go about submitting a PR, or perhaps you can suggest an existing solution?
Thanks!
In other words - make dry-struct
dependency optional and turn existing functionality into an extension using Dry::Core::Extensions
.
Currently the default value is set by the second argument passed to setting, this should be updated to use a keyword argument (i.e. :default
)
Currently if you try to define a setting after config has been created it will just be dropped silently, we should raise if setting
is called after create_config
Will there be a support for lazy loaded default options values? I have some settings that if not set, should be set from proc during runtime (with first invocation)
When you load configuration from, say, a YAML file, you already have a hash. It would be awesome to have a method that automatically recurs into the hash assigning configuration:
hash = YAML.load_file('config/database.yaml')
MyConfigurableClass.config.load_hash(hash)
https://github.com/dry-rb/dry-configurable/releases/tag/v0.2.0 on release page. But in version file 0.1.7
Sorry, I don't have the right terms to describe this clearly.
The value of a setting defined with a constructor
was stable in 0.15.0. You could call your setting from anywhere in your application and get the same value. What constructor
is for and how it behaves is not explained in the documentation, but my understanding from using it was that it would be called the first time you accessed the setting, to set the initial value or update the default value.
In 0.16.0, the constructor
seems to be called every time you access the setting in your application.
I have provided two scripts in this Gist. They are identical except for the dry-configurable
version specified in the inline gemfile block.
It defines a dummy class called Something
. Then it defines a module called App
that extends Dry::Configurable and defines a setting named thing
, with a constructor proc that creates a new Something
. Then it calls App.thing
twice and puts the object_id of each.
Run ruby dry-config-15.rb
.
Then run ruby dry-config-16.rb
.
Without any mention of changed behavior in the CHANGELOG, I expect to get the same instance of the Something
object when I call App.thing
:
❯ ruby dry-config-15.rb
1160
1160
Instead I get 2 separate instances of the object when I call App.thing
subsequently:
❯ ruby dry-config-16.rb
1060
1080
This side effect may be implied by "Improve memory usage by separating setting definitions from config values", but it's really not clear, and it breaks things even if you are not "accessing objects from _settings
or the internals of Dry::Configurable::Config
"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.