This library officially supports the following Ruby versions:
- MRI
>= 3.0.0
- jruby
>= 9.4
(not tested on CI)
See LICENSE
file.
A simple, configurable object container implemented in Ruby
Home Page: https://dry-rb.org/gems/dry-container
License: MIT License
This library officially supports the following Ruby versions:
>= 3.0.0
>= 9.4
(not tested on CI)See LICENSE
file.
Hi,
There are test failures when tried to build on a Debian system.
Here are the logs:
┌──────────────────────────────────────────────────────────────────────────────┐
│ Run tests for ruby2.5 from debian/ruby-tests.rake │
└──────────────────────────────────────────────────────────────────────────────┘
RUBYLIB=. GEM_PATH=debian/ruby-dry-container/usr/share/rubygems-integration/all:/home/utkarsh/.gem/ruby/2.5.0:/var/lib/gems/2.5.0:/usr/lib/ruby/gems/2.5.0:/usr/share/rubygems-integration/2.5.0:/usr/share/rubygems-integration/all:/usr/lib/x86_64-linux-gnu/rubygems-integration/2.5.0 ruby2.5 -S rake -f debian/ruby-tests.rake
/usr/bin/ruby2.5 /usr/bin/rspec --pattern ./spec/\*\*/\*_spec.rb --format documentation
An error occurred while loading ./spec/spec_helper.rb.
Failure/Error:
Dir[Pathname(__FILE__).dirname.join('support/**/*.rb').to_s].each do |file|
require file
end
NoMethodError:
undefined method `Pathname' for main:Object
# ./spec/spec_helper.rb:102:in `<top (required)>'
An error occurred while loading ./spec/integration/container_spec.rb.
Failure/Error: it_behaves_like 'a container'
ArgumentError:
Could not find shared examples "a container"
# ./spec/integration/container_spec.rb:5:in `block in <top (required)>'
# ./spec/integration/container_spec.rb:1:in `<top (required)>'
An error occurred while loading ./spec/integration/container_spec.rb.
Failure/Error: it_behaves_like 'a container'
ArgumentError:
Could not find shared examples "a container"
# ./spec/integration/container_spec.rb:5:in `block in <top (required)>'
# ./spec/integration/container_spec.rb:1:in `<top (required)>'
An error occurred while loading ./spec/integration/mixin_spec.rb.
Failure/Error: it_behaves_like 'a container'
ArgumentError:
Could not find shared examples "a container"
# ./spec/integration/mixin_spec.rb:8:in `block (2 levels) in <top (required)>'
# ./spec/integration/mixin_spec.rb:2:in `block in <top (required)>'
# ./spec/integration/mixin_spec.rb:1:in `<top (required)>'
An error occurred while loading ./spec/integration/mixin_spec.rb.
Failure/Error: it_behaves_like 'a container'
ArgumentError:
Could not find shared examples "a container"
# ./spec/integration/mixin_spec.rb:8:in `block (2 levels) in <top (required)>'
# ./spec/integration/mixin_spec.rb:2:in `block in <top (required)>'
# ./spec/integration/mixin_spec.rb:1:in `<top (required)>'
No examples found.
No examples found.
Randomized with seed 63721
Randomized with seed 63721
Top 0 slowest examples (0 seconds, 0.0% of total time):
Finished in 0.00025 seconds (files took 0.17628 seconds to load)
0 examples, 0 failures, 3 errors occurred outside of examples
Finished in 0.00025 seconds (files took 0.17628 seconds to load)
0 examples, 0 failures, 3 errors occurred outside of examples
Randomized with seed 63721
Randomized with seed 63721
/usr/bin/ruby2.5 /usr/bin/rspec --pattern ./spec/\*\*/\*_spec.rb --format documentation failed
ERROR: Test "ruby2.5" failed. Exiting.
I thinking about preparation of PR for addition of interceptors. It would be interested to know how likely PR with this kind of feature could be merged.
This feature already present in different implementations of containers in Ruby and other languages.
Essentially this is a wrapper around instance of service added before returning the service to a client.
Interceptors are great way to implement service instantiation tracers, loggers, exception handlers, authorization checks and many other auxiliary functionality which correspond the instance.
When attempting to install dry-container 0.8.0 on JRuby, I'm consistently getting an error:
ERROR: Error installing dry-container:
dry-container-0.8.0 requires Ruby version >= 2.6.0. The current ruby version is 2.5.7.0.
dry-core
, which has similar code in the gemspec, installs fine.
jruby -S gem install dry-container --version 0.8.0
dry-container
0.8.0 is installed
I checked it with JRuby versions 9.2.16.0 and 9.2.17.0 on Linux and Mac. Tried gem update --system
but did not help.
The only thing I see is that in dry-container rubygems page required ruby version on the right is >= 2.6.0
while with dry-core it says >= 2.5.0
. So maybe a wrong file was pushed to RubyGems somehow?
Hi! Thanks for a great gem!
I have a question regarding testing. Is it possible to somehow unregister objects from the registry? I have a problem with leaking test object added to the registry.
Before I had this code:
require 'dry/container/stub'
Fortnox::API::Registry.enable_stubs!
Fortnox::API::Registry.stub(:test, Model::Test)
Now I get an error: cannot stub "test" - no such key in container
. When I try adding the test
object to the registry before stubbing, as you suggest in the documentation, the first test passes but the second fails with:
Dry::Container::Error:
There is already an item registered with the key "test"
Also, I found below code in your own test suite. Unfortunately, I cannot do the same in my test since my registry includes other objects that I do not want to throw away :)
after do
# HACK: Have to reset the configuration so that it doesn't
# interfere with other specs
klass.configure do |config|
config.registry = Dry::Container::Registry.new
end
end
I think it'll be helpful to store some meta-information about dependency in a container. Some ideas where you can use this information:
container.register('users.repositories.users', only_in: 'users.operations.*') { ... }
module Books
module Operations
class Create
include Import['users.repositories.users'] # => raise error on booting
end
end
end
WDYT? I can implement simple PoC for meta information, and after that we can start play with it if you like the idea
Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-container-0.11.0/lib/dry/container/mixin.rb:155:in `register': undefined method `call' for {:default=>#<Dry::Container::Registry:0x0000000104e2c458 @_mutex=#<Thread::Mutex:0x0000000104e2c368>>}:Hash (NoMethodError)
config.registry.call(_container, key, item, options)
^^^^^
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject/strategies/args.rb:72:in `<class:Strategies>'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject/strategies/args.rb:8:in `<module:AutoInject>'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject/strategies/args.rb:7:in `<module:Dry>'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject/strategies/args.rb:6:in `<top (required)>'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject/strategies.rb:19:in `require'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject/strategies.rb:19:in `<top (required)>'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject/builder.rb:3:in `require'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject/builder.rb:3:in `<top (required)>'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject.rb:3:in `require'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/dry-auto_inject-0.9.0/lib/dry/auto_inject.rb:3:in `<top (required)>'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/warden-jwt_auth-0.5.0/lib/warden/jwt_auth.rb:4:in `require'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/warden-jwt_auth-0.5.0/lib/warden/jwt_auth.rb:4:in `<top (required)>'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-jwt-0.8.1/lib/devise/jwt.rb:6:in `require'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/devise-jwt-0.8.1/lib/devise/jwt.rb:6:in `<top (required)>'
from /Users/macbookpro/Desktop/development/dashboard/config/application.rb:5:in `require'
from /Users/macbookpro/Desktop/development/dashboard/config/application.rb:5:in `<top (required)>'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.4.3/lib/rails/commands/server/server_command.rb:137:in `require'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.4.3/lib/rails/commands/server/server_command.rb:137:in `block in perform'
from <internal:kernel>:90:in `tap'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.4.3/lib/rails/commands/server/server_command.rb:134:in `perform'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.4.3/lib/rails/command/base.rb:87:in `perform'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.4.3/lib/rails/command.rb:48:in `invoke'
from /Users/macbookpro/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/railties-7.0.4.3/lib/rails/commands.rb:18:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
A problem reported in this reddit thread
You should know that dry-container doesn't play well with activesupport tagged logging because of use of fibers. (Thread.current is fiber local, not thread local, and they rely on that)
https://travis-ci.org/dry-rb/dry-container/builds/167707810
Discovered when submitting PR #25.
Hello all,
I noticed that the following doesn't work:
class X
include Dry::Container::Mixin
def initialize
end
end
X.new.register :foo, -> {}
# =>
# NoMethodError: undefined method `key?' for nil:NilClass
# from /home/malte/.rbenv/versions/2.2.4/lib/ruby/gems/2.2.0/gems/dry-container-0.5.0/lib/dry/container/registry.rb:33:in `block in call'
More specifically, I wanted to register items in the initializer. Any reason why this was implemented this way, relying on the module being able to define the class initializer?
Thank you!
I ran into an problem writing a test with a stubbed container value where the container in question was empty when the test is run in isolation. This caused a hard-to-find issue where some code in dry-transaction
was calling #key?
on the container, and it was returning false
even though a stubbed value had been registered.
Is this something that should be supported, or is the current code right to assume that only existing registered values can be stubbed?
If we allow non-registered values to be stubbed, I think we'll either need a different approach to stubbing or the stubbing API will need to be fleshed out to better support the full API of Dry::Container::Mixin
.
Using the current code and documentation, a container having a custom resolver won't be able to use #keys
, #each
, #each_key
or #key?
, with the error that a Proc doesn't have those methods.
# current documentation for memory
class ContainerObject
include Dry::Container::Mixin
configure do |config|
config.registry = ->(container, key, item, options) { container[key] = item }
config.resolver = ->(container, key) { container[key] }
end
end
The workaround I found is by subclassing Dry::Container::Resolver like this:
class ResolverObject < Dry::Container::Resolver
def call(container, key)
container[key]
end
end
class ContainerObject
include Dry::Container::Mixin
configure do |config|
config.registry = ->(container, key, item, options) { container[key] = item }
config.resolver = ResolverObject.new
end
end
But I don't understand the benefit of having those four methods delegated to the resolver as they are methods of the container?
Relevant lines of code concerned:
I have been using dry-container
& dry-auto_inject
since use ruby 2.3, everything works well until ruby 2.7, when I try upgrade to ruby 3.0 I'm getting an ArgumentError
missing keywords.
ArgumentError (wrong number of arguments (given 1, expected 0; required keywords: status_message, data, meta)):
app/services/version1/list_result.rb:7:in `initialize'
Ruby <= 2.7 & Rails <= 6.1.x ✅
Ruby 3.0.1 & Rails 6.1.x ❌
class ListResult
attr_reader :status,
:status_message,
:data,
:meta
SUCCESS = 1
def initialize(status_message:, data:, meta:)
@status = SUCCESS
@status_message = status_message
@data = data
@meta = meta
end
end
try to Register
require 'dry-container'
require 'dry-auto_inject'
module MyClass
class DiContainer
extend Dry::Container::Mixin
register :list_result do
ListResult
end
end
# dependency injection
INJECT = Dry::AutoInject(MyClass::DiContainer)
end
Try inject to the service
require 'my_class/di_container'
module Version1
class MyService
include MyClass::INJECT[:list_result]
def get_data
list_result.new(status_message: '', data: [], meta: {})
end
end
end
Manual call without DI
ListResult.new(status_message: '', data: [], meta: {})
=> #<ListResult:0x00007f8d40a70970 @data=[], @meta={}, @status=1, @status_message="">
I think it would be useful to have a public API for mocking. Currently I mutate internal _container
object in a couple special places in my test suite where there's really no other way than to mock a dependency via container.
Looking for a way to memoize by default, since for my usage, not memoizing is more of a corner case.
Thanks :)
I have a use-case where I have several "parser" objects registered in a namespace within a container, and I'd like to iterate over each of those objects to find the first that works.
I have a container like this:
class MyContainer
extend Dry::Container::Mixin
namespace :parsers do
register(:first) { MyParser.new }
register(:another) { MyOtherParser.new }
register(:fallback) { MyFallbackParser.new }
end
namespace :more_things do
# ...
end
end
In my code, I want to try each one till I get one that works:
MyContainer
.namespaced(:parsers) # Something like this
.lazy
.map { |parser| parser.call }
.detect(&:success?)
.presence || Failure("no valid parser found")
I can work around it by doing:
MyContainer
.each
.select { |k,_| k.start_with? "parsers." }
.map(&:last)
... but that seems more cumbersome than it needs to be.
@solnic asked my to open a feature request from this convo in zulip.
After updating dry-container
from 0.8.0 to 0.10.0, I'm getting an ArgumentError missing keywords in mixin.rb
dry-container-0.10.0/lib/dry/container/mixin.rb:221:in `key?': wrong number of arguments (given 2, expected 1) (ArgumentError)
I have a dry system container that has dependencies organized by namespace. I also want to create keys for arrays of component types i can operate on with an enum. What would be the best way of doing this? Each dependency has a method like below so I can call the method in an aggregate way.
class Foo::Bar
def self.register!
Container.register('foo.bar', Foo::Bar)
bars = (Container['foo.bars'] rescue []) << Foo::Bar
Container.register('foo.bars', bars)
end
end
class Foo::Bar2
def self.register!
Container.register('foo.bar2', Foo::Bar2)
bars = (Container['foo.bars'] rescue []) << Foo::Bar2
Container.register('foo.bars', bars)
end
end
..
Foo::Bar.register!
Foo::Bar2.register!
Container.finalize!
OPTION 1 Container['foo.bars'] #should equal [Foo::Bar, Foo::Bar2]
OPTION 2 Container['foo'] #should equal [Foo::Bar, Foo::Bar2]
What would be a good way of achieving this in a dry fashion? Is this currently possible?
Given that Dry::Container::Resolver#key?
exists, I was anticipating that Dry::Container::Resolver#keys
would also exist.
I believe it would make sense to cast keys into strings
Right now the following happens if you switch between Symbols and Strings:
container = Dry::Container.new
container.register(:foo, 'bar')
container[:foo]
# => "bar"
container['foo']
# => Dry::Container::Error: Nothing registered with the key "foo"
The confusion appears when you start to namespace things, for example:
container = Dry::Container.new
container.namespace(:test) do
register(:foo, 'bar')
end
# Now it's a string
container['test.foo']
# => "bar"
I think it would be clearer if things got stored as strings by default.
If you think that's better I can push a PR with the change.
I'd like to be able to freeze a container after it is set up, so that it won't accept new keys anymore.
Right now, this works:
MyContainer._container.freeze
MyContainer.register("test", "bail")
FrozenError (can't modify frozen Concurrent::Hash)
But as the comment says, _container
is pretty private.
Is the above usage ok, or should the be a new feature?
Noticed, when trying to install Dry Container 0.8.0, that it doesn't exist. Only 0.7.2 is the latest version at the time of this writing. By the way, this seems to be an oddity with other Dry libraries in case it's of interest. It seems the generated documentation is ahead of what is available.
Visit the landing page (also notice 0.8
is in the URL as well). Here's a screenshot for illustration:
Would expect 0.7.2 to be listed instead of 0.8.0 as found on RubyGems.
Using Firefox as my browser.
Custom resolver using lambda examples are shown in the document .
But it seems that resolvers are supposed to respond to more messages other than #call
(cf. https://github.com/dry-rb/dry-container/blob/v0.6.0/lib/dry/container/resolver.rb , https://github.com/dry-rb/dry-container/blob/v0.6.0/lib/dry/container/mixin.rb ).
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.