dry-container 0.5.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +93 -6
- data/LICENSE +1 -1
- data/README.md +18 -158
- data/dry-container.gemspec +39 -23
- data/lib/dry-container.rb +3 -1
- data/lib/dry/container.rb +10 -10
- data/lib/dry/container/error.rb +3 -1
- data/lib/dry/container/item.rb +29 -22
- data/lib/dry/container/item/callable.rb +22 -0
- data/lib/dry/container/item/factory.rb +26 -0
- data/lib/dry/container/item/memoizable.rb +49 -0
- data/lib/dry/container/mixin.rb +90 -14
- data/lib/dry/container/namespace.rb +2 -0
- data/lib/dry/container/namespace_dsl.rb +8 -0
- data/lib/dry/container/registry.rb +9 -1
- data/lib/dry/container/resolver.rb +27 -4
- data/lib/dry/container/stub.rb +10 -3
- data/lib/dry/container/version.rb +3 -1
- metadata +16 -27
- data/.codeclimate.yml +0 -32
- data/.gitignore +0 -8
- data/.rspec +0 -3
- data/.rubocop.yml +0 -24
- data/.rubocop_todo.yml +0 -6
- data/.travis.yml +0 -31
- data/Gemfile +0 -15
- data/Rakefile +0 -12
- data/rakelib/rubocop.rake +0 -18
- data/spec/integration/container_spec.rb +0 -18
- data/spec/integration/mixin_spec.rb +0 -19
- data/spec/spec_helper.rb +0 -13
- data/spec/support/shared_examples/container.rb +0 -479
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 77e050044acc97600020d74da69d2b54a5788a61fcb84b7c9feba51068b2977e
|
4
|
+
data.tar.gz: d7aa97eea6849253f410414c12844f6c04baf4e4a3e9a58f2a26c0211f98ea89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd18bbb80600daf28c2ce1ce5ea4a24c688a1cfd7e21b365e3486cb871d5cd2065f4484123b0c5d016a9e637fb4fdc44208c6884bb4fd24a241e7c43d26175cd
|
7
|
+
data.tar.gz: 19d157a7db948b4663b9ced4d5db537cd0b43407afd8e8e852b203202863f8eba279a083d6d302b8cbe05899e5036b24465186683b8d5746f3fc63d3a5debfeb
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,98 @@
|
|
1
|
-
|
1
|
+
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
2
2
|
|
3
|
-
##
|
3
|
+
## 0.7.2 2019-07-09
|
4
4
|
|
5
|
-
* `memoize` option to `#register` - memoizes items on first resolve ([ivoanjo](https://github.com/ivoanjo))
|
6
5
|
|
7
|
-
|
6
|
+
### Added
|
8
7
|
|
9
|
-
|
8
|
+
- `.resolve` accepts an optional fallback block, similar to how `Hash#fetch` works ([flash-gordon](https://github.com/flash-gordon))
|
9
|
+
```ruby
|
10
|
+
container.resolve('missing_key') { :fallback } # => :fallback
|
11
|
+
```
|
12
|
+
- `.decorate` can (again) work with static values. Also, it can take a block instead of `with` ([flash-gordon](https://github.com/flash-gordon))
|
13
|
+
```ruby
|
14
|
+
container.register('key', 'value')
|
15
|
+
container.decorate('key') { |v| "<'#{v}'>" }
|
16
|
+
container.resolve('key') # => "<'value'>"
|
17
|
+
```
|
10
18
|
|
11
|
-
|
19
|
+
|
20
|
+
[Compare v0.7.1...v0.7.2](https://github.com/dry-rb/dry-container/compare/v0.7.1...v0.7.2)
|
21
|
+
|
22
|
+
## 0.7.1 2019-06-07
|
23
|
+
|
24
|
+
|
25
|
+
### Fixed
|
26
|
+
|
27
|
+
- Added `Mixin#dup` and `Mixin#clone`, now copies don't share underlying containers (flash-gordon)
|
28
|
+
|
29
|
+
|
30
|
+
[Compare v0.7.0...v0.7.1](https://github.com/dry-rb/dry-container/compare/v0.7.0...v0.7.1)
|
31
|
+
|
32
|
+
## 0.7.0 2019-02-05
|
33
|
+
|
34
|
+
|
35
|
+
### Added
|
36
|
+
|
37
|
+
- Namespace DSL resolves keys relative to the current namespace, see the corresponding [changes](https://github.com/dry-rb/dry-container/pull/47) ([yuszuv](https://github.com/yuszuv))
|
38
|
+
- Registered objects can be decorated with the following API ([igor-alexandrov](https://github.com/igor-alexandrov))
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
class CreateUser
|
42
|
+
def call(params)
|
43
|
+
# ...
|
44
|
+
end
|
45
|
+
end
|
46
|
+
container.register('create_user') { CreateUser.new }
|
47
|
+
container.decorate('create_user', with: ShinyLogger.new)
|
48
|
+
|
49
|
+
# Now subsequent resolutions will return a wrapped object
|
50
|
+
|
51
|
+
container.resolve('create_user')
|
52
|
+
# => #<ShinyLogger @obj=#<CreateUser:0x...>]>
|
53
|
+
```
|
54
|
+
- Freezing a container now prevents further registrations ([flash-gordon](https://github.com/flash-gordon))
|
55
|
+
- ## Internal
|
56
|
+
- Handling container items was generalized in [#34](https://github.com/dry-rb/dry-container/pull/34) ([GabrielMalakias](https://github.com/GabrielMalakias))
|
57
|
+
|
58
|
+
### Fixed
|
59
|
+
|
60
|
+
- Symbols are now coerced to strings when resolving stubbed dependencies ([cthulhu666](https://github.com/cthulhu666))
|
61
|
+
- Stubbing keys not present in container will raise an error ([flash-gordon](https://github.com/flash-gordon))
|
62
|
+
|
63
|
+
This means after upgrading you may see errors like this
|
64
|
+
```
|
65
|
+
ArgumentError (cannot stub "something" - no such key in container)
|
66
|
+
```
|
67
|
+
Be sure you register dependencies before using them. The new behavior will likely save quite a bit of time when debugging ill-configured container setups.
|
68
|
+
|
69
|
+
### Changed
|
70
|
+
|
71
|
+
- [BREAKING] Now only Ruby 2.3 and above is supported ([flash-gordon](https://github.com/flash-gordon))
|
72
|
+
|
73
|
+
[Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-container/compare/v0.6.0...v0.7.0)
|
74
|
+
|
75
|
+
## 0.6.0 2016-12-09
|
76
|
+
|
77
|
+
|
78
|
+
### Added
|
79
|
+
|
80
|
+
- `Dry::Container::Mixin#each` - provides a means of seeing what all is registered in the container ([jeremyf](https://github.com/jeremyf))
|
81
|
+
|
82
|
+
### Fixed
|
83
|
+
|
84
|
+
- Including mixin into a class with a custom initializer ([maltoe](https://github.com/maltoe))
|
85
|
+
|
86
|
+
|
87
|
+
[Compare v0.5.0...v0.6.0](https://github.com/dry-rb/dry-container/compare/v0.5.0...v0.6.0)
|
88
|
+
|
89
|
+
## 0.5.0 2016-08-31
|
90
|
+
|
91
|
+
|
92
|
+
### Added
|
93
|
+
|
94
|
+
- `memoize` option to `#register` - memoizes items on first resolve ([ivoanjo](https://github.com/ivoanjo))
|
95
|
+
|
96
|
+
### Fixed
|
97
|
+
|
98
|
+
- `required_ruby_version` set to `>= 2.0.0` ([artofhuman](https://github.com/artofhuman))
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,169 +1,29 @@
|
|
1
|
-
|
1
|
+
<!--- this file is synced from dry-rb/template-gem project -->
|
2
2
|
[gem]: https://rubygems.org/gems/dry-container
|
3
|
-
[
|
4
|
-
[
|
5
|
-
[
|
3
|
+
[actions]: https://github.com/dry-rb/dry-container/actions
|
4
|
+
[codacy]: https://www.codacy.com/gh/dry-rb/dry-container
|
5
|
+
[chat]: https://dry-rb.zulipchat.com
|
6
|
+
[inchpages]: http://inch-ci.org/github/dry-rb/dry-container
|
6
7
|
|
7
|
-
# dry-container [![Join the
|
8
|
+
# dry-container [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
|
8
9
|
|
9
|
-
[![Gem Version](https://
|
10
|
-
[![
|
11
|
-
[![
|
12
|
-
[![
|
13
|
-
[![
|
10
|
+
[![Gem Version](https://badge.fury.io/rb/dry-container.svg)][gem]
|
11
|
+
[![CI Status](https://github.com/dry-rb/dry-container/workflows/ci/badge.svg)][actions]
|
12
|
+
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/227509c9034340b493f769f6277f4ecb)][codacy]
|
13
|
+
[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/227509c9034340b493f769f6277f4ecb)][codacy]
|
14
|
+
[![Inline docs](http://inch-ci.org/github/dry-rb/dry-container.svg?branch=master)][inchpages]
|
14
15
|
|
16
|
+
## Links
|
15
17
|
|
16
|
-
|
18
|
+
* [User documentation](https://dry-rb.org/gems/dry-container)
|
19
|
+
* [API documentation](http://rubydoc.info/gems/dry-container)
|
17
20
|
|
18
|
-
##
|
21
|
+
## Supported Ruby versions
|
19
22
|
|
20
|
-
|
23
|
+
This library officially supports the following Ruby versions:
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
container.register(:parrot) { |a| puts a }
|
25
|
-
|
26
|
-
parrot = container.resolve(:parrot)
|
27
|
-
parrot.call("Hello World")
|
28
|
-
# Hello World
|
29
|
-
# => nil
|
30
|
-
```
|
31
|
-
|
32
|
-
### Detailed Example
|
33
|
-
|
34
|
-
```ruby
|
35
|
-
User = Struct.new(:name, :email)
|
36
|
-
|
37
|
-
data_store = Concurrent::Map.new.tap do |ds|
|
38
|
-
ds[:users] = Concurrent::Array.new
|
39
|
-
end
|
40
|
-
|
41
|
-
# Initialize container
|
42
|
-
container = Dry::Container.new
|
43
|
-
|
44
|
-
# Register an item with the container to be resolved later
|
45
|
-
container.register(:data_store, data_store)
|
46
|
-
container.register(:user_repository, -> { container.resolve(:data_store)[:users] })
|
47
|
-
|
48
|
-
# Resolve an item from the container
|
49
|
-
container.resolve(:user_repository) << User.new('Jack', 'jack@dry-container.com')
|
50
|
-
# You can also resolve with []
|
51
|
-
container[:user_repository] << User.new('Jill', 'jill@dry-container.com')
|
52
|
-
# => [
|
53
|
-
# #<struct User name="Jack", email="jack@dry-container.com">,
|
54
|
-
# #<struct User name="Jill", email="jill@dry-container.com">
|
55
|
-
# ]
|
56
|
-
|
57
|
-
# If you wish to register an item that responds to call but don't want it to be
|
58
|
-
# called when resolved, you can use the options hash
|
59
|
-
container.register(:proc, -> { :result }, call: false)
|
60
|
-
container.resolve(:proc)
|
61
|
-
# => #<Proc:0x007fa75e652c98@(irb):25 (lambda)>
|
62
|
-
|
63
|
-
# You can also register using a block
|
64
|
-
container.register(:item) do
|
65
|
-
:result
|
66
|
-
end
|
67
|
-
container.resolve(:item)
|
68
|
-
# => :result
|
69
|
-
|
70
|
-
container.register(:block, call: false) do
|
71
|
-
:result
|
72
|
-
end
|
73
|
-
container.resolve(:block)
|
74
|
-
# => #<Proc:0x007fa75e6830f0@(irb):36>
|
75
|
-
|
76
|
-
# You can also register items under namespaces using the #namespace method
|
77
|
-
container.namespace('repositories') do
|
78
|
-
namespace('checkout') do
|
79
|
-
register('orders') { Concurrent::Array.new }
|
80
|
-
end
|
81
|
-
end
|
82
|
-
container.resolve('repositories.checkout.orders')
|
83
|
-
# => []
|
84
|
-
|
85
|
-
# Or import a namespace
|
86
|
-
ns = Dry::Container::Namespace.new('repositories') do
|
87
|
-
namespace('authentication') do
|
88
|
-
register('users') { Concurrent::Array.new }
|
89
|
-
end
|
90
|
-
end
|
91
|
-
container.import(ns)
|
92
|
-
container.resolve('repositories.authentication.users')
|
93
|
-
# => []
|
94
|
-
|
95
|
-
# You can also register a block that is used to initialize a dependency and
|
96
|
-
# then memoize it, allowing several dependencies to be added without
|
97
|
-
# enforcing an instantiation order
|
98
|
-
class MessagePrinter
|
99
|
-
def initialize(container)
|
100
|
-
@message = container.resolve(:message)
|
101
|
-
@time = Time.now
|
102
|
-
end
|
103
|
-
|
104
|
-
def print
|
105
|
-
puts "#{@message} at #{@time}"
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
container.register(:message_printer, -> { MessagePrinter.new(container) }, memoize: true)
|
110
|
-
container.register(:message, 'Hello, world!')
|
111
|
-
container.resolve(:message_printer).print
|
112
|
-
# => Hello, world! at 2016-08-30 05:32:12 -0700
|
113
|
-
|
114
|
-
# Same instance is reused next time
|
115
|
-
container.resolve(:message_printer).print
|
116
|
-
# => Hello, world! at 2016-08-30 05:32:12 -0700
|
117
|
-
```
|
118
|
-
|
119
|
-
You can also get container behaviour at both the class and instance level via the mixin:
|
120
|
-
|
121
|
-
```ruby
|
122
|
-
class Container
|
123
|
-
extend Dry::Container::Mixin
|
124
|
-
end
|
125
|
-
Container.register(:item, :my_item)
|
126
|
-
Container.resolve(:item)
|
127
|
-
# => :my_item
|
128
|
-
|
129
|
-
class ContainerObject
|
130
|
-
include Dry::Container::Mixin
|
131
|
-
end
|
132
|
-
container = ContainerObject.new
|
133
|
-
container.register(:item, :my_item)
|
134
|
-
container.resolve(:item)
|
135
|
-
# => :my_item
|
136
|
-
```
|
137
|
-
### Using a custom registry/resolver
|
138
|
-
|
139
|
-
You can configure how items are registered and resolved from the container:
|
140
|
-
|
141
|
-
```ruby
|
142
|
-
Dry::Container.configure do |config|
|
143
|
-
config.registry = ->(container, key, item, options) { container[key] = item }
|
144
|
-
config.resolver = ->(container, key) { container[key] }
|
145
|
-
end
|
146
|
-
|
147
|
-
class Container
|
148
|
-
extend Dry::Container::Mixin
|
149
|
-
|
150
|
-
configure do |config|
|
151
|
-
config.registry = ->(container, key, item, options) { container[key] = item }
|
152
|
-
config.resolver = ->(container, key) { container[key] }
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
class ContainerObject
|
157
|
-
include Dry::Container::Mixin
|
158
|
-
|
159
|
-
configure do |config|
|
160
|
-
config.registry = ->(container, key, item, options) { container[key] = item }
|
161
|
-
config.resolver = ->(container, key) { container[key] }
|
162
|
-
end
|
163
|
-
end
|
164
|
-
```
|
165
|
-
|
166
|
-
This allows you to customise the behaviour of Dry::Container, for example, the default registry (Dry::Container::Registry) will raise a Dry::Container::Error exception if you try to register under a key that is already used, you may want to just overwrite the existing value in that scenario, configuration allows you to do so.
|
25
|
+
* MRI `>= 2.6.0`
|
26
|
+
* jruby `>= 9.2`
|
167
27
|
|
168
28
|
## License
|
169
29
|
|
data/dry-container.gemspec
CHANGED
@@ -1,26 +1,42 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# this file is synced from dry-rb/template-gem project
|
4
|
+
|
5
|
+
lib = File.expand_path("lib", __dir__)
|
6
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
7
|
+
require "dry/container/version"
|
3
8
|
|
4
9
|
Gem::Specification.new do |spec|
|
5
|
-
spec.name =
|
6
|
-
spec.
|
7
|
-
spec.
|
8
|
-
spec.
|
9
|
-
spec.
|
10
|
-
|
11
|
-
spec.
|
12
|
-
|
13
|
-
spec.
|
14
|
-
spec.
|
15
|
-
spec.
|
16
|
-
spec.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
spec.
|
21
|
-
spec.
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
10
|
+
spec.name = "dry-container"
|
11
|
+
spec.authors = ["Andy Holland"]
|
12
|
+
spec.email = ["andyholland1991@aol.com"]
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.version = Dry::Container::VERSION.dup
|
15
|
+
|
16
|
+
spec.summary = "A simple, configurable object container implemented in Ruby"
|
17
|
+
spec.description = spec.summary
|
18
|
+
spec.homepage = "https://dry-rb.org/gems/dry-container"
|
19
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-container.gemspec", "lib/**/*"]
|
20
|
+
spec.bindir = "bin"
|
21
|
+
spec.executables = []
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
25
|
+
spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-container/blob/master/CHANGELOG.md"
|
26
|
+
spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-container"
|
27
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-container/issues"
|
28
|
+
|
29
|
+
if defined? JRUBY_VERSION
|
30
|
+
spec.required_ruby_version = ">= 2.5.0"
|
31
|
+
else
|
32
|
+
spec.required_ruby_version = ">= 2.6.0"
|
33
|
+
end
|
34
|
+
|
35
|
+
# to update dependencies edit project.yml
|
36
|
+
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
37
|
+
spec.add_runtime_dependency "dry-configurable", "~> 0.1", ">= 0.1.3"
|
38
|
+
|
39
|
+
spec.add_development_dependency "bundler"
|
40
|
+
spec.add_development_dependency "rake"
|
41
|
+
spec.add_development_dependency "rspec"
|
26
42
|
end
|
data/lib/dry-container.rb
CHANGED
data/lib/dry/container.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry-configurable"
|
4
|
+
require "dry/container/error"
|
5
|
+
require "dry/container/namespace"
|
6
|
+
require "dry/container/registry"
|
7
|
+
require "dry/container/resolver"
|
8
|
+
require "dry/container/namespace_dsl"
|
9
|
+
require "dry/container/mixin"
|
10
|
+
require "dry/container/version"
|
11
11
|
|
12
12
|
# A collection of micro-libraries, each intended to encapsulate
|
13
13
|
# a common task in Ruby
|
data/lib/dry/container/error.rb
CHANGED
data/lib/dry/container/item.rb
CHANGED
@@ -1,42 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
class Container
|
3
|
-
#
|
5
|
+
# Base class to abstract Memoizable and Callable implementations
|
6
|
+
#
|
7
|
+
# @api abstract
|
4
8
|
#
|
5
|
-
# @private
|
6
9
|
class Item
|
7
|
-
|
10
|
+
# @return [Mixed] the item to be solved later
|
11
|
+
attr_reader :item
|
12
|
+
|
13
|
+
# @return [Hash] the options to memoize, call or no.
|
14
|
+
attr_reader :options
|
8
15
|
|
16
|
+
# @api abstract
|
9
17
|
def initialize(item, options = {})
|
10
18
|
@item = item
|
11
19
|
@options = {
|
12
20
|
call: item.is_a?(::Proc) && item.parameters.empty?
|
13
21
|
}.merge(options)
|
14
|
-
|
15
|
-
if options[:memoize] == true
|
16
|
-
raise(
|
17
|
-
::Dry::Container::Error,
|
18
|
-
'Memoize only supported for a block or a proc'
|
19
|
-
) unless item.is_a?(::Proc)
|
20
|
-
@memoize = true
|
21
|
-
@memoize_mutex = ::Mutex.new
|
22
|
-
end
|
23
22
|
end
|
24
23
|
|
24
|
+
# @api abstract
|
25
25
|
def call
|
26
|
-
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
item
|
32
|
-
end
|
29
|
+
# @private
|
30
|
+
def value?
|
31
|
+
!callable?
|
33
32
|
end
|
34
33
|
|
35
|
-
private
|
34
|
+
# @private
|
35
|
+
def callable?
|
36
|
+
options[:call]
|
37
|
+
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
# Build a new item with transformation applied
|
40
|
+
#
|
41
|
+
# @private
|
42
|
+
def map(func)
|
43
|
+
if callable?
|
44
|
+
self.class.new(-> { func.(item.call) }, options)
|
45
|
+
else
|
46
|
+
self.class.new(func.(item), options)
|
40
47
|
end
|
41
48
|
end
|
42
49
|
end
|