dry-container 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 35fd3e8023c0220150dade45164cdefbe011633c
4
- data.tar.gz: 4060a17b5831ef9c1fe7aa4440e0c34ef7d8fb4e
2
+ SHA256:
3
+ metadata.gz: d9983b02db6de06274a1233f9bfa5c0e8ab2c9df34fc15f2f801619912335265
4
+ data.tar.gz: d34942c991fcee5e85e67fb7b345105726ed28a3fd0ef04524514b37739b8f4e
5
5
  SHA512:
6
- metadata.gz: 9e1f8876a5ea3cdb77b8516e1d85481ed86b58d70c8d41aa77d71c45fbf30bdd1b4c226a60a50a0795fde809934461a8c72ff6225b6a2b4b9bd6e468cb369709
7
- data.tar.gz: bf68f2feb7608a30d851f69c7e370741a0cf2af50e539abe027cad53ce3714b7965b8964266b5e045fabb43fcdcb6f86f95b9398de874b8f7752cf4c56797558
6
+ metadata.gz: fab850d709bbcc1f22ee2b50c4dc59aa79773ce7bcdec40278aa7ac2a0df4780a3b2f82bb409a711de6a13a69a92a2bf591ff326df992129f9afcd4578403242
7
+ data.tar.gz: 1f258852df4376546fbf2ce5ee1cabb14d97d6e434c9c94df5568c689aae2debbd4406d2f657703901a0001caa73df1850475fc532579395d1895efb2be3dc76
@@ -8,22 +8,15 @@ script:
8
8
  after_success:
9
9
  - '[ -d coverage ] && bundle exec codeclimate-test-reporter'
10
10
  rvm:
11
- - 2.0
12
- - 2.1
13
- - 2.2
14
- - 2.3.1
15
- - rbx-3
16
- - jruby-9.1.5.0
17
- - ruby-head
18
- - jruby-head
11
+ - 2.3.8
12
+ - 2.4.5
13
+ - 2.5.3
14
+ - 2.6.1
15
+ - jruby-9.2.5.0
19
16
  env:
20
17
  global:
21
18
  - JRUBY_OPTS='--dev -J-Xmx1024M'
22
19
  - COVERAGE='true'
23
- matrix:
24
- allow_failures:
25
- - rvm: ruby-head
26
- - rvm: jruby-head
27
20
  notifications:
28
21
  email: false
29
22
  webhooks:
@@ -1,10 +1,60 @@
1
- ## Unreleased
1
+ ## v0.7.0 - 2019-02-05
2
+
3
+ ## Changed
4
+
5
+ * [BREAKING] Now only Ruby 2.3 and above is supported ([flash-gordon](https://github.com/flash-gordon))
6
+
7
+ ## Fixed
8
+
9
+ * Symbols are now coerced to strings when resolving stubbed dependencies ([cthulhu666](https://github.com/cthulhu666))
10
+ * Stubbing keys not present in container will raise an error ([flash-gordon](https://github.com/flash-gordon))
11
+
12
+ This means after upgrading you may see errors like this
13
+ ```
14
+ ArgumentError (cannot stub "something" - no such key in container)
15
+ ```
16
+ Be sure you register dependencies before using them. The new behavior will likely save quite a bit of time when debugging ill-configured container setups.
17
+
18
+ ## Added
19
+
20
+ * Namespace DSL resolves keys relative to the current namespace, see the corresponding [changes](https://github.com/dry-rb/dry-container/pull/47) ([yuszuv](https://github.com/yuszuv))
21
+ * Registered objects can be decorated with the following API ([igor-alexandrov](https://github.com/igor-alexandrov))
22
+
23
+ ```ruby
24
+ class CreateUser
25
+ def call(params)
26
+ # ...
27
+ end
28
+ end
29
+ container.register('create_user') { CreateUser.new }
30
+ container.decorate('create_user', with: ShinyLogger.new)
31
+
32
+ # Now subsequent resolutions will return a wrapped object
33
+
34
+ container.resolve('create_user')
35
+ # => #<ShinyLogger @obj=#<CreateUser:0x...>]>
36
+ ```
37
+ * Freezing a container now prevents further registrations ([flash-gordon](https://github.com/flash-gordon))
38
+
39
+ ## Internal
40
+
41
+ * Handling container items was generalized in [#34](https://github.com/dry-rb/dry-container/pull/34) ([GabrielMalakias](https://github.com/GabrielMalakias))
42
+
43
+ [Compare v0.6.0...HEAD](https://github.com/dry-rb/dry-container/compare/v0.6.0...v0.7.0)
44
+
45
+ ## v0.6.0 - 2019-12-09
2
46
 
3
47
  ## Added
4
48
 
5
49
  * `Dry::Container::Mixin#each` - provides a means of seeing what all is registered in the container ([jeremyf](https://github.com/jeremyf))
6
50
 
7
- ## v0.5.0
51
+ ## Fixed
52
+
53
+ * Including mixin into a class with a custom initializer ([maltoe](https://github.com/maltoe))
54
+
55
+ [Compare v0.5.0...v0.6.0](https://github.com/dry-rb/dry-container/compare/v0.5.0...v0.6.0)
56
+
57
+ ## v0.5.0 - 2016-08-31
8
58
 
9
59
  ## Added
10
60
 
@@ -14,4 +64,4 @@
14
64
 
15
65
  * `required_ruby_version` set to `>= 2.0.0` ([artofhuman](https://github.com/artofhuman))
16
66
 
17
- [Compare v0.4.0...HEAD](https://github.com/dry-rb/dry-container/compare/v0.4.0...v0.5.0)
67
+ [Compare v0.4.0...v0.5.0](https://github.com/dry-rb/dry-container/compare/v0.4.0...v0.5.0)
@@ -0,0 +1,29 @@
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 CHANGED
@@ -15,4 +15,5 @@ group :tools do
15
15
  gem 'guard-rspec'
16
16
  gem 'guard-rubocop'
17
17
  gem 'listen', '3.0.6'
18
+ gem 'pry-byebug', platform: :mri
18
19
  end
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014 Ruby Object Mapper
3
+ Copyright (c) 2015-2017 dry-container
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -1,171 +1,23 @@
1
1
  [gitter]: https://gitter.im/dry-rb/chat
2
2
  [gem]: https://rubygems.org/gems/dry-container
3
3
  [travis]: https://travis-ci.org/dry-rb/dry-container
4
- [code_climate]: https://codeclimate.com/github/dry-rb/dry-container
4
+ [maintainability]: https://codeclimate.com/github/dry-rb/dry-container/maintainability
5
+ [test_coverage]: https://codeclimate.com/github/dry-rb/dry-container/test_coverage
5
6
  [inch]: http://inch-ci.org/github/dry-rb/dry-container
6
7
 
7
8
  # dry-container [![Join the Gitter chat](https://badges.gitter.im/Join%20Chat.svg)][gitter]
8
9
 
9
10
  [![Gem Version](https://img.shields.io/gem/v/dry-container.svg)][gem]
10
11
  [![Build Status](https://img.shields.io/travis/dry-rb/dry-container.svg)][travis]
11
- [![Code Climate](https://img.shields.io/codeclimate/github/dry-rb/dry-container.svg)][code_climate]
12
- [![Test Coverage](https://img.shields.io/codeclimate/coverage/github/dry-rb/dry-container.svg)][code_climate]
12
+ [![Maintainability](https://api.codeclimate.com/v1/badges/97faf9446cb5811100e7/maintainability)][maintainability]
13
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/97faf9446cb5811100e7/test_coverage)][test_coverage]
13
14
  [![API Documentation Coverage](http://inch-ci.org/github/dry-rb/dry-container.svg)][inch]
14
15
 
15
-
16
16
  A simple, configurable container implemented in Ruby.
17
17
 
18
- ## Synopsis
19
-
20
- ### Brief Example
21
-
22
- ```ruby
23
- container = Dry::Container.new
24
- container.register(:parrot) { |a| puts a }
25
-
26
- parrot = container.resolve(:parrot)
27
- parrot.call("Hello World")
28
- # Hello World
29
- # => nil
30
- ```
31
-
32
- See [Dry::AutoInject Usage](https://github.com/dry-rb/dry-auto_inject#usage) for additional details.
33
-
34
- ### Detailed Example
35
-
36
- ```ruby
37
- User = Struct.new(:name, :email)
38
-
39
- data_store = Concurrent::Map.new.tap do |ds|
40
- ds[:users] = Concurrent::Array.new
41
- end
42
-
43
- # Initialize container
44
- container = Dry::Container.new
45
-
46
- # Register an item with the container to be resolved later
47
- container.register(:data_store, data_store)
48
- container.register(:user_repository, -> { container.resolve(:data_store)[:users] })
49
-
50
- # Resolve an item from the container
51
- container.resolve(:user_repository) << User.new('Jack', 'jack@dry-container.com')
52
- # You can also resolve with []
53
- container[:user_repository] << User.new('Jill', 'jill@dry-container.com')
54
- # => [
55
- # #<struct User name="Jack", email="jack@dry-container.com">,
56
- # #<struct User name="Jill", email="jill@dry-container.com">
57
- # ]
58
-
59
- # If you wish to register an item that responds to call but don't want it to be
60
- # called when resolved, you can use the options hash
61
- container.register(:proc, -> { :result }, call: false)
62
- container.resolve(:proc)
63
- # => #<Proc:0x007fa75e652c98@(irb):25 (lambda)>
64
-
65
- # You can also register using a block
66
- container.register(:item) do
67
- :result
68
- end
69
- container.resolve(:item)
70
- # => :result
71
-
72
- container.register(:block, call: false) do
73
- :result
74
- end
75
- container.resolve(:block)
76
- # => #<Proc:0x007fa75e6830f0@(irb):36>
77
-
78
- # You can also register items under namespaces using the #namespace method
79
- container.namespace('repositories') do
80
- namespace('checkout') do
81
- register('orders') { Concurrent::Array.new }
82
- end
83
- end
84
- container.resolve('repositories.checkout.orders')
85
- # => []
86
-
87
- # Or import a namespace
88
- ns = Dry::Container::Namespace.new('repositories') do
89
- namespace('authentication') do
90
- register('users') { Concurrent::Array.new }
91
- end
92
- end
93
- container.import(ns)
94
- container.resolve('repositories.authentication.users')
95
- # => []
96
-
97
- # You can also register a block that is used to initialize a dependency and
98
- # then memoize it, allowing several dependencies to be added without
99
- # enforcing an instantiation order
100
- class MessagePrinter
101
- def initialize(container)
102
- @message = container.resolve(:message)
103
- @time = Time.now
104
- end
105
-
106
- def print
107
- puts "#{@message} at #{@time}"
108
- end
109
- end
110
-
111
- container.register(:message_printer, -> { MessagePrinter.new(container) }, memoize: true)
112
- container.register(:message, 'Hello, world!')
113
- container.resolve(:message_printer).print
114
- # => Hello, world! at 2016-08-30 05:32:12 -0700
115
-
116
- # Same instance is reused next time
117
- container.resolve(:message_printer).print
118
- # => Hello, world! at 2016-08-30 05:32:12 -0700
119
- ```
120
-
121
- You can also get container behaviour at both the class and instance level via the mixin:
122
-
123
- ```ruby
124
- class Container
125
- extend Dry::Container::Mixin
126
- end
127
- Container.register(:item, :my_item)
128
- Container.resolve(:item)
129
- # => :my_item
130
-
131
- class ContainerObject
132
- include Dry::Container::Mixin
133
- end
134
- container = ContainerObject.new
135
- container.register(:item, :my_item)
136
- container.resolve(:item)
137
- # => :my_item
138
- ```
139
- ### Using a custom registry/resolver
140
-
141
- You can configure how items are registered and resolved from the container:
142
-
143
- ```ruby
144
- Dry::Container.configure do |config|
145
- config.registry = ->(container, key, item, options) { container[key] = item }
146
- config.resolver = ->(container, key) { container[key] }
147
- end
148
-
149
- class Container
150
- extend Dry::Container::Mixin
151
-
152
- configure do |config|
153
- config.registry = ->(container, key, item, options) { container[key] = item }
154
- config.resolver = ->(container, key) { container[key] }
155
- end
156
- end
157
-
158
- class ContainerObject
159
- include Dry::Container::Mixin
160
-
161
- configure do |config|
162
- config.registry = ->(container, key, item, options) { container[key] = item }
163
- config.resolver = ->(container, key) { container[key] }
164
- end
165
- end
166
- ```
18
+ ## Links
167
19
 
168
- 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.
20
+ [Documentation](http://dry-rb.org/gems/dry-container/)
169
21
 
170
22
  ## License
171
23
 
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  require File.expand_path('../lib/dry/container/version', __FILE__)
3
2
 
4
3
  Gem::Specification.new do |spec|
@@ -7,7 +6,7 @@ Gem::Specification.new do |spec|
7
6
  spec.authors = ['Andy Holland']
8
7
  spec.email = ['andyholland1991@aol.com']
9
8
  spec.summary = 'A simple container intended for use as an IoC container'
10
- spec.homepage = 'https://github.com/dryrb/dry-container'
9
+ spec.homepage = 'https://github.com/dry-rb/dry-container'
11
10
  spec.license = 'MIT'
12
11
 
13
12
  spec.files = `git ls-files -z`.split("\x0")
@@ -15,7 +14,7 @@ Gem::Specification.new do |spec|
15
14
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
15
  spec.require_paths = ['lib']
17
16
 
18
- spec.required_ruby_version = ">= 2.0.0"
17
+ spec.required_ruby_version = '>= 2.3.0'
19
18
 
20
19
  spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
21
20
  spec.add_runtime_dependency 'dry-configurable', '~> 0.1', '>= 0.1.3'
@@ -1,7 +1,5 @@
1
- require 'concurrent'
2
1
  require 'dry-configurable'
3
2
  require 'dry/container/error'
4
- require 'dry/container/item'
5
3
  require 'dry/container/namespace'
6
4
  require 'dry/container/registry'
7
5
  require 'dry/container/resolver'
@@ -1,6 +1,6 @@
1
1
  module Dry
2
2
  class Container
3
3
  # @api public
4
- class Error < ::StandardError; end
4
+ Error = Class.new(StandardError)
5
5
  end
6
6
  end
@@ -1,43 +1,27 @@
1
1
  module Dry
2
2
  class Container
3
- # Container class
3
+ # Base class to abstract Memoizable and Callable implementations
4
+ #
5
+ # @api abstract
4
6
  #
5
- # @private
6
7
  class Item
7
- attr_reader :item, :options, :memoize, :memoize_mutex
8
+ # @return [Mixed] the item to be solved later
9
+ attr_reader :item
10
+
11
+ # @return [Hash] the options to memoize, call or no.
12
+ attr_reader :options
8
13
 
14
+ # @api abstract
9
15
  def initialize(item, options = {})
10
16
  @item = item
11
17
  @options = {
12
18
  call: item.is_a?(::Proc) && item.parameters.empty?
13
19
  }.merge(options)
14
-
15
- if options[:memoize] == true
16
- raise(
17
- ::Dry::Container::Error,
18
- 'Memoize only supported for a block or a proc'
19
- ) unless item.is_a?(::Proc)
20
- @memoize = true
21
- @memoize_mutex = ::Mutex.new
22
- end
23
20
  end
24
21
 
22
+ # @api abstract
25
23
  def call
26
- return memoized_item if memoize
27
-
28
- if options[:call] == true
29
- item.call
30
- else
31
- item
32
- end
33
- end
34
-
35
- private
36
-
37
- def memoized_item
38
- memoize_mutex.synchronize do
39
- @memoized_item ||= item.call
40
- end
24
+ raise NotImplementedError
41
25
  end
42
26
  end
43
27
  end
@@ -0,0 +1,27 @@
1
+ require 'dry/container/item'
2
+
3
+ module Dry
4
+ class Container
5
+ class Item
6
+ # Callable class to returns a item call
7
+ #
8
+ # @api public
9
+ #
10
+ class Callable < Item
11
+ # Returns the result of item call or item
12
+ #
13
+ # @return [Mixed]
14
+ def call
15
+ callable? ? item.call : item
16
+ end
17
+
18
+ private
19
+
20
+ # @private
21
+ def callable?
22
+ options[:call]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ require 'dry/container/item/memoizable'
2
+ require 'dry/container/item/callable'
3
+
4
+ module Dry
5
+ class Container
6
+ class Item
7
+ # Factory for create an Item to register inside of container
8
+ #
9
+ # @api public
10
+ class Factory
11
+ # Creates an Item Memoizable or Callable
12
+ # @param [Mixed] item
13
+ # @param [Hash] options
14
+ #
15
+ # @raise [Dry::Container::Error]
16
+ #
17
+ # @return [Dry::Container::Item::Base]
18
+ def call(item, options = {})
19
+ options[:memoize] ? Memoizable.new(item, options) : Callable.new(item, options)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,49 @@
1
+ require 'dry/container/item'
2
+
3
+ module Dry
4
+ class Container
5
+ class Item
6
+ # Memoizable class to store and execute item calls
7
+ #
8
+ # @api public
9
+ #
10
+ class Memoizable < Item
11
+ # @return [Mutex] the stored mutex
12
+ attr_reader :memoize_mutex
13
+
14
+ # Returns a new Memoizable instance
15
+ #
16
+ # @param [Mixed] item
17
+ # @param [Hash] options
18
+ #
19
+ # @raise [Dry::Container::Error]
20
+ #
21
+ # @return [Dry::Container::Item::Base]
22
+ def initialize(item, options = {})
23
+ super
24
+ raise_not_supported_error unless item.is_a?(::Proc)
25
+
26
+ @memoize_mutex = ::Mutex.new
27
+ end
28
+
29
+ # Returns the result of item call using a syncronized mutex
30
+ #
31
+ # @return [Dry::Container::Item::Base]
32
+ def call
33
+ memoize_mutex.synchronize do
34
+ @memoized_item ||= item.call
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # @private
41
+ def raise_not_supported_error
42
+ raise ::Dry::Container::Error, 'Memoize only supported for a block or a proc'.freeze
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+
@@ -1,6 +1,9 @@
1
+
2
+ require 'concurrent/hash'
3
+
1
4
  module Dry
2
5
  class Container
3
- PREFIX_NAMESPACE = ->(namespace, key, config) do
6
+ PREFIX_NAMESPACE = lambda do |namespace, key, config|
4
7
  [namespace, key].join(config.namespace_separator)
5
8
  end
6
9
  # Mixin to expose Inversion of Control (IoC) container behaviour
@@ -129,8 +132,7 @@ module Dry
129
132
  #
130
133
  # @param [Dry::Container] other
131
134
  # The other container to merge in
132
- # @param [Hash] options
133
- # @option options [Symbol] :namespace
135
+ # @param [Symbol, nil] namespace
134
136
  # Namespace to prefix other container items with, defaults to nil
135
137
  #
136
138
  # @return [Dry::Container::Mixin] self
@@ -150,7 +152,7 @@ module Dry
150
152
  self
151
153
  end
152
154
 
153
- # Check whether an items is registered under the given key
155
+ # Check whether an item is registered under the given key
154
156
  #
155
157
  # @param [Mixed] key
156
158
  # The key you wish to check for registration with
@@ -198,6 +200,25 @@ module Dry
198
200
  config.resolver.each(_container, &block)
199
201
  end
200
202
 
203
+ # Decorates an item from the container with specified decorator
204
+ #
205
+ # @return [Dry::Container::Mixin] self
206
+ #
207
+ # @api public
208
+ def decorate(key, with:)
209
+ original = _container.delete(key.to_s) do
210
+ raise Error, "Nothing registered with the key #{key.inspect}"
211
+ end
212
+
213
+ decorator = with
214
+
215
+ if decorator.is_a?(Class)
216
+ register(key, decorator.new(original.call))
217
+ else
218
+ register(key, decorator)
219
+ end
220
+ end
221
+
201
222
  # Evaluate block and register items in namespace
202
223
  #
203
224
  # @param [Mixed] namespace
@@ -231,6 +252,15 @@ module Dry
231
252
  self
232
253
  end
233
254
 
255
+ # Freeze the container. Nothing can be registered after freezing
256
+ #
257
+ # @api public
258
+ def freeze
259
+ super
260
+ _container.freeze
261
+ self
262
+ end
263
+
234
264
  # @private no, really
235
265
  def _container
236
266
  @_container
@@ -1,3 +1,5 @@
1
+ require 'delegate'
2
+
1
3
  module Dry
2
4
  class Container
3
5
  # @api private
@@ -43,6 +45,10 @@ module Dry
43
45
  self
44
46
  end
45
47
 
48
+ def resolve(key)
49
+ super(namespaced(key))
50
+ end
51
+
46
52
  private
47
53
 
48
54
  def namespaced(key)
@@ -1,3 +1,5 @@
1
+ require 'dry/container/item/factory'
2
+
1
3
  module Dry
2
4
  class Container
3
5
  # Default registry for registering items with the container
@@ -34,9 +36,13 @@ module Dry
34
36
  raise Error, "There is already an item registered with the key #{key.inspect}"
35
37
  end
36
38
 
37
- container[key] = ::Dry::Container::Item.new(item, options)
39
+ container[key] = factory.call(item, options)
38
40
  end
39
41
  end
42
+
43
+ def factory
44
+ @factory ||= ::Dry::Container::Item::Factory.new
45
+ end
40
46
  end
41
47
  end
42
48
  end
@@ -48,7 +48,6 @@ module Dry
48
48
  container.keys
49
49
  end
50
50
 
51
-
52
51
  # Calls block once for each key in container, passing the key as a parameter.
53
52
  #
54
53
  # If no block is given, an enumerator is returned instead.
@@ -5,12 +5,16 @@ module Dry
5
5
  #
6
6
  # @api public
7
7
  def resolve(key)
8
- _stubs.fetch(key) { super }
8
+ _stubs.fetch(key.to_s) { super }
9
9
  end
10
10
 
11
11
  # Add a stub to the container
12
12
  def stub(key, value, &block)
13
- _stubs[key] = value
13
+ unless key?(key)
14
+ raise ArgumentError, "cannot stub #{ key.to_s.inspect } - no such key in container"
15
+ end
16
+
17
+ _stubs[key.to_s] = value
14
18
 
15
19
  if block
16
20
  yield
@@ -23,11 +27,12 @@ module Dry
23
27
  # Remove stubbed keys from the container
24
28
  def unstub(*keys)
25
29
  keys = _stubs.keys if keys.empty?
26
- keys.each { |key| _stubs.delete(key) }
30
+ keys.each { |key| _stubs.delete(key.to_s) }
27
31
  end
28
32
 
29
33
  # Stubs have already been enabled turning this into a noop
30
34
  def enable_stubs!
35
+ # DO NOTHING
31
36
  end
32
37
 
33
38
  private
@@ -1,6 +1,6 @@
1
1
  module Dry
2
2
  class Container
3
3
  # @api public
4
- VERSION = '0.6.0'.freeze
4
+ VERSION = '0.7.0'.freeze
5
5
  end
6
6
  end
@@ -25,7 +25,7 @@ RSpec.describe Dry::Container::Mixin do
25
25
  end
26
26
 
27
27
  it 'does not fail on missing member variable' do
28
- expect { container.register :key, ->{} }.to_not raise_error
28
+ expect { container.register :key, -> {} }.to_not raise_error
29
29
  end
30
30
  end
31
31
  end
@@ -1,11 +1,21 @@
1
- if ENV['COVERAGE'] == 'true' && RUBY_ENGINE == 'ruby' && RUBY_VERSION == '2.3.1'
2
- require 'simplecov'
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
3
5
 
4
- SimpleCov.start do
5
- add_filter '/spec/'
6
+ if RUBY_VERSION == latest_mri
7
+ require 'simplecov'
8
+ SimpleCov.start do
9
+ add_filter '/spec/'
10
+ end
6
11
  end
7
12
  end
8
13
 
14
+ begin
15
+ require 'pry-byebug'
16
+ rescue LoadError
17
+ end
18
+
9
19
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
10
20
  RSpec.configure do |config|
11
21
  config.expect_with :rspec do |expectations|
@@ -43,7 +53,7 @@ RSpec.configure do |config|
43
53
  # Allows RSpec to persist some state between runs in order to support
44
54
  # the `--only-failures` and `--next-failure` CLI options. We recommend
45
55
  # you configure your source control system to ignore this file.
46
- config.example_status_persistence_file_path = "spec/examples.txt"
56
+ config.example_status_persistence_file_path = 'spec/examples.txt'
47
57
 
48
58
  # Limits the available syntax to the non-monkey patched syntax that is
49
59
  # recommended. For more details, see:
@@ -130,7 +130,7 @@ RSpec.shared_examples 'a container' do
130
130
  end
131
131
 
132
132
  it 'does not call a proc on resolving if one accepts an arbitrary number of keyword arguments' do
133
- container.register(:item) { |**kw| 'item' }
133
+ container.register(:item) { |*| 'item' }
134
134
 
135
135
  expect(container.resolve(:item)).to be_a_kind_of Proc
136
136
  expect(container.resolve(:item).call).to eq('item')
@@ -383,6 +383,36 @@ RSpec.shared_examples 'a container' do
383
383
  end
384
384
  end
385
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
+
386
416
  describe 'namespace' do
387
417
  context 'when block does not take arguments' do
388
418
  before do
@@ -427,6 +457,21 @@ RSpec.shared_examples 'a container' do
427
457
  is_expected.to eq(3)
428
458
  end
429
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
430
475
  end
431
476
 
432
477
  describe 'import' do
@@ -499,5 +544,34 @@ RSpec.shared_examples 'a container' do
499
544
  expect(container.resolve(:item)).to eql('item')
500
545
  end
501
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
502
576
  end
503
577
  end
metadata CHANGED
@@ -1,31 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-container
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Holland
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-09 00:00:00.000000000 Z
11
+ date: 2019-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: concurrent-ruby
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
18
  version: '1.0'
20
- type: :runtime
19
+ name: concurrent-ruby
21
20
  prerelease: false
21
+ type: :runtime
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: dry-configurable
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
@@ -34,8 +33,9 @@ dependencies:
34
33
  - - ">="
35
34
  - !ruby/object:Gem::Version
36
35
  version: 0.1.3
37
- type: :runtime
36
+ name: dry-configurable
38
37
  prerelease: false
38
+ type: :runtime
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - "~>"
@@ -45,48 +45,48 @@ dependencies:
45
45
  - !ruby/object:Gem::Version
46
46
  version: 0.1.3
47
47
  - !ruby/object:Gem::Dependency
48
- name: bundler
49
48
  requirement: !ruby/object:Gem::Requirement
50
49
  requirements:
51
50
  - - ">="
52
51
  - !ruby/object:Gem::Version
53
52
  version: '0'
54
- type: :development
53
+ name: bundler
55
54
  prerelease: false
55
+ type: :development
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
60
  version: '0'
61
61
  - !ruby/object:Gem::Dependency
62
- name: rake
63
62
  requirement: !ruby/object:Gem::Requirement
64
63
  requirements:
65
64
  - - ">="
66
65
  - !ruby/object:Gem::Version
67
66
  version: '0'
68
- type: :development
67
+ name: rake
69
68
  prerelease: false
69
+ type: :development
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  - !ruby/object:Gem::Dependency
76
- name: rspec
77
76
  requirement: !ruby/object:Gem::Requirement
78
77
  requirements:
79
78
  - - ">="
80
79
  - !ruby/object:Gem::Version
81
80
  version: '0'
82
- type: :development
81
+ name: rspec
83
82
  prerelease: false
83
+ type: :development
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - ">="
87
87
  - !ruby/object:Gem::Version
88
88
  version: '0'
89
- description:
89
+ description:
90
90
  email:
91
91
  - andyholland1991@aol.com
92
92
  executables: []
@@ -100,6 +100,7 @@ files:
100
100
  - ".rubocop_todo.yml"
101
101
  - ".travis.yml"
102
102
  - CHANGELOG.md
103
+ - CONTRIBUTING.md
103
104
  - Gemfile
104
105
  - LICENSE
105
106
  - README.md
@@ -109,6 +110,9 @@ files:
109
110
  - lib/dry/container.rb
110
111
  - lib/dry/container/error.rb
111
112
  - lib/dry/container/item.rb
113
+ - lib/dry/container/item/callable.rb
114
+ - lib/dry/container/item/factory.rb
115
+ - lib/dry/container/item/memoizable.rb
112
116
  - lib/dry/container/mixin.rb
113
117
  - lib/dry/container/namespace.rb
114
118
  - lib/dry/container/namespace_dsl.rb
@@ -121,11 +125,11 @@ files:
121
125
  - spec/integration/mixin_spec.rb
122
126
  - spec/spec_helper.rb
123
127
  - spec/support/shared_examples/container.rb
124
- homepage: https://github.com/dryrb/dry-container
128
+ homepage: https://github.com/dry-rb/dry-container
125
129
  licenses:
126
130
  - MIT
127
131
  metadata: {}
128
- post_install_message:
132
+ post_install_message:
129
133
  rdoc_options: []
130
134
  require_paths:
131
135
  - lib
@@ -133,16 +137,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
137
  requirements:
134
138
  - - ">="
135
139
  - !ruby/object:Gem::Version
136
- version: 2.0.0
140
+ version: 2.3.0
137
141
  required_rubygems_version: !ruby/object:Gem::Requirement
138
142
  requirements:
139
143
  - - ">="
140
144
  - !ruby/object:Gem::Version
141
145
  version: '0'
142
146
  requirements: []
143
- rubyforge_project:
144
- rubygems_version: 2.5.1
145
- signing_key:
147
+ rubyforge_project:
148
+ rubygems_version: 2.7.6
149
+ signing_key:
146
150
  specification_version: 4
147
151
  summary: A simple container intended for use as an IoC container
148
152
  test_files: