dry-container 0.1.0 → 0.2.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 +4 -4
- data/.rubocop.yml +8 -0
- data/.rubocop_todo.yml +1 -6
- data/.travis.yml +2 -0
- data/LICENSE +0 -1
- data/README.md +31 -1
- data/dry-container.gemspec +1 -0
- data/lib/dry/container.rb +3 -0
- data/lib/dry/container/mixin.rb +31 -29
- data/lib/dry/container/registry.rb +40 -0
- data/lib/dry/container/resolver.rb +29 -0
- data/lib/dry/container/version.rb +1 -1
- data/spec/integration/container_spec.rb +2 -1
- data/spec/integration/mixin_spec.rb +5 -3
- data/spec/support/shared_examples/container.rb +122 -45
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 746334a72c7c6dbc33c55a831bc0b6be199d5307
|
4
|
+
data.tar.gz: 2c86a308642567d9dbc2d91330fd86f5f5dcd7e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfd4c3abb602f546e0abdf5e4ff39cdd8abb20ef16b8eea97896fdf6b8fed34324556b9150883c351cd8736493e9d2defb5159a2a5c47223403689e94a0e9d95
|
7
|
+
data.tar.gz: fd568448c7ccbb98bb0049b66878b6eccddca1d3db95c47cf3ffea365f5bd6f514eaed861b142a9e77151c9dab04f15566b9e401a5ca58a69a60f9edbb1af3f5
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
-
# on 2015-06-
|
2
|
+
# on 2015-06-16 19:51:19 +0100 using RuboCop version 0.32.0.
|
3
3
|
# The point is for the user to remove these configuration records
|
4
4
|
# one by one as the offenses are removed from the code base.
|
5
5
|
# Note that changes in the inspected code, or installation of new
|
6
6
|
# versions of RuboCop, may require this file to be generated again.
|
7
|
-
|
8
|
-
# Offense count: 1
|
9
|
-
# Configuration parameters: CountComments.
|
10
|
-
Metrics/MethodLength:
|
11
|
-
Max: 14
|
data/.travis.yml
CHANGED
data/LICENSE
CHANGED
@@ -18,4 +18,3 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
18
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
19
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
20
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
-
s
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
<a href="https://travis-ci.org/dryrb/dry-container" target="_blank"></a>
|
5
5
|
<a href="http://inch-ci.org/github/dryrb/dry-container" target="_blank"></a>
|
6
6
|
|
7
|
-
A simple
|
7
|
+
A simple, configurable container implemented in Ruby
|
8
8
|
|
9
9
|
## Synopsis
|
10
10
|
|
@@ -69,6 +69,36 @@ container.register(:item, :my_item)
|
|
69
69
|
container.resolve(:item)
|
70
70
|
# => :my_item
|
71
71
|
```
|
72
|
+
### Using a custom registry/resolver
|
73
|
+
|
74
|
+
You can configure how items are registered and resolved from the container:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
Dry::Container.configure do |config|
|
78
|
+
config.registry = ->(container, key, item, options) { container[key] = item }
|
79
|
+
config.resolver = ->(key) { container[key] }
|
80
|
+
end
|
81
|
+
|
82
|
+
class Container
|
83
|
+
extend Dry::Container::Mixin
|
84
|
+
|
85
|
+
configure do |config|
|
86
|
+
config.registry = ->(container, key, item, options) { container[key] = item }
|
87
|
+
config.resolver = ->(key) { container[key] }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class ContainerObject
|
92
|
+
include Dry::Container::Mixin
|
93
|
+
|
94
|
+
configure do |config|
|
95
|
+
config.registry = ->(container, key, item, options) { container[key] = item }
|
96
|
+
config.resolver = ->(key) { container[key] }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
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.
|
72
102
|
|
73
103
|
## License
|
74
104
|
|
data/dry-container.gemspec
CHANGED
data/lib/dry/container.rb
CHANGED
data/lib/dry/container/mixin.rb
CHANGED
@@ -26,13 +26,37 @@ module Dry
|
|
26
26
|
module Mixin
|
27
27
|
# @private
|
28
28
|
def self.extended(base)
|
29
|
-
base.
|
29
|
+
base.class_eval do
|
30
|
+
extend ::Dry::Configurable
|
31
|
+
|
32
|
+
setting :registry, Registry.new
|
33
|
+
setting :resolver, Resolver.new
|
34
|
+
|
35
|
+
@_container = ThreadSafe::Cache.new
|
36
|
+
|
37
|
+
class << self
|
38
|
+
attr_reader :_container
|
39
|
+
end
|
40
|
+
end
|
30
41
|
end
|
31
42
|
# @private
|
32
43
|
def self.included(base)
|
33
|
-
base.
|
34
|
-
|
35
|
-
|
44
|
+
base.class_eval do
|
45
|
+
extend ::Dry::Configurable
|
46
|
+
|
47
|
+
setting :registry, Registry.new
|
48
|
+
setting :resolver, Resolver.new
|
49
|
+
|
50
|
+
attr_reader :_container
|
51
|
+
|
52
|
+
def initialize(*args, &block)
|
53
|
+
@_container = ThreadSafe::Cache.new
|
54
|
+
super(*args, &block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def config
|
58
|
+
self.class.config
|
59
|
+
end
|
36
60
|
end
|
37
61
|
end
|
38
62
|
# Register an item with the container to be resolved later
|
@@ -42,15 +66,11 @@ module Dry
|
|
42
66
|
# @param [Mixed] contents
|
43
67
|
# The item to register with the container (if no block given)
|
44
68
|
# @param [Hash] options
|
45
|
-
#
|
46
|
-
# Whether the item should be called when resolved
|
69
|
+
# Options to pass to the registry when registering the item
|
47
70
|
# @yield
|
48
71
|
# If a block is given, contents will be ignored and the block
|
49
72
|
# will be registered instead
|
50
73
|
#
|
51
|
-
# @raise [Dry::Conainer::Error]
|
52
|
-
# If an item is already registered with the given key
|
53
|
-
#
|
54
74
|
# @return [Dry::Container] self
|
55
75
|
#
|
56
76
|
# @api public
|
@@ -62,11 +82,7 @@ module Dry
|
|
62
82
|
item = contents
|
63
83
|
end
|
64
84
|
|
65
|
-
|
66
|
-
fail Error, "There is already an item registered with the key #{key.inspect}"
|
67
|
-
else
|
68
|
-
_container[key] = Item.new(item, options)
|
69
|
-
end
|
85
|
+
config.registry.call(_container, key, item, options)
|
70
86
|
|
71
87
|
self
|
72
88
|
end
|
@@ -75,18 +91,11 @@ module Dry
|
|
75
91
|
# @param [Mixed] key
|
76
92
|
# The key for the item you wish to resolve
|
77
93
|
#
|
78
|
-
# @raise [Dry::Conainer::Error]
|
79
|
-
# If the given key is not registered with the container
|
80
|
-
#
|
81
94
|
# @return [Mixed]
|
82
95
|
#
|
83
96
|
# @api public
|
84
97
|
def resolve(key)
|
85
|
-
|
86
|
-
fail Error, "Nothing registered with the key #{key.inspect}"
|
87
|
-
end
|
88
|
-
|
89
|
-
item.call
|
98
|
+
config.resolver.call(_container, key)
|
90
99
|
end
|
91
100
|
# Resolve an item from the container
|
92
101
|
#
|
@@ -99,13 +108,6 @@ module Dry
|
|
99
108
|
def [](key)
|
100
109
|
resolve(key)
|
101
110
|
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
# @private
|
106
|
-
def _container
|
107
|
-
@_mutex.synchronize { @_container ||= ThreadSafe::Cache.new }
|
108
|
-
end
|
109
111
|
end
|
110
112
|
end
|
111
113
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Dry
|
2
|
+
class Container
|
3
|
+
# Default registry for registering items with the container
|
4
|
+
#
|
5
|
+
# @api public
|
6
|
+
class Registry
|
7
|
+
# @private
|
8
|
+
def initialize
|
9
|
+
@_mutex = Mutex.new
|
10
|
+
end
|
11
|
+
# Register an item with the container to be resolved later
|
12
|
+
#
|
13
|
+
# @param [ThreadSafe::Hash] container
|
14
|
+
# The container
|
15
|
+
# @param [Mixed] key
|
16
|
+
# The key to register the container item with (used to resolve)
|
17
|
+
# @param [Mixed] item
|
18
|
+
# The item to register with the container
|
19
|
+
# @param [Hash] options
|
20
|
+
# @option options [Symbol] :call
|
21
|
+
# Whether the item should be called when resolved
|
22
|
+
#
|
23
|
+
# @raise [Dry::Conainer::Error]
|
24
|
+
# If an item is already registered with the given key
|
25
|
+
#
|
26
|
+
# @return [Mixed]
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
def call(container, key, item, options)
|
30
|
+
@_mutex.synchronize do
|
31
|
+
if container.key?(key)
|
32
|
+
fail Error, "There is already an item registered with the key #{key.inspect}"
|
33
|
+
else
|
34
|
+
container[key] = Item.new(item, options)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Dry
|
2
|
+
class Container
|
3
|
+
# Default resolver for resolving items from container
|
4
|
+
#
|
5
|
+
# @api public
|
6
|
+
class Resolver
|
7
|
+
# Resolve an item from the container
|
8
|
+
#
|
9
|
+
# @param [ThreadSafe::Hash] container
|
10
|
+
# The container
|
11
|
+
# @param [Mixed] key
|
12
|
+
# The key for the item you wish to resolve
|
13
|
+
#
|
14
|
+
# @raise [Dry::Conainer::Error]
|
15
|
+
# If the given key is not registered with the container
|
16
|
+
#
|
17
|
+
# @return [Mixed]
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
def call(container, key)
|
21
|
+
item = container.fetch(key) do
|
22
|
+
fail Error, "Nothing registered with the key #{key.inspect}"
|
23
|
+
end
|
24
|
+
|
25
|
+
item.call
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,16 +1,18 @@
|
|
1
1
|
RSpec.describe Dry::Container::Mixin do
|
2
2
|
describe 'extended' do
|
3
|
-
let(:
|
3
|
+
let(:klass) do
|
4
4
|
Class.new { extend Dry::Container::Mixin }
|
5
5
|
end
|
6
|
+
let(:container) { klass }
|
6
7
|
|
7
8
|
it_behaves_like 'a container'
|
8
9
|
end
|
9
10
|
|
10
11
|
describe 'included' do
|
11
|
-
let(:
|
12
|
-
Class.new { include Dry::Container::Mixin }
|
12
|
+
let(:klass) do
|
13
|
+
Class.new { include Dry::Container::Mixin }
|
13
14
|
end
|
15
|
+
let(:container) { klass.new }
|
14
16
|
|
15
17
|
it_behaves_like 'a container'
|
16
18
|
end
|
@@ -1,76 +1,153 @@
|
|
1
1
|
shared_examples 'a container' do
|
2
|
-
describe '
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
describe 'configuration' do
|
3
|
+
describe 'registry' do
|
4
|
+
describe 'default' do
|
5
|
+
it { expect(klass.config.registry).to be_a(Dry::Container::Registry) }
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'custom' do
|
9
|
+
let(:custom_registry) { double('Registry') }
|
10
|
+
let(:key) { :key }
|
11
|
+
let(:item) { :item }
|
12
|
+
let(:options) { {} }
|
13
|
+
|
14
|
+
before do
|
15
|
+
klass.configure do |config|
|
16
|
+
config.registry = custom_registry
|
17
|
+
end
|
18
|
+
|
19
|
+
allow(custom_registry).to receive(:call)
|
20
|
+
end
|
6
21
|
|
7
|
-
|
22
|
+
after do
|
23
|
+
# HACK: Have to reset the configuration so that it doesn't
|
24
|
+
# interfere with other specs
|
25
|
+
klass.configure do |config|
|
26
|
+
config.registry = Dry::Container::Registry.new
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
subject! { container.register(key, item, options) }
|
31
|
+
|
32
|
+
it do
|
33
|
+
expect(custom_registry).to have_received(:call).with(
|
34
|
+
container._container,
|
35
|
+
key,
|
36
|
+
item,
|
37
|
+
options
|
38
|
+
)
|
39
|
+
end
|
8
40
|
end
|
9
41
|
end
|
10
42
|
|
11
|
-
|
12
|
-
|
13
|
-
|
43
|
+
describe 'resolver' do
|
44
|
+
describe 'default' do
|
45
|
+
it { expect(klass.config.resolver).to be_a(Dry::Container::Resolver) }
|
46
|
+
end
|
14
47
|
|
15
|
-
|
16
|
-
|
48
|
+
describe 'custom' do
|
49
|
+
let(:custom_resolver) { double('Resolver') }
|
50
|
+
let(:item) { double('Item') }
|
51
|
+
let(:key) { :key }
|
52
|
+
|
53
|
+
before do
|
54
|
+
klass.configure do |config|
|
55
|
+
config.resolver = custom_resolver
|
56
|
+
end
|
57
|
+
|
58
|
+
allow(custom_resolver).to receive(:call).and_return(item)
|
59
|
+
end
|
60
|
+
|
61
|
+
after do
|
62
|
+
# HACK: Have to reset the configuration so that it doesn't
|
63
|
+
# interfere with other specs
|
64
|
+
klass.configure do |config|
|
65
|
+
config.resolver = Dry::Container::Resolver.new
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
subject! { container.resolve(key) }
|
70
|
+
|
71
|
+
it { expect(custom_resolver).to have_received(:call).with(container._container, key) }
|
72
|
+
it { is_expected.to eq(item) }
|
17
73
|
end
|
18
74
|
end
|
19
75
|
end
|
20
76
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
77
|
+
context 'with default configuration' do
|
78
|
+
describe 'registering a block' do
|
79
|
+
context 'without options' do
|
80
|
+
it 'registers and resolves an object' do
|
81
|
+
container.register(:item) { 'item' }
|
25
82
|
|
26
|
-
|
27
|
-
|
83
|
+
expect(container.resolve(:item)).to eq('item')
|
84
|
+
end
|
28
85
|
end
|
29
|
-
end
|
30
86
|
|
31
|
-
|
32
|
-
|
33
|
-
|
87
|
+
context 'with option call: false' do
|
88
|
+
it 'registers and resolves a proc' do
|
89
|
+
container.register(:item, call: false) { 'item' }
|
34
90
|
|
35
|
-
|
36
|
-
|
91
|
+
expect(container.resolve(:item).call).to eq('item')
|
92
|
+
expect(container[:item].call).to eq('item')
|
93
|
+
end
|
37
94
|
end
|
38
95
|
end
|
39
|
-
end
|
40
96
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
container.register(:item, item)
|
97
|
+
describe 'registering a proc' do
|
98
|
+
context 'without options' do
|
99
|
+
it 'registers and resolves an object' do
|
100
|
+
container.register(:item, proc { 'item' })
|
46
101
|
|
47
|
-
|
48
|
-
|
102
|
+
expect(container.resolve(:item)).to eq('item')
|
103
|
+
expect(container[:item]).to eq('item')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'with option call: false' do
|
108
|
+
it 'registers and resolves a proc' do
|
109
|
+
container.register(:item, proc { 'item' }, call: false)
|
110
|
+
|
111
|
+
expect(container.resolve(:item).call).to eq('item')
|
112
|
+
expect(container[:item].call).to eq('item')
|
113
|
+
end
|
49
114
|
end
|
50
115
|
end
|
51
116
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
117
|
+
describe 'registering an object' do
|
118
|
+
context 'without options' do
|
119
|
+
it 'registers and resolves the object' do
|
120
|
+
item = 'item'
|
121
|
+
container.register(:item, item)
|
56
122
|
|
57
|
-
|
58
|
-
|
123
|
+
expect(container.resolve(:item)).to be(item)
|
124
|
+
expect(container[:item]).to be(item)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'with option call: false' do
|
129
|
+
it 'registers and resolves an object' do
|
130
|
+
item = -> { 'test' }
|
131
|
+
container.register(:item, item, call: false)
|
132
|
+
|
133
|
+
expect(container.resolve(:item)).to eq(item)
|
134
|
+
expect(container[:item]).to eq(item)
|
135
|
+
end
|
59
136
|
end
|
60
137
|
end
|
61
|
-
end
|
62
138
|
|
63
|
-
|
64
|
-
|
65
|
-
|
139
|
+
describe 'registering with the same key multiple times' do
|
140
|
+
it do
|
141
|
+
container.register(:item, proc { 'item' })
|
66
142
|
|
67
|
-
|
143
|
+
expect { container.register(:item, proc { 'item' }) }.to raise_error(Dry::Container::Error)
|
144
|
+
end
|
68
145
|
end
|
69
|
-
end
|
70
146
|
|
71
|
-
|
72
|
-
|
73
|
-
|
147
|
+
describe 'resolving with a key that has not been registered' do
|
148
|
+
it do
|
149
|
+
expect { container.resolve(:item) }.to raise_error(Dry::Container::Error)
|
150
|
+
end
|
74
151
|
end
|
75
152
|
end
|
76
153
|
end
|
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.2.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: 2015-06-
|
11
|
+
date: 2015-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thread_safe
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dry-configurable
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.1.0
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -87,6 +101,8 @@ files:
|
|
87
101
|
- lib/dry/container/error.rb
|
88
102
|
- lib/dry/container/item.rb
|
89
103
|
- lib/dry/container/mixin.rb
|
104
|
+
- lib/dry/container/registry.rb
|
105
|
+
- lib/dry/container/resolver.rb
|
90
106
|
- lib/dry/container/version.rb
|
91
107
|
- rakelib/rubocop.rake
|
92
108
|
- spec/integration/container_spec.rb
|