dry-container 0.7.0 → 0.9.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/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,102 +0,0 @@
1
- if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
2
- require 'yaml'
3
- rubies = YAML.load(File.read(File.join(__dir__, '..', '.travis.yml')))['rvm']
4
- latest_mri = rubies.select { |v| v =~ /\A\d+\.\d+.\d+\z/ }.max
5
-
6
- if RUBY_VERSION == latest_mri
7
- require 'simplecov'
8
- SimpleCov.start do
9
- add_filter '/spec/'
10
- end
11
- end
12
- end
13
-
14
- begin
15
- require 'pry-byebug'
16
- rescue LoadError
17
- end
18
-
19
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
20
- RSpec.configure do |config|
21
- config.expect_with :rspec do |expectations|
22
- # This option will default to `true` in RSpec 4. It makes the `description`
23
- # and `failure_message` of custom matchers include text for helper methods
24
- # defined using `chain`, e.g.:
25
- # be_bigger_than(2).and_smaller_than(4).description
26
- # # => "be bigger than 2 and smaller than 4"
27
- # ...rather than:
28
- # # => "be bigger than 2"
29
- expectations.include_chain_clauses_in_custom_matcher_descriptions = true
30
- end
31
-
32
- config.mock_with :rspec do |mocks|
33
- # Prevents you from mocking or stubbing a method that does not exist on
34
- # a real object. This is generally recommended, and will default to
35
- # `true` in RSpec 4.
36
- mocks.verify_partial_doubles = true
37
- end
38
-
39
- # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
40
- # have no way to turn it off -- the option exists only for backwards
41
- # compatibility in RSpec 3). It causes shared context metadata to be
42
- # inherited by the metadata hash of host groups and examples, rather than
43
- # triggering implicit auto-inclusion in groups with matching metadata.
44
- config.shared_context_metadata_behavior = :apply_to_host_groups
45
-
46
- # This allows you to limit a spec run to individual examples or groups
47
- # you care about by tagging them with `:focus` metadata. When nothing
48
- # is tagged with `:focus`, all examples get run. RSpec also provides
49
- # aliases for `it`, `describe`, and `context` that include `:focus`
50
- # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
51
- config.filter_run_when_matching :focus
52
-
53
- # Allows RSpec to persist some state between runs in order to support
54
- # the `--only-failures` and `--next-failure` CLI options. We recommend
55
- # you configure your source control system to ignore this file.
56
- config.example_status_persistence_file_path = 'spec/examples.txt'
57
-
58
- # Limits the available syntax to the non-monkey patched syntax that is
59
- # recommended. For more details, see:
60
- # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
61
- # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
62
- # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
63
- config.disable_monkey_patching!
64
-
65
- # This setting enables warnings. It's recommended, but in some cases may
66
- # be too noisy due to issues in dependencies.
67
- config.warnings = true
68
-
69
- # Many RSpec users commonly either run the entire suite or an individual
70
- # file, and it's useful to allow more verbose output when running an
71
- # individual spec file.
72
- if config.files_to_run.one?
73
- # Use the documentation formatter for detailed output,
74
- # unless a formatter has already been configured
75
- # (e.g. via a command-line flag).
76
- config.default_formatter = 'doc'
77
- end
78
-
79
- # Print the n slowest examples and example groups at the
80
- # end of the spec run, to help surface which specs are running
81
- # particularly slow.
82
- config.profile_examples = 3
83
-
84
- # Run specs in random order to surface order dependencies. If you find an
85
- # order dependency and want to debug it, you can fix the order by providing
86
- # the seed, which is printed after each run.
87
- # --seed 1234
88
- config.order = :random
89
-
90
- # Seed global randomization in this process using the `--seed` CLI option.
91
- # Setting this allows you to use `--seed` to deterministically reproduce
92
- # test failures related to randomization by passing the same `--seed` value
93
- # as the one that triggered the failure.
94
- Kernel.srand config.seed
95
- end
96
-
97
- require 'dry/container'
98
- require 'dry/container/stub'
99
-
100
- Dir[Pathname(__FILE__).dirname.join('support/**/*.rb').to_s].each do |file|
101
- require file
102
- end
@@ -1,577 +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
-
391
- context 'for callable item' do
392
- before do
393
- container.register(key) { "value" }
394
- container.decorate(key, with: SimpleDelegator)
395
- end
396
-
397
- it 'expected to be an instance of SimpleDelegator' do
398
- expect(container.resolve(key)).to be_instance_of(SimpleDelegator)
399
- expect(container.resolve(key).__getobj__).to eql("value")
400
- end
401
- end
402
-
403
- context 'for not callable item' do
404
- before do
405
- container.register(key, call: false) { "value" }
406
- container.decorate(key, with: SimpleDelegator)
407
- end
408
-
409
- it 'expected to be an instance of SimpleDelegator' do
410
- expect(container.resolve(key)).to be_instance_of(SimpleDelegator)
411
- expect(container.resolve(key).__getobj__.call).to eql("value")
412
- end
413
- end
414
- end
415
-
416
- describe 'namespace' do
417
- context 'when block does not take arguments' do
418
- before do
419
- container.namespace('one') do
420
- register('two', 2)
421
- end
422
- end
423
-
424
- subject! { container.resolve('one.two') }
425
-
426
- it 'registers items under the given namespace' do
427
- is_expected.to eq(2)
428
- end
429
- end
430
-
431
- context 'when block takes arguments' do
432
- before do
433
- container.namespace('one') do |c|
434
- c.register('two', 2)
435
- end
436
- end
437
-
438
- subject! { container.resolve('one.two') }
439
-
440
- it 'registers items under the given namespace' do
441
- is_expected.to eq(2)
442
- end
443
- end
444
-
445
- context 'with nesting' do
446
- before do
447
- container.namespace('one') do
448
- namespace('two') do
449
- register('three', 3)
450
- end
451
- end
452
- end
453
-
454
- subject! { container.resolve('one.two.three') }
455
-
456
- it 'registers items under the given namespaces' do
457
- is_expected.to eq(3)
458
- end
459
- end
460
-
461
- context 'with nesting and when block takes arguments' do
462
- before do
463
- container.namespace('one') do |c|
464
- c.register('two', 2)
465
- c.register('three', c.resolve('two'))
466
- end
467
- end
468
-
469
- subject! { container.resolve('one.three') }
470
-
471
- it 'resolves items relative to the namespace' do
472
- is_expected.to eq(2)
473
- end
474
- end
475
- end
476
-
477
- describe 'import' do
478
- it 'allows importing of namespaces' do
479
- ns = Dry::Container::Namespace.new('one') do
480
- register('two', 2)
481
- end
482
-
483
- container.import(ns)
484
-
485
- expect(container.resolve('one.two')).to eq(2)
486
- end
487
-
488
- it 'allows importing of nested namespaces' do
489
- ns = Dry::Container::Namespace.new('two') do
490
- register('three', 3)
491
- end
492
-
493
- container.namespace('one') do
494
- import(ns)
495
- end
496
-
497
- expect(container.resolve('one.two.three')).to eq(3)
498
- end
499
- end
500
- end
501
-
502
- describe 'stubbing' do
503
- before do
504
- container.enable_stubs!
505
-
506
- container.register(:item, 'item')
507
- container.register(:foo, 'bar')
508
- end
509
-
510
- after do
511
- container.unstub
512
- end
513
-
514
- it 'keys can be stubbed' do
515
- container.stub(:item, 'stub')
516
- expect(container.resolve(:item)).to eql('stub')
517
- expect(container[:item]).to eql('stub')
518
- end
519
-
520
- it 'only other keys remain accesible' do
521
- container.stub(:item, 'stub')
522
- expect(container.resolve(:foo)).to eql('bar')
523
- expect(container[:foo]).to eql('bar')
524
- end
525
-
526
- it 'keys can be reverted back to their original value' do
527
- container.stub(:item, 'stub')
528
- container.unstub(:item)
529
-
530
- expect(container.resolve(:item)).to eql('item')
531
- expect(container[:item]).to eql('item')
532
- end
533
-
534
- describe 'with block argument' do
535
- it 'executes the block with the given stubs' do
536
- expect { |b| container.stub(:item, 'stub', &b) }.to yield_control
537
- end
538
-
539
- it 'keys are stubbed only while inside the block' do
540
- container.stub(:item, 'stub') do
541
- expect(container.resolve(:item)).to eql('stub')
542
- end
543
-
544
- expect(container.resolve(:item)).to eql('item')
545
- end
546
- end
547
-
548
- describe 'mixing Strings and Symbols' do
549
- it do
550
- container.stub(:item, 'stub')
551
- expect(container.resolve('item')).to eql('stub')
552
- end
553
- end
554
-
555
- it 'raises an error when key is missing' do
556
- expect { container.stub(:non_existing, 'something') }.
557
- to raise_error(ArgumentError, 'cannot stub "non_existing" - no such key in container')
558
- end
559
- end
560
-
561
- describe '.freeze' do
562
- before do
563
- container.register(:foo, 'bar')
564
- end
565
-
566
- it 'allows to freeze a container so that nothing can be registered later' do
567
- container.freeze
568
- error = RUBY_VERSION >= '2.5' ? FrozenError : RuntimeError
569
- expect { container.register(:baz, 'quux') }.to raise_error(error)
570
- expect(container).to be_frozen
571
- end
572
-
573
- it 'returns self back' do
574
- expect(container.freeze).to be(container)
575
- end
576
- end
577
- end