dry-container 0.7.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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