dry-container 0.7.2 → 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.
data/.codeclimate.yml DELETED
@@ -1,32 +0,0 @@
1
- engines:
2
- rubocop:
3
- enabled: true
4
- checks:
5
- Rubocop/Metrics/LineLength:
6
- enabled: true
7
- max: 120
8
- Rubocop/Style/Documentation:
9
- enabled: false
10
- Rubocop/Lint/HandleExceptions:
11
- enabled: true
12
- exclude:
13
- - rakelib/*.rake
14
- Rubocop/Lint/NestedMethodDefinition:
15
- enabled: true
16
- exclude:
17
- - lib/dry/container/mixin.rb
18
- Rubocop/Metrics/MethodLength:
19
- enabled: true
20
- exclude:
21
- - lib/dry/container/mixin.rb
22
- Rubocop/Style/FileName:
23
- enabled: true
24
- exclude:
25
- - lib/dry-container.rb
26
-
27
- ratings:
28
- paths:
29
- - lib/**/*.rb
30
- exclude_paths:
31
- - spec/**/*
32
- - examples/**/*
data/.gitignore DELETED
@@ -1,10 +0,0 @@
1
- .DS_Store
2
- coverage
3
- /.bundle
4
- vendor/bundle
5
- bin/
6
- tmp/
7
- .idea/
8
- Gemfile.lock
9
- spec/examples.txt
10
- pkg/
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --color
2
- --require ./spec/spec_helper.rb
data/.rubocop.yml DELETED
@@ -1,24 +0,0 @@
1
- # Generated by `rubocop --auto-gen-config`
2
- inherit_from: .rubocop_todo.yml
3
-
4
- Metrics/LineLength:
5
- Max: 120
6
-
7
- Style/Documentation:
8
- Enabled: false
9
-
10
- Lint/HandleExceptions:
11
- Exclude:
12
- - rakelib/*.rake
13
-
14
- Lint/NestedMethodDefinition:
15
- Exclude:
16
- - lib/dry/container/mixin.rb
17
-
18
- Metrics/MethodLength:
19
- Exclude:
20
- - lib/dry/container/mixin.rb
21
-
22
- Style/FileName:
23
- Exclude:
24
- - lib/dry-container.rb
data/.rubocop_todo.yml DELETED
@@ -1,6 +0,0 @@
1
- # This configuration was generated by `rubocop --auto-gen-config`
2
- # on 2015-06-16 19:51:19 +0100 using RuboCop version 0.32.0.
3
- # The point is for the user to remove these configuration records
4
- # one by one as the offenses are removed from the code base.
5
- # Note that changes in the inspected code, or installation of new
6
- # versions of RuboCop, may require this file to be generated again.
data/.travis.yml DELETED
@@ -1,30 +0,0 @@
1
- language: ruby
2
- dist: trusty
3
- sudo: required
4
- cache: bundler
5
- bundler_args: --without console
6
- script:
7
- - bundle exec rake spec
8
- after_success:
9
- - '[ -d coverage ] && bundle exec codeclimate-test-reporter'
10
- rvm:
11
- - 2.4.6
12
- - 2.5.5
13
- - 2.6.3
14
- - jruby-9.2.7.0
15
- - truffleruby
16
- matrix:
17
- allow_failures:
18
- - rvm: truffleruby
19
- env:
20
- global:
21
- - JRUBY_OPTS='--dev -J-Xmx1024M'
22
- - COVERAGE='true'
23
- notifications:
24
- email: false
25
- webhooks:
26
- urls:
27
- - https://webhooks.gitter.im/e/19098b4253a72c9796db
28
- on_success: change # options: [always|never|change] default: always
29
- on_failure: always # options: [always|never|change] default: always
30
- on_start: false # default: false
data/CONTRIBUTING.md DELETED
@@ -1,29 +0,0 @@
1
- # Issue Guidelines
2
-
3
- ## Reporting bugs
4
-
5
- If you found a bug, report an issue and describe what's the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.
6
-
7
- ## Reporting feature requests
8
-
9
- Report a feature request **only after discussing it first on [discourse.dry-rb.org](http://discourse.dry-rb.org)** where it was accepted. Please provide a concise description of the feature, don't link to a discussion thread, and instead summarize what was discussed.
10
-
11
- ## Reporting questions, support requests, ideas, concerns etc.
12
-
13
- **PLEASE DON'T** - use [discourse.dry-rb.org](http://discourse.dry-rb.org) instead.
14
-
15
- # Pull Request Guidelines
16
-
17
- A Pull Request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.
18
-
19
- Other requirements:
20
-
21
- 1) Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.
22
- 2) Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.
23
- 3) Add API documentation if it's a new feature
24
- 4) Update API documentation if it changes an existing feature
25
- 5) Bonus points for sending a PR to [github.com/dry-rb/dry-rb.org](github.com/dry-rb/dry-rb.org) which updates user documentation and guides
26
-
27
- # Asking for help
28
-
29
- If these guidelines aren't helpful, and you're stuck, please post a message on [[discourse.dry-rb.org](http://discourse.dry-rb.org).
data/Gemfile DELETED
@@ -1,19 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- group :test do
6
- platforms :mri do
7
- gem 'codeclimate-test-reporter', require: false
8
- gem 'simplecov', require: false
9
- end
10
- end
11
-
12
- group :tools do
13
- gem 'rubocop'
14
- gem 'guard'
15
- gem 'guard-rspec'
16
- gem 'guard-rubocop'
17
- gem 'listen', '3.0.6'
18
- gem 'pry-byebug', platform: :mri
19
- end
data/Rakefile DELETED
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env rake
2
- require 'bundler/gem_tasks'
3
-
4
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
5
-
6
- require 'rspec/core'
7
- require 'rspec/core/rake_task'
8
-
9
- task default: :spec
10
-
11
- desc 'Run all specs in spec directory'
12
- RSpec::Core::RakeTask.new(:spec)
data/rakelib/rubocop.rake DELETED
@@ -1,18 +0,0 @@
1
- begin
2
- require 'rubocop/rake_task'
3
-
4
- Rake::Task[:default].enhance [:rubocop]
5
-
6
- RuboCop::RakeTask.new do |task|
7
- task.options << '--display-cop-names'
8
- end
9
-
10
- namespace :rubocop do
11
- desc 'Generate a configuration file acting as a TODO list.'
12
- task :auto_gen_config do
13
- exec 'bundle exec rubocop --auto-gen-config'
14
- end
15
- end
16
-
17
- rescue LoadError
18
- end
@@ -1,18 +0,0 @@
1
- RSpec.describe Dry::Container do
2
- let(:klass) { Dry::Container }
3
- let(:container) { klass.new }
4
-
5
- it_behaves_like 'a container'
6
-
7
- describe 'inheritance' do
8
- it 'sets up a container for a child class' do
9
- parent = Class.new { extend Dry::Container::Mixin }
10
- child = Class.new(parent)
11
-
12
- parent.register(:foo, 'foo')
13
- child.register(:foo, 'foo')
14
-
15
- expect(parent[:foo]).to_not be(child[:foo])
16
- end
17
- end
18
- end
@@ -1,32 +0,0 @@
1
- RSpec.describe Dry::Container::Mixin do
2
- describe 'extended' do
3
- let(:klass) do
4
- Class.new { extend Dry::Container::Mixin }
5
- end
6
- let(:container) { klass }
7
-
8
- it_behaves_like 'a container'
9
- end
10
-
11
- describe 'included' do
12
- let(:klass) do
13
- Class.new { include Dry::Container::Mixin }
14
- end
15
- let(:container) { klass.new }
16
-
17
- it_behaves_like 'a container'
18
-
19
- context 'into a class with a custom .initialize method' do
20
- let(:klass) do
21
- Class.new do
22
- include Dry::Container::Mixin
23
- def initialize; end
24
- end
25
- end
26
-
27
- it 'does not fail on missing member variable' do
28
- expect { container.register :key, -> {} }.to_not raise_error
29
- end
30
- end
31
- end
32
- end
data/spec/spec_helper.rb DELETED
@@ -1,104 +0,0 @@
1
- # require 'pathname'
2
-
3
- if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
4
- require 'yaml'
5
- rubies = YAML.load(File.read(File.join(__dir__, '..', '.travis.yml')))['rvm']
6
- latest_mri = rubies.select { |v| v =~ /\A\d+\.\d+.\d+\z/ }.max
7
-
8
- if RUBY_VERSION == latest_mri
9
- require 'simplecov'
10
- SimpleCov.start do
11
- add_filter '/spec/'
12
- end
13
- end
14
- end
15
-
16
- begin
17
- require 'pry-byebug'
18
- rescue LoadError
19
- end
20
-
21
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
22
- RSpec.configure do |config|
23
- config.expect_with :rspec do |expectations|
24
- # This option will default to `true` in RSpec 4. It makes the `description`
25
- # and `failure_message` of custom matchers include text for helper methods
26
- # defined using `chain`, e.g.:
27
- # be_bigger_than(2).and_smaller_than(4).description
28
- # # => "be bigger than 2 and smaller than 4"
29
- # ...rather than:
30
- # # => "be bigger than 2"
31
- expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32
- end
33
-
34
- config.mock_with :rspec do |mocks|
35
- # Prevents you from mocking or stubbing a method that does not exist on
36
- # a real object. This is generally recommended, and will default to
37
- # `true` in RSpec 4.
38
- mocks.verify_partial_doubles = true
39
- end
40
-
41
- # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
42
- # have no way to turn it off -- the option exists only for backwards
43
- # compatibility in RSpec 3). It causes shared context metadata to be
44
- # inherited by the metadata hash of host groups and examples, rather than
45
- # triggering implicit auto-inclusion in groups with matching metadata.
46
- config.shared_context_metadata_behavior = :apply_to_host_groups
47
-
48
- # This allows you to limit a spec run to individual examples or groups
49
- # you care about by tagging them with `:focus` metadata. When nothing
50
- # is tagged with `:focus`, all examples get run. RSpec also provides
51
- # aliases for `it`, `describe`, and `context` that include `:focus`
52
- # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
53
- config.filter_run_when_matching :focus
54
-
55
- # Allows RSpec to persist some state between runs in order to support
56
- # the `--only-failures` and `--next-failure` CLI options. We recommend
57
- # you configure your source control system to ignore this file.
58
- config.example_status_persistence_file_path = 'spec/examples.txt'
59
-
60
- # Limits the available syntax to the non-monkey patched syntax that is
61
- # recommended. For more details, see:
62
- # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
63
- # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
64
- # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
65
- config.disable_monkey_patching!
66
-
67
- # This setting enables warnings. It's recommended, but in some cases may
68
- # be too noisy due to issues in dependencies.
69
- config.warnings = true
70
-
71
- # Many RSpec users commonly either run the entire suite or an individual
72
- # file, and it's useful to allow more verbose output when running an
73
- # individual spec file.
74
- if config.files_to_run.one?
75
- # Use the documentation formatter for detailed output,
76
- # unless a formatter has already been configured
77
- # (e.g. via a command-line flag).
78
- config.default_formatter = 'doc'
79
- end
80
-
81
- # Print the n slowest examples and example groups at the
82
- # end of the spec run, to help surface which specs are running
83
- # particularly slow.
84
- config.profile_examples = 3
85
-
86
- # Run specs in random order to surface order dependencies. If you find an
87
- # order dependency and want to debug it, you can fix the order by providing
88
- # the seed, which is printed after each run.
89
- # --seed 1234
90
- config.order = :random
91
-
92
- # Seed global randomization in this process using the `--seed` CLI option.
93
- # Setting this allows you to use `--seed` to deterministically reproduce
94
- # test failures related to randomization by passing the same `--seed` value
95
- # as the one that triggered the failure.
96
- Kernel.srand config.seed
97
- end
98
-
99
- require 'dry/container'
100
- require 'dry/container/stub'
101
-
102
- Dir[Pathname(__FILE__).dirname.join('support/**/*.rb').to_s].each do |file|
103
- require file
104
- end
@@ -1,664 +0,0 @@
1
- RSpec.shared_examples 'a container' do
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
21
-
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
40
- end
41
- end
42
-
43
- describe 'resolver' do
44
- describe 'default' do
45
- it { expect(klass.config.resolver).to be_a(Dry::Container::Resolver) }
46
- end
47
-
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) }
73
- end
74
- end
75
-
76
- describe 'namespace_separator' do
77
- describe 'default' do
78
- it { expect(klass.config.namespace_separator).to eq('.') }
79
- end
80
-
81
- describe 'custom' do
82
- let(:custom_registry) { double('Registry') }
83
- let(:key) { 'key' }
84
- let(:namespace_separator) { '-' }
85
- let(:namespace) { 'one' }
86
-
87
- before do
88
- klass.configure do |config|
89
- config.namespace_separator = namespace_separator
90
- end
91
-
92
- container.namespace(namespace) do
93
- register('key', 'item')
94
- end
95
- end
96
-
97
- after do
98
- # HACK: Have to reset the configuration so that it doesn't
99
- # interfere with other specs
100
- klass.configure do |config|
101
- config.namespace_separator = '.'
102
- end
103
- end
104
-
105
- subject! { container.resolve([namespace, key].join(namespace_separator)) }
106
-
107
- it { is_expected.to eq('item') }
108
- end
109
- end
110
- end
111
-
112
- context 'with default configuration' do
113
- describe 'registering a block' do
114
- context 'without options' do
115
- context 'without arguments' do
116
- it 'registers and resolves an object' do
117
- container.register(:item) { 'item' }
118
-
119
- expect(container.keys).to eq(['item'])
120
- expect(container.key?(:item)).to be true
121
- expect(container.resolve(:item)).to eq('item')
122
- end
123
- end
124
-
125
- context 'with arguments' do
126
- it 'registers and resolves a proc' do
127
- container.register(:item) { |item| item }
128
-
129
- expect(container.resolve(:item).call('item')).to eq('item')
130
- end
131
-
132
- it 'does not call a proc on resolving if one accepts an arbitrary number of keyword arguments' do
133
- container.register(:item) { |*| 'item' }
134
-
135
- expect(container.resolve(:item)).to be_a_kind_of Proc
136
- expect(container.resolve(:item).call).to eq('item')
137
- end
138
- end
139
- end
140
-
141
- context 'with option call: false' do
142
- it 'registers and resolves a proc' do
143
- container.register(:item, call: false) { 'item' }
144
-
145
- expect(container.keys).to eq(['item'])
146
- expect(container.key?(:item)).to be true
147
- expect(container.resolve(:item).call).to eq('item')
148
- expect(container[:item].call).to eq('item')
149
- end
150
- end
151
- end
152
-
153
- describe 'registering a proc' do
154
- context 'without options' do
155
- context 'without arguments' do
156
- it 'registers and resolves an object' do
157
- container.register(:item, proc { 'item' })
158
-
159
- expect(container.keys).to eq(['item'])
160
- expect(container.key?(:item)).to be true
161
- expect(container.resolve(:item)).to eq('item')
162
- expect(container[:item]).to eq('item')
163
- end
164
- end
165
-
166
- context 'with arguments' do
167
- it 'registers and resolves a proc' do
168
- container.register(:item, proc { |item| item })
169
-
170
- expect(container.keys).to eq(['item'])
171
- expect(container.key?(:item)).to be true
172
- expect(container.resolve(:item).call('item')).to eq('item')
173
- expect(container[:item].call('item')).to eq('item')
174
- end
175
- end
176
- end
177
-
178
- context 'with option call: false' do
179
- it 'registers and resolves a proc' do
180
- container.register(:item, proc { 'item' }, call: false)
181
-
182
- expect(container.keys).to eq(['item'])
183
- expect(container.key?(:item)).to be true
184
- expect(container.resolve(:item).call).to eq('item')
185
- expect(container[:item].call).to eq('item')
186
- end
187
- end
188
-
189
- context 'with option memoize: true' do
190
- it 'registers and resolves a proc' do
191
- container.register(:item, proc { 'item' }, memoize: true)
192
-
193
- expect(container[:item]).to be container[:item]
194
- expect(container.keys).to eq(['item'])
195
- expect(container.key?(:item)).to be true
196
- expect(container.resolve(:item)).to eq('item')
197
- expect(container[:item]).to eq('item')
198
- end
199
-
200
- it 'only resolves the proc once' do
201
- resolved_times = 0
202
-
203
- container.register(:item, proc { resolved_times += 1 }, memoize: true)
204
-
205
- expect(container.resolve(:item)).to be 1
206
- expect(container.resolve(:item)).to be 1
207
- end
208
-
209
- context 'when receiving something other than a proc' do
210
- it do
211
- expect { container.register(:item, 'Hello!', memoize: true) }.to raise_error(Dry::Container::Error)
212
- end
213
- end
214
- end
215
- end
216
-
217
- describe 'registering an object' do
218
- context 'without options' do
219
- it 'registers and resolves the object' do
220
- item = 'item'
221
- container.register(:item, item)
222
-
223
- expect(container.keys).to eq(['item'])
224
- expect(container.key?(:item)).to be true
225
- expect(container.resolve(:item)).to be(item)
226
- expect(container[:item]).to be(item)
227
- end
228
- end
229
-
230
- context 'with option call: false' do
231
- it 'registers and resolves an object' do
232
- item = -> { 'test' }
233
- container.register(:item, item, call: false)
234
-
235
- expect(container.keys).to eq(['item'])
236
- expect(container.key?(:item)).to be true
237
- expect(container.resolve(:item)).to eq(item)
238
- expect(container[:item]).to eq(item)
239
- end
240
- end
241
- end
242
-
243
- describe 'registering with the same key multiple times' do
244
- it do
245
- container.register(:item, proc { 'item' })
246
-
247
- expect { container.register(:item, proc { 'item' }) }.to raise_error(Dry::Container::Error)
248
- end
249
- end
250
-
251
- describe 'resolving with a key that has not been registered' do
252
- it do
253
- expect(container.key?(:item)).to be false
254
- expect { container.resolve(:item) }.to raise_error(Dry::Container::Error)
255
- end
256
- end
257
-
258
- describe 'mixing Strings and Symbols' do
259
- it do
260
- container.register(:item, 'item')
261
- expect(container.resolve('item')).to eql('item')
262
- end
263
- end
264
-
265
- describe '#merge' do
266
- let(:key) { :key }
267
- let(:other) { Dry::Container.new }
268
-
269
- before do
270
- other.register(key) { :item }
271
- end
272
-
273
- context 'without namespace argument' do
274
- subject! { container.merge(other) }
275
-
276
- it { expect(container.resolve(key)).to be(:item) }
277
- it { expect(container[key]).to be(:item) }
278
- end
279
-
280
- context 'with namespace argument' do
281
- subject! { container.merge(other, namespace: namespace) }
282
-
283
- context 'when namespace is nil' do
284
- let(:namespace) { nil }
285
-
286
- it { expect(container.resolve(key)).to be(:item) }
287
- it { expect(container[key]).to be(:item) }
288
- end
289
-
290
- context 'when namespace is not nil' do
291
- let(:namespace) { 'namespace' }
292
-
293
- it { expect(container.resolve("#{namespace}.#{key}")).to be(:item) }
294
- it { expect(container["#{namespace}.#{key}"]).to be(:item) }
295
- end
296
- end
297
- end
298
-
299
- describe '#key?' do
300
- let(:key) { :key }
301
-
302
- before do
303
- container.register(key) { :item }
304
- end
305
-
306
- subject! { container.key?(resolve_key) }
307
-
308
- context 'when key exists in container' do
309
- let(:resolve_key) { key }
310
-
311
- it { is_expected.to be true }
312
- end
313
-
314
- context 'when key does not exist in container' do
315
- let(:resolve_key) { :random }
316
-
317
- it { is_expected.to be false }
318
- end
319
- end
320
-
321
- describe '#keys' do
322
- let(:keys) { [:key_1, :key_2] }
323
- let(:expected_keys) { ['key_1', 'key_2'] }
324
-
325
- before do
326
- keys.each do |key|
327
- container.register(key) { :item }
328
- end
329
- end
330
-
331
- subject! { container.keys }
332
-
333
- it 'returns stringified versions of all registered keys' do
334
- is_expected.to match_array(expected_keys)
335
- end
336
- end
337
-
338
- describe '#each_key' do
339
- let(:keys) { [:key_1, :key_2] }
340
- let(:expected_keys) { ['key_1', 'key_2'] }
341
- let!(:yielded_keys) { [] }
342
-
343
- before do
344
- keys.each do |key|
345
- container.register(key) { :item }
346
- end
347
- end
348
-
349
- subject! do
350
- container.each_key { |key| yielded_keys << key }
351
- end
352
-
353
- it 'yields stringified versions of all registered keys to the block' do
354
- expect(yielded_keys).to match_array(expected_keys)
355
- end
356
-
357
- it 'returns the container' do
358
- is_expected.to eq(container)
359
- end
360
- end
361
-
362
- describe '#each' do
363
- let(:keys) { [:key_1, :key_2] }
364
- let(:expected_key_value_pairs) { [['key_1', 'value_for_key_1'], ['key_2', 'value_for_key_2']] }
365
- let!(:yielded_key_value_pairs) { [] }
366
-
367
- before do
368
- keys.each do |key|
369
- container.register(key) { "value_for_#{key}" }
370
- end
371
- end
372
-
373
- subject! do
374
- container.each { |key, value| yielded_key_value_pairs << [key, value] }
375
- end
376
-
377
- it 'yields stringified versions of all registered keys to the block' do
378
- expect(yielded_key_value_pairs).to match_array(expected_key_value_pairs)
379
- end
380
-
381
- it 'returns the container' do
382
- is_expected.to eq(expected_key_value_pairs)
383
- end
384
- end
385
-
386
- describe '#decorate' do
387
- require 'delegate'
388
-
389
- let(:key) { :key }
390
- let(:decorated_class_spy) { spy(:decorated_class_spy) }
391
- let(:decorated_class) { Class.new }
392
-
393
- context 'for callable item' do
394
- before do
395
- allow(decorated_class_spy).to receive(:new) { decorated_class.new }
396
- container.register(key, memoize: memoize) { decorated_class_spy.new }
397
- container.decorate(key, with: SimpleDelegator)
398
- end
399
-
400
- context 'memoize false' do
401
- let(:memoize) { false }
402
-
403
- it 'does not call the block until the key is resolved' do
404
- expect(decorated_class_spy).not_to have_received(:new)
405
- container.resolve(key)
406
- expect(decorated_class_spy).to have_received(:new)
407
- end
408
-
409
- specify do
410
- expect(container[key]).to be_instance_of(SimpleDelegator)
411
- expect(container[key].__getobj__).to be_instance_of(decorated_class)
412
- expect(container[key]).not_to be(container[key])
413
- expect(container[key].__getobj__).not_to be(container[key].__getobj__)
414
- end
415
- end
416
-
417
- context 'memoize true' do
418
- let(:memoize) { true }
419
-
420
- specify do
421
- expect(container[key]).to be_instance_of(SimpleDelegator)
422
- expect(container[key].__getobj__).to be_instance_of(decorated_class)
423
- expect(container[key]).to be(container[key])
424
- end
425
- end
426
- end
427
-
428
- context 'for not callable item' do
429
- describe 'wrapping' do
430
- before do
431
- container.register(key, call: false) { "value" }
432
- container.decorate(key, with: SimpleDelegator)
433
- end
434
-
435
- it 'expected to be an instance of SimpleDelegator' do
436
- expect(container.resolve(key)).to be_instance_of(SimpleDelegator)
437
- expect(container.resolve(key).__getobj__.call).to eql("value")
438
- end
439
- end
440
-
441
- describe 'memoization' do
442
- before do
443
- @called = 0
444
- container.register(key, 'value')
445
-
446
- container.decorate(key) do |value|
447
- @called += 1
448
- "<#{value}>"
449
- end
450
- end
451
-
452
- it 'decorates static value only once' do
453
- expect(container.resolve(key)).to eql('<value>')
454
- expect(container.resolve(key)).to eql('<value>')
455
- expect(@called).to be(1)
456
- end
457
- end
458
- end
459
-
460
- context 'with an instance as a decorator' do
461
- let(:decorator) do
462
- double.tap do |decorator|
463
- allow(decorator).to receive(:call) { |input| "decorated #{input}" }
464
- end
465
- end
466
-
467
- before do
468
- container.register(key) { "value" }
469
- container.decorate(key, with: decorator)
470
- end
471
-
472
- it 'expected to pass original value to decorator#call method' do
473
- expect(container.resolve(key)).to eq("decorated value")
474
- end
475
- end
476
- end
477
-
478
- describe 'namespace' do
479
- context 'when block does not take arguments' do
480
- before do
481
- container.namespace('one') do
482
- register('two', 2)
483
- end
484
- end
485
-
486
- subject! { container.resolve('one.two') }
487
-
488
- it 'registers items under the given namespace' do
489
- is_expected.to eq(2)
490
- end
491
- end
492
-
493
- context 'when block takes arguments' do
494
- before do
495
- container.namespace('one') do |c|
496
- c.register('two', 2)
497
- end
498
- end
499
-
500
- subject! { container.resolve('one.two') }
501
-
502
- it 'registers items under the given namespace' do
503
- is_expected.to eq(2)
504
- end
505
- end
506
-
507
- context 'with nesting' do
508
- before do
509
- container.namespace('one') do
510
- namespace('two') do
511
- register('three', 3)
512
- end
513
- end
514
- end
515
-
516
- subject! { container.resolve('one.two.three') }
517
-
518
- it 'registers items under the given namespaces' do
519
- is_expected.to eq(3)
520
- end
521
- end
522
-
523
- context 'with nesting and when block takes arguments' do
524
- before do
525
- container.namespace('one') do |c|
526
- c.register('two', 2)
527
- c.register('three', c.resolve('two'))
528
- end
529
- end
530
-
531
- subject! { container.resolve('one.three') }
532
-
533
- it 'resolves items relative to the namespace' do
534
- is_expected.to eq(2)
535
- end
536
- end
537
- end
538
-
539
- describe 'import' do
540
- it 'allows importing of namespaces' do
541
- ns = Dry::Container::Namespace.new('one') do
542
- register('two', 2)
543
- end
544
-
545
- container.import(ns)
546
-
547
- expect(container.resolve('one.two')).to eq(2)
548
- end
549
-
550
- it 'allows importing of nested namespaces' do
551
- ns = Dry::Container::Namespace.new('two') do
552
- register('three', 3)
553
- end
554
-
555
- container.namespace('one') do
556
- import(ns)
557
- end
558
-
559
- expect(container.resolve('one.two.three')).to eq(3)
560
- end
561
- end
562
- end
563
-
564
- describe 'stubbing' do
565
- before do
566
- container.enable_stubs!
567
-
568
- container.register(:item, 'item')
569
- container.register(:foo, 'bar')
570
- end
571
-
572
- after do
573
- container.unstub
574
- end
575
-
576
- it 'keys can be stubbed' do
577
- container.stub(:item, 'stub')
578
- expect(container.resolve(:item)).to eql('stub')
579
- expect(container[:item]).to eql('stub')
580
- end
581
-
582
- it 'only other keys remain accesible' do
583
- container.stub(:item, 'stub')
584
- expect(container.resolve(:foo)).to eql('bar')
585
- expect(container[:foo]).to eql('bar')
586
- end
587
-
588
- it 'keys can be reverted back to their original value' do
589
- container.stub(:item, 'stub')
590
- container.unstub(:item)
591
-
592
- expect(container.resolve(:item)).to eql('item')
593
- expect(container[:item]).to eql('item')
594
- end
595
-
596
- describe 'with block argument' do
597
- it 'executes the block with the given stubs' do
598
- expect { |b| container.stub(:item, 'stub', &b) }.to yield_control
599
- end
600
-
601
- it 'keys are stubbed only while inside the block' do
602
- container.stub(:item, 'stub') do
603
- expect(container.resolve(:item)).to eql('stub')
604
- end
605
-
606
- expect(container.resolve(:item)).to eql('item')
607
- end
608
- end
609
-
610
- describe 'mixing Strings and Symbols' do
611
- it do
612
- container.stub(:item, 'stub')
613
- expect(container.resolve('item')).to eql('stub')
614
- end
615
- end
616
-
617
- it 'raises an error when key is missing' do
618
- expect { container.stub(:non_existing, 'something') }.
619
- to raise_error(ArgumentError, 'cannot stub "non_existing" - no such key in container')
620
- end
621
- end
622
-
623
- describe '.freeze' do
624
- before do
625
- container.register(:foo, 'bar')
626
- end
627
-
628
- it 'allows to freeze a container so that nothing can be registered later' do
629
- container.freeze
630
- error = RUBY_VERSION >= '2.5' ? FrozenError : RuntimeError
631
- expect { container.register(:baz, 'quux') }.to raise_error(error)
632
- expect(container).to be_frozen
633
- end
634
-
635
- it 'returns self back' do
636
- expect(container.freeze).to be(container)
637
- end
638
- end
639
-
640
- describe '.dup' do
641
- it "returns a copy that doesn't share registered keys with the parent" do
642
- container.dup.register(:foo, 'bar')
643
- expect(container.key?(:foo)).to be false
644
- end
645
- end
646
-
647
- describe '.clone' do
648
- it "returns a copy that doesn't share registered keys with the parent" do
649
- container.clone.register(:foo, 'bar')
650
- expect(container.key?(:foo)).to be false
651
- end
652
-
653
- it 're-uses frozen container' do
654
- expect(container.freeze.clone).to be_frozen
655
- expect(container.clone._container).to be(container._container)
656
- end
657
- end
658
-
659
- describe '.resolve' do
660
- it 'accepts a fallback block' do
661
- expect(container.resolve('missing') { :fallback }).to be(:fallback)
662
- end
663
- end
664
- end