dry-container 0.5.0 → 0.8.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 +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
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/container/item"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
class Container
|
7
|
+
class Item
|
8
|
+
# Callable class to returns a item call
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
#
|
12
|
+
class Callable < Item
|
13
|
+
# Returns the result of item call or item
|
14
|
+
#
|
15
|
+
# @return [Mixed]
|
16
|
+
def call
|
17
|
+
callable? ? item.call : item
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/container/item/memoizable"
|
4
|
+
require "dry/container/item/callable"
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
class Container
|
8
|
+
class Item
|
9
|
+
# Factory for create an Item to register inside of container
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
class Factory
|
13
|
+
# Creates an Item Memoizable or Callable
|
14
|
+
# @param [Mixed] item
|
15
|
+
# @param [Hash] options
|
16
|
+
#
|
17
|
+
# @raise [Dry::Container::Error]
|
18
|
+
#
|
19
|
+
# @return [Dry::Container::Item::Base]
|
20
|
+
def call(item, options = {})
|
21
|
+
options[:memoize] ? Memoizable.new(item, options) : Callable.new(item, options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/container/item"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
class Container
|
7
|
+
class Item
|
8
|
+
# Memoizable class to store and execute item calls
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
#
|
12
|
+
class Memoizable < Item
|
13
|
+
# @return [Mutex] the stored mutex
|
14
|
+
attr_reader :memoize_mutex
|
15
|
+
|
16
|
+
# Returns a new Memoizable instance
|
17
|
+
#
|
18
|
+
# @param [Mixed] item
|
19
|
+
# @param [Hash] options
|
20
|
+
#
|
21
|
+
# @raise [Dry::Container::Error]
|
22
|
+
#
|
23
|
+
# @return [Dry::Container::Item::Base]
|
24
|
+
def initialize(item, options = {})
|
25
|
+
super
|
26
|
+
raise_not_supported_error unless callable?
|
27
|
+
|
28
|
+
@memoize_mutex = ::Mutex.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the result of item call using a syncronized mutex
|
32
|
+
#
|
33
|
+
# @return [Dry::Container::Item::Base]
|
34
|
+
def call
|
35
|
+
memoize_mutex.synchronize do
|
36
|
+
@memoized_item ||= item.call
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @private
|
43
|
+
def raise_not_supported_error
|
44
|
+
raise ::Dry::Container::Error, "Memoize only supported for a block or a proc".freeze
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/dry/container/mixin.rb
CHANGED
@@ -1,8 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "concurrent/hash"
|
4
|
+
|
1
5
|
module Dry
|
2
6
|
class Container
|
3
|
-
PREFIX_NAMESPACE =
|
7
|
+
PREFIX_NAMESPACE = lambda do |namespace, key, config|
|
4
8
|
[namespace, key].join(config.namespace_separator)
|
5
9
|
end
|
10
|
+
|
11
|
+
EMPTY_HASH = {}.freeze
|
12
|
+
|
6
13
|
# Mixin to expose Inversion of Control (IoC) container behaviour
|
7
14
|
#
|
8
15
|
# @example
|
@@ -42,9 +49,17 @@ module Dry
|
|
42
49
|
|
43
50
|
setting :registry, ::Dry::Container::Registry.new
|
44
51
|
setting :resolver, ::Dry::Container::Resolver.new
|
45
|
-
setting :namespace_separator,
|
52
|
+
setting :namespace_separator, "."
|
53
|
+
|
54
|
+
@_container = ::Concurrent::Hash.new
|
55
|
+
end
|
56
|
+
end
|
46
57
|
|
58
|
+
# @private
|
59
|
+
module Initializer
|
60
|
+
def initialize(*args, &block)
|
47
61
|
@_container = ::Concurrent::Hash.new
|
62
|
+
super
|
48
63
|
end
|
49
64
|
end
|
50
65
|
|
@@ -52,15 +67,11 @@ module Dry
|
|
52
67
|
def self.included(base)
|
53
68
|
base.class_eval do
|
54
69
|
extend ::Dry::Configurable
|
70
|
+
prepend Initializer
|
55
71
|
|
56
72
|
setting :registry, ::Dry::Container::Registry.new
|
57
73
|
setting :resolver, ::Dry::Container::Resolver.new
|
58
|
-
setting :namespace_separator,
|
59
|
-
|
60
|
-
def initialize(*args, &block)
|
61
|
-
@_container = ::Concurrent::Hash.new
|
62
|
-
super(*args, &block)
|
63
|
-
end
|
74
|
+
setting :namespace_separator, "."
|
64
75
|
|
65
76
|
def config
|
66
77
|
self.class.config
|
@@ -83,7 +94,7 @@ module Dry
|
|
83
94
|
# @return [Dry::Container::Mixin] self
|
84
95
|
#
|
85
96
|
# @api public
|
86
|
-
def register(key, contents = nil, options =
|
97
|
+
def register(key, contents = nil, options = EMPTY_HASH, &block)
|
87
98
|
if block_given?
|
88
99
|
item = block
|
89
100
|
options = contents if contents.is_a?(::Hash)
|
@@ -100,12 +111,15 @@ module Dry
|
|
100
111
|
#
|
101
112
|
# @param [Mixed] key
|
102
113
|
# The key for the item you wish to resolve
|
114
|
+
# @yield
|
115
|
+
# Fallback block to call when a key is missing. Its result will be returned
|
116
|
+
# @yieldparam [Mixed] key Missing key
|
103
117
|
#
|
104
118
|
# @return [Mixed]
|
105
119
|
#
|
106
120
|
# @api public
|
107
|
-
def resolve(key)
|
108
|
-
config.resolver.call(_container, key)
|
121
|
+
def resolve(key, &block)
|
122
|
+
config.resolver.call(_container, key, &block)
|
109
123
|
end
|
110
124
|
|
111
125
|
# Resolve an item from the container
|
@@ -125,8 +139,7 @@ module Dry
|
|
125
139
|
#
|
126
140
|
# @param [Dry::Container] other
|
127
141
|
# The other container to merge in
|
128
|
-
# @param [
|
129
|
-
# @option options [Symbol] :namespace
|
142
|
+
# @param [Symbol, nil] namespace
|
130
143
|
# Namespace to prefix other container items with, defaults to nil
|
131
144
|
#
|
132
145
|
# @return [Dry::Container::Mixin] self
|
@@ -146,7 +159,7 @@ module Dry
|
|
146
159
|
self
|
147
160
|
end
|
148
161
|
|
149
|
-
# Check whether an
|
162
|
+
# Check whether an item is registered under the given key
|
150
163
|
#
|
151
164
|
# @param [Mixed] key
|
152
165
|
# The key you wish to check for registration with
|
@@ -179,6 +192,44 @@ module Dry
|
|
179
192
|
self
|
180
193
|
end
|
181
194
|
|
195
|
+
# Calls block once for each key/value pair in the container, passing the key and the registered item parameters.
|
196
|
+
#
|
197
|
+
# If no block is given, an enumerator is returned instead.
|
198
|
+
#
|
199
|
+
# @return [Enumerator]
|
200
|
+
#
|
201
|
+
# @api public
|
202
|
+
#
|
203
|
+
# @note In discussions with other developers, it was felt that being able to iterate over not just
|
204
|
+
# the registered keys, but to see what was registered would be very helpful. This is a step
|
205
|
+
# toward doing that.
|
206
|
+
def each(&block)
|
207
|
+
config.resolver.each(_container, &block)
|
208
|
+
end
|
209
|
+
|
210
|
+
# Decorates an item from the container with specified decorator
|
211
|
+
#
|
212
|
+
# @return [Dry::Container::Mixin] self
|
213
|
+
#
|
214
|
+
# @api public
|
215
|
+
def decorate(key, with: nil, &block)
|
216
|
+
key = key.to_s
|
217
|
+
original = _container.delete(key) do
|
218
|
+
raise Error, "Nothing registered with the key #{key.inspect}"
|
219
|
+
end
|
220
|
+
|
221
|
+
if with.is_a?(Class)
|
222
|
+
decorator = with.method(:new)
|
223
|
+
elsif block.nil? && !with.respond_to?(:call)
|
224
|
+
raise Error, "Decorator needs to be a Class, block, or respond to the `call` method"
|
225
|
+
else
|
226
|
+
decorator = with || block
|
227
|
+
end
|
228
|
+
|
229
|
+
_container[key] = original.map(decorator)
|
230
|
+
self
|
231
|
+
end
|
232
|
+
|
182
233
|
# Evaluate block and register items in namespace
|
183
234
|
#
|
184
235
|
# @param [Mixed] namespace
|
@@ -212,10 +263,35 @@ module Dry
|
|
212
263
|
self
|
213
264
|
end
|
214
265
|
|
266
|
+
# Freeze the container. Nothing can be registered after freezing
|
267
|
+
#
|
268
|
+
# @api public
|
269
|
+
def freeze
|
270
|
+
super
|
271
|
+
_container.freeze
|
272
|
+
self
|
273
|
+
end
|
274
|
+
|
215
275
|
# @private no, really
|
216
276
|
def _container
|
217
277
|
@_container
|
218
278
|
end
|
279
|
+
|
280
|
+
# @api public
|
281
|
+
def dup
|
282
|
+
copy = super
|
283
|
+
copy.instance_variable_set(:@_container, _container.dup)
|
284
|
+
copy
|
285
|
+
end
|
286
|
+
|
287
|
+
# @api public
|
288
|
+
def clone
|
289
|
+
copy = super
|
290
|
+
unless copy.frozen?
|
291
|
+
copy.instance_variable_set(:@_container, _container.dup)
|
292
|
+
end
|
293
|
+
copy
|
294
|
+
end
|
219
295
|
end
|
220
296
|
end
|
221
297
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
1
5
|
module Dry
|
2
6
|
class Container
|
3
7
|
# @api private
|
@@ -43,6 +47,10 @@ module Dry
|
|
43
47
|
self
|
44
48
|
end
|
45
49
|
|
50
|
+
def resolve(key)
|
51
|
+
super(namespaced(key))
|
52
|
+
end
|
53
|
+
|
46
54
|
private
|
47
55
|
|
48
56
|
def namespaced(key)
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/container/item/factory"
|
4
|
+
|
1
5
|
module Dry
|
2
6
|
class Container
|
3
7
|
# Default registry for registering items with the container
|
@@ -34,9 +38,13 @@ module Dry
|
|
34
38
|
raise Error, "There is already an item registered with the key #{key.inspect}"
|
35
39
|
end
|
36
40
|
|
37
|
-
container[key] =
|
41
|
+
container[key] = factory.call(item, options)
|
38
42
|
end
|
39
43
|
end
|
44
|
+
|
45
|
+
def factory
|
46
|
+
@factory ||= ::Dry::Container::Item::Factory.new
|
47
|
+
end
|
40
48
|
end
|
41
49
|
end
|
42
50
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
class Container
|
3
5
|
# Default resolver for resolving items from container
|
@@ -10,16 +12,24 @@ module Dry
|
|
10
12
|
# The container
|
11
13
|
# @param [Mixed] key
|
12
14
|
# The key for the item you wish to resolve
|
15
|
+
# @yield
|
16
|
+
# Fallback block to call when a key is missing. Its result will be returned
|
17
|
+
# @yieldparam [Mixed] key Missing key
|
18
|
+
#
|
19
|
+
# @raise [Dry::Container::Error]
|
20
|
+
# If the given key is not registered with the container (and no block provided)
|
13
21
|
#
|
14
|
-
# @raise [Dry::Conainer::Error]
|
15
|
-
# If the given key is not registered with the container
|
16
22
|
#
|
17
23
|
# @return [Mixed]
|
18
24
|
#
|
19
25
|
# @api public
|
20
26
|
def call(container, key)
|
21
27
|
item = container.fetch(key.to_s) do
|
22
|
-
|
28
|
+
if block_given?
|
29
|
+
return yield(key)
|
30
|
+
else
|
31
|
+
raise Error, "Nothing registered with the key #{key.inspect}"
|
32
|
+
end
|
23
33
|
end
|
24
34
|
|
25
35
|
item.call
|
@@ -48,7 +58,6 @@ module Dry
|
|
48
58
|
container.keys
|
49
59
|
end
|
50
60
|
|
51
|
-
|
52
61
|
# Calls block once for each key in container, passing the key as a parameter.
|
53
62
|
#
|
54
63
|
# If no block is given, an enumerator is returned instead.
|
@@ -59,6 +68,20 @@ module Dry
|
|
59
68
|
def each_key(container, &block)
|
60
69
|
container.each_key(&block)
|
61
70
|
end
|
71
|
+
|
72
|
+
# Calls block once for each key in container, passing the key and the registered item parameters.
|
73
|
+
#
|
74
|
+
# If no block is given, an enumerator is returned instead.
|
75
|
+
#
|
76
|
+
# @return Key, Value
|
77
|
+
#
|
78
|
+
# @api public
|
79
|
+
# @note In discussions with other developers, it was felt that being able to iterate over not just
|
80
|
+
# the registered keys, but to see what was registered would be very helpful. This is a step
|
81
|
+
# toward doing that.
|
82
|
+
def each(container, &block)
|
83
|
+
container.map { |key, value| [key, value.call] }.each(&block)
|
84
|
+
end
|
62
85
|
end
|
63
86
|
end
|
64
87
|
end
|
data/lib/dry/container/stub.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
class Container
|
3
5
|
module Stub
|
@@ -5,12 +7,16 @@ module Dry
|
|
5
7
|
#
|
6
8
|
# @api public
|
7
9
|
def resolve(key)
|
8
|
-
_stubs.fetch(key) { super }
|
10
|
+
_stubs.fetch(key.to_s) { super }
|
9
11
|
end
|
10
12
|
|
11
13
|
# Add a stub to the container
|
12
14
|
def stub(key, value, &block)
|
13
|
-
|
15
|
+
unless key?(key)
|
16
|
+
raise ArgumentError, "cannot stub #{key.to_s.inspect} - no such key in container"
|
17
|
+
end
|
18
|
+
|
19
|
+
_stubs[key.to_s] = value
|
14
20
|
|
15
21
|
if block
|
16
22
|
yield
|
@@ -23,11 +29,12 @@ module Dry
|
|
23
29
|
# Remove stubbed keys from the container
|
24
30
|
def unstub(*keys)
|
25
31
|
keys = _stubs.keys if keys.empty?
|
26
|
-
keys.each { |key| _stubs.delete(key) }
|
32
|
+
keys.each { |key| _stubs.delete(key.to_s) }
|
27
33
|
end
|
28
34
|
|
29
35
|
# Stubs have already been enabled turning this into a noop
|
30
36
|
def enable_stubs!
|
37
|
+
# DO NOTHING
|
31
38
|
end
|
32
39
|
|
33
40
|
private
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-container
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Holland
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -86,29 +86,24 @@ dependencies:
|
|
86
86
|
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
|
-
description:
|
89
|
+
description: A simple, configurable object container implemented in Ruby
|
90
90
|
email:
|
91
91
|
- andyholland1991@aol.com
|
92
92
|
executables: []
|
93
93
|
extensions: []
|
94
94
|
extra_rdoc_files: []
|
95
95
|
files:
|
96
|
-
- ".codeclimate.yml"
|
97
|
-
- ".gitignore"
|
98
|
-
- ".rspec"
|
99
|
-
- ".rubocop.yml"
|
100
|
-
- ".rubocop_todo.yml"
|
101
|
-
- ".travis.yml"
|
102
96
|
- CHANGELOG.md
|
103
|
-
- Gemfile
|
104
97
|
- LICENSE
|
105
98
|
- README.md
|
106
|
-
- Rakefile
|
107
99
|
- dry-container.gemspec
|
108
100
|
- lib/dry-container.rb
|
109
101
|
- lib/dry/container.rb
|
110
102
|
- lib/dry/container/error.rb
|
111
103
|
- lib/dry/container/item.rb
|
104
|
+
- lib/dry/container/item/callable.rb
|
105
|
+
- lib/dry/container/item/factory.rb
|
106
|
+
- lib/dry/container/item/memoizable.rb
|
112
107
|
- lib/dry/container/mixin.rb
|
113
108
|
- lib/dry/container/namespace.rb
|
114
109
|
- lib/dry/container/namespace_dsl.rb
|
@@ -116,15 +111,14 @@ files:
|
|
116
111
|
- lib/dry/container/resolver.rb
|
117
112
|
- lib/dry/container/stub.rb
|
118
113
|
- lib/dry/container/version.rb
|
119
|
-
-
|
120
|
-
- spec/integration/container_spec.rb
|
121
|
-
- spec/integration/mixin_spec.rb
|
122
|
-
- spec/spec_helper.rb
|
123
|
-
- spec/support/shared_examples/container.rb
|
124
|
-
homepage: https://github.com/dryrb/dry-container
|
114
|
+
homepage: https://dry-rb.org/gems/dry-container
|
125
115
|
licenses:
|
126
116
|
- MIT
|
127
|
-
metadata:
|
117
|
+
metadata:
|
118
|
+
allowed_push_host: https://rubygems.org
|
119
|
+
changelog_uri: https://github.com/dry-rb/dry-container/blob/master/CHANGELOG.md
|
120
|
+
source_code_uri: https://github.com/dry-rb/dry-container
|
121
|
+
bug_tracker_uri: https://github.com/dry-rb/dry-container/issues
|
128
122
|
post_install_message:
|
129
123
|
rdoc_options: []
|
130
124
|
require_paths:
|
@@ -133,20 +127,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
127
|
requirements:
|
134
128
|
- - ">="
|
135
129
|
- !ruby/object:Gem::Version
|
136
|
-
version: 2.
|
130
|
+
version: 2.6.0
|
137
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
132
|
requirements:
|
139
133
|
- - ">="
|
140
134
|
- !ruby/object:Gem::Version
|
141
135
|
version: '0'
|
142
136
|
requirements: []
|
143
|
-
|
144
|
-
rubygems_version: 2.5.1
|
137
|
+
rubygems_version: 3.1.6
|
145
138
|
signing_key:
|
146
139
|
specification_version: 4
|
147
|
-
summary: A simple
|
148
|
-
test_files:
|
149
|
-
- spec/integration/container_spec.rb
|
150
|
-
- spec/integration/mixin_spec.rb
|
151
|
-
- spec/spec_helper.rb
|
152
|
-
- spec/support/shared_examples/container.rb
|
140
|
+
summary: A simple, configurable object container implemented in Ruby
|
141
|
+
test_files: []
|