smart_container 0.7.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +2 -2
- data/README.md +114 -14
- data/lib/smart_core/container.rb +53 -4
- data/lib/smart_core/container/{arbitary_lock.rb → arbitrary_lock.rb} +1 -1
- data/lib/smart_core/container/definition_dsl.rb +2 -2
- data/lib/smart_core/container/definition_dsl/command_set.rb +1 -1
- data/lib/smart_core/container/dependency_watcher.rb +149 -0
- data/lib/smart_core/container/dependency_watcher/observer.rb +46 -0
- data/lib/smart_core/container/entities/memoized_dependency.rb +1 -1
- data/lib/smart_core/container/entities/namespace.rb +1 -1
- data/lib/smart_core/container/mixin.rb +2 -2
- data/lib/smart_core/container/registry.rb +1 -1
- data/lib/smart_core/container/version.rb +2 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6670714cdeb503df6debb42135ee26283aef48a012fcf2469487668390a675f3
|
4
|
+
data.tar.gz: ba0ad291f05bdebb5d5af7fc46554c30c0748753243e04ac6277abf74886acb6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29b1566aaff6a6227ed13a03a0b65110ce319c4b08bccc50b8c346793cb258174ee611fa19e3950e339049ab50b5819fc31ae6164b2e6d715c8a51d72a29a44f
|
7
|
+
data.tar.gz: cd38836e86ef48c860e58e55af5a30b8f3babdb7724658f96dee7a42ee953a122667688b29bdbb50aeccb94fc4026c1dc17d922524f21a32b20ab67ad7f3ca58
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [0.8.0] - 2020-07-08
|
5
|
+
### Added
|
6
|
+
- An ability to observe dependency re-registrations:
|
7
|
+
- `#observe(path, &observer) # => observer object` - listen specific dependency path;
|
8
|
+
- `#unobserve(observer)` - unsubscribe concrete observer object;
|
9
|
+
- `#clear_observers(path = nil)` - unsubscribe specific listenr or all listeners (`nil` parameter);
|
10
|
+
|
4
11
|
## [0.7.0] - 2020-06-20
|
5
12
|
### Added
|
6
13
|
- `SmartCore::Container.define {}` - an ability to avoid explicit class definition that allows
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
smart_container (0.
|
4
|
+
smart_container (0.8.0)
|
5
5
|
smart_engine (~> 0.5)
|
6
6
|
|
7
7
|
GEM
|
@@ -75,7 +75,7 @@ GEM
|
|
75
75
|
docile (~> 1.1)
|
76
76
|
simplecov-html (~> 0.11)
|
77
77
|
simplecov-html (0.12.2)
|
78
|
-
smart_engine (0.
|
78
|
+
smart_engine (0.7.0)
|
79
79
|
thread_safe (0.3.6)
|
80
80
|
tzinfo (1.2.7)
|
81
81
|
thread_safe (~> 0.1)
|
data/README.md
CHANGED
@@ -22,9 +22,27 @@ require 'smart_core/container'
|
|
22
22
|
|
23
23
|
---
|
24
24
|
|
25
|
-
##
|
25
|
+
## Table of cotnents
|
26
|
+
|
27
|
+
- [Functionality](#functionality)
|
28
|
+
- [container class creation](#container-class-creation)
|
29
|
+
- [mixin](#mixin)
|
30
|
+
- [container instantiation and dependency resolving](#container-instantiation-and-dependency-resolving)
|
31
|
+
- [runtime-level dependency/namespace registration](#runtime-level-dependencynamespace-registration)
|
32
|
+
- [container keys (dependency names)](#container-keys-dependency-names)
|
33
|
+
- [key predicates](#key-predicates)
|
34
|
+
- [state freeze](#state-freeze)
|
35
|
+
- [reloading](#reloading)
|
36
|
+
- [hash tree](#hash-tree)
|
37
|
+
- [explicit class definition](#explicit-class-definition)
|
38
|
+
- [dependency changement observing](#dependency-changement-observing)
|
39
|
+
- [Roadmap](#roadmap)
|
26
40
|
|
27
|
-
|
41
|
+
---
|
42
|
+
|
43
|
+
## Functionality
|
44
|
+
|
45
|
+
#### container class creation
|
28
46
|
|
29
47
|
```ruby
|
30
48
|
class Container < SmartCore::Container
|
@@ -45,7 +63,9 @@ class Container < SmartCore::Container
|
|
45
63
|
end
|
46
64
|
```
|
47
65
|
|
48
|
-
|
66
|
+
---
|
67
|
+
|
68
|
+
#### mixin
|
49
69
|
|
50
70
|
```ruby
|
51
71
|
# full documentaiton is coming;
|
@@ -65,7 +85,9 @@ Application.container
|
|
65
85
|
Application.new.container # NOTE: the same instance as Application.container
|
66
86
|
```
|
67
87
|
|
68
|
-
|
88
|
+
---
|
89
|
+
|
90
|
+
#### container instantiation and dependency resolving
|
69
91
|
|
70
92
|
```ruby
|
71
93
|
container = Container.new # create container instance
|
@@ -90,7 +112,9 @@ container.fetch('database') # => SmartCore::Container (nested container)
|
|
90
112
|
container.fetch('database.resolver') # => #<SomeDatabaseResolver:0x00007f0f0f1d6332>
|
91
113
|
```
|
92
114
|
|
93
|
-
|
115
|
+
---
|
116
|
+
|
117
|
+
#### runtime-level dependency/namespace registration
|
94
118
|
|
95
119
|
```ruby
|
96
120
|
container.namespace(:api) do
|
@@ -103,7 +127,9 @@ container['api.provider'] # => GoogleProvider
|
|
103
127
|
container['game_api'] # => 'overwatch'
|
104
128
|
```
|
105
129
|
|
106
|
-
|
130
|
+
---
|
131
|
+
|
132
|
+
#### container keys (dependency names):
|
107
133
|
|
108
134
|
```ruby
|
109
135
|
# get dependnecy keys (only dependencies)
|
@@ -132,12 +158,15 @@ container.keys(all_variants: true)
|
|
132
158
|
]
|
133
159
|
```
|
134
160
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
161
|
+
---
|
162
|
+
|
163
|
+
#### key predicates
|
164
|
+
|
165
|
+
- `key?(key)` - has dependency or namespace?
|
166
|
+
- `namespace?(path)` - has namespace?
|
167
|
+
- `dependency?(path)` - has dependency?
|
168
|
+
- `dependency?(path, memoized: true)` - has memoized dependency?
|
169
|
+
- `dependency?(path, memoized: false)` - has non-memoized dependency?
|
141
170
|
|
142
171
|
```ruby
|
143
172
|
container.key?('database') # => true
|
@@ -156,24 +185,40 @@ container.dependency?('random', memoized: true) # => false
|
|
156
185
|
container.dependency?('random', memoized: false) # => true
|
157
186
|
```
|
158
187
|
|
188
|
+
---
|
189
|
+
|
190
|
+
#### state freeze
|
191
|
+
|
159
192
|
- state freeze (`#freeze!`, `.#frozen?`):
|
160
193
|
|
161
194
|
```ruby
|
162
195
|
# documentation is coming;
|
163
196
|
```
|
164
197
|
|
165
|
-
|
198
|
+
---
|
199
|
+
|
200
|
+
#### reloading
|
201
|
+
|
202
|
+
- reloading (`#reload!`):
|
166
203
|
|
167
204
|
```ruby
|
168
205
|
# documentation is coming;
|
169
206
|
```
|
170
207
|
|
208
|
+
---
|
209
|
+
|
210
|
+
#### hash tree
|
211
|
+
|
171
212
|
- hash tree (`#hash_tree`, `#hash_tree(resolve_dependencies: true)`):
|
172
213
|
|
173
214
|
```ruby
|
174
|
-
# documentation is coming
|
215
|
+
# documentation is coming;
|
175
216
|
```
|
176
217
|
|
218
|
+
---
|
219
|
+
|
220
|
+
#### explicit class definition
|
221
|
+
|
177
222
|
- `SmartCore::Container.define` - avoid explicit class definition (allows to create container instance from an anonymous container class immidietly):
|
178
223
|
|
179
224
|
```ruby
|
@@ -212,8 +257,61 @@ AppContainer['db_driver'] # => Sequel (AppContainer dependency)
|
|
212
257
|
|
213
258
|
---
|
214
259
|
|
260
|
+
#### dependency changement observing
|
261
|
+
|
262
|
+
- features and limitations:
|
263
|
+
- you can subscribe only on container instances (on container instance changements);
|
264
|
+
- at this moment only the full entity path patterns are supported (pattern-based pathes are not supported yet);
|
265
|
+
- you can subscribe on namespace changements (when the full namespace is re-registered) and dependency changement (when some dependency has been changed);
|
266
|
+
- `#observe(path, &observer) => observer` - subscribe a custom block to dependency changement events (your proc will be invoked with `|path, container|` attributes);
|
267
|
+
- `#unobserve(observer)` - unsubscribe concrete observer from dependency observing (returns `true` (unsubscribed) or `false` (nothing to unsubscribe));
|
268
|
+
- `#clear_observers(entity_path = nil)` - unsubscribe all observers from concrete path or from all pathes (`nil` parameters);
|
269
|
+
- aliases:
|
270
|
+
- `#observe` => `#subscribe`;
|
271
|
+
- `#unobserve` => `#unsubscribe`;
|
272
|
+
- `#clear_observers` => `#clear_listeners`;
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
container = SmartCore::Container.define do
|
276
|
+
namespace(:database) do
|
277
|
+
register(:stats) { 'stat_db' }
|
278
|
+
end
|
279
|
+
end
|
280
|
+
```
|
281
|
+
|
282
|
+
```ruby
|
283
|
+
# observe entity change
|
284
|
+
entity_observer = container.observe('database.stats') do |dependency_path, container|
|
285
|
+
puts "changed => '#{container[dependency_path]}'"
|
286
|
+
end
|
287
|
+
|
288
|
+
# observe namespace change
|
289
|
+
namespace_observer = container.observe('database') do |namespace_path, container|
|
290
|
+
puts "changed => '#{namespace_path}'"
|
291
|
+
end
|
292
|
+
```
|
293
|
+
|
294
|
+
```ruby
|
295
|
+
container.register('database.stats') { 'kek' } # => invokes entity_observer and outputs "changed! => 'kek'"
|
296
|
+
container.namespace('database') {} # => invoks namespace_observer and outputs "changed => 'database'"
|
297
|
+
|
298
|
+
container.unobserve(observer) # unsubscribe entity_observer from dependency changement observing;
|
299
|
+
container.clear_observers # unsubscribe all observers
|
300
|
+
|
301
|
+
container.register('database.stats') { 'kek' } # no one to listen this changement... :)
|
302
|
+
container.namespace('database') {} # no one to listen this changement... :)
|
303
|
+
```
|
304
|
+
|
305
|
+
---
|
306
|
+
|
215
307
|
## Roadmap
|
216
308
|
|
309
|
+
- pattern-based pathes in dependency changement observing;
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
container.observe('path.*') { puts 'kek!' } # subscribe to all changements in `path` namespace;
|
313
|
+
```
|
314
|
+
|
217
315
|
- support for instant dependency registration:
|
218
316
|
|
219
317
|
```ruby
|
@@ -232,6 +330,8 @@ resolve('logger', :allocate) # Draft
|
|
232
330
|
|
233
331
|
- container composition;
|
234
332
|
|
333
|
+
- support for fallback block in `.resolve` operation (similar to `Hash#fetch` works);
|
334
|
+
|
235
335
|
---
|
236
336
|
|
237
337
|
## Contributing
|
data/lib/smart_core/container.rb
CHANGED
@@ -7,10 +7,10 @@ require 'smart_core'
|
|
7
7
|
module SmartCore
|
8
8
|
# @api public
|
9
9
|
# @since 0.1.0
|
10
|
-
class Container
|
10
|
+
class Container # rubocop:disable Metrics/ClassLength
|
11
11
|
require_relative 'container/version'
|
12
12
|
require_relative 'container/errors'
|
13
|
-
require_relative 'container/
|
13
|
+
require_relative 'container/arbitrary_lock'
|
14
14
|
require_relative 'container/key_guard'
|
15
15
|
require_relative 'container/entities'
|
16
16
|
require_relative 'container/definition_dsl'
|
@@ -18,6 +18,7 @@ module SmartCore
|
|
18
18
|
require_relative 'container/registry'
|
19
19
|
require_relative 'container/registry_builder'
|
20
20
|
require_relative 'container/dependency_resolver'
|
21
|
+
require_relative 'container/dependency_watcher'
|
21
22
|
require_relative 'container/mixin'
|
22
23
|
|
23
24
|
class << self
|
@@ -56,7 +57,7 @@ module SmartCore
|
|
56
57
|
# @since 0.1.0
|
57
58
|
def initialize
|
58
59
|
build_registry!
|
59
|
-
@access_lock =
|
60
|
+
@access_lock = ArbitraryLock.new
|
60
61
|
end
|
61
62
|
|
62
63
|
# @param dependency_name [String, Symbol]
|
@@ -65,6 +66,7 @@ module SmartCore
|
|
65
66
|
#
|
66
67
|
# @api public
|
67
68
|
# @sicne 0.1.0
|
69
|
+
# @version 0.8.0
|
68
70
|
def register(
|
69
71
|
dependency_name,
|
70
72
|
memoize: SmartCore::Container::Registry::DEFAULT_MEMOIZATION_BEHAVIOR,
|
@@ -72,6 +74,7 @@ module SmartCore
|
|
72
74
|
)
|
73
75
|
thread_safe do
|
74
76
|
registry.register_dependency(dependency_name, memoize: memoize, &dependency_definition)
|
77
|
+
watcher.notify(dependency_name)
|
75
78
|
end
|
76
79
|
end
|
77
80
|
|
@@ -81,8 +84,12 @@ module SmartCore
|
|
81
84
|
#
|
82
85
|
# @api public
|
83
86
|
# @since 0.1.0
|
87
|
+
# @version 0.8.0
|
84
88
|
def namespace(namespace_name, &dependencies_definition)
|
85
|
-
thread_safe
|
89
|
+
thread_safe do
|
90
|
+
registry.register_namespace(namespace_name, &dependencies_definition)
|
91
|
+
watcher.notify(namespace_name)
|
92
|
+
end
|
86
93
|
end
|
87
94
|
|
88
95
|
# @param dependency_path [String, Symbol]
|
@@ -195,14 +202,56 @@ module SmartCore
|
|
195
202
|
alias_method :to_h, :hash_tree
|
196
203
|
alias_method :to_hash, :hash_tree
|
197
204
|
|
205
|
+
# @param entity_path [String]
|
206
|
+
# @param observer [Block]
|
207
|
+
# @yield [entity_path, container]
|
208
|
+
# @yieldparam entity_path [String]
|
209
|
+
# @yieldparam container [SmartCore::Container]
|
210
|
+
# @return [SmartCore::Container::DependencyWatcher::Observer]
|
211
|
+
#
|
212
|
+
# @api public
|
213
|
+
# @since 0.8.0
|
214
|
+
def observe(entity_path, &observer) # TODO: support for pattern-based pathes
|
215
|
+
thread_safe { watcher.watch(entity_path, &observer) }
|
216
|
+
end
|
217
|
+
alias_method :subscribe, :observe
|
218
|
+
|
219
|
+
# @param observer [SmartCore::Container::DependencyWatcher::Observer]
|
220
|
+
# @return [Boolean]
|
221
|
+
#
|
222
|
+
# @api public
|
223
|
+
# @since 0.8.0
|
224
|
+
def unobserve(observer)
|
225
|
+
thread_safe { watcher.unwatch(observer) }
|
226
|
+
end
|
227
|
+
alias_method :unsubscribe, :unobserve
|
228
|
+
|
229
|
+
# @param entity_path [String, Symbol, NilClass]
|
230
|
+
# @return [void]
|
231
|
+
#
|
232
|
+
# @api public
|
233
|
+
# @since 0.8.0
|
234
|
+
def clear_observers(entity_path = nil) # TODO: support for pattern-based pathes
|
235
|
+
thread_safe { watcher.clear_listeners(entity_path) }
|
236
|
+
end
|
237
|
+
alias_method :clear_listeners, :clear_observers
|
238
|
+
|
198
239
|
private
|
199
240
|
|
241
|
+
# @return [SmartCore::Container::DependencyWatcher]
|
242
|
+
#
|
243
|
+
# @api private
|
244
|
+
# @since 0.8.0
|
245
|
+
attr_reader :watcher
|
246
|
+
|
200
247
|
# @return [void]
|
201
248
|
#
|
202
249
|
# @api private
|
203
250
|
# @since 0.1.0
|
251
|
+
# @version 0.8.0
|
204
252
|
def build_registry!
|
205
253
|
@registry = RegistryBuilder.build(self)
|
254
|
+
@watcher = SmartCore::Container::DependencyWatcher.new(self)
|
206
255
|
end
|
207
256
|
|
208
257
|
# @param block [Block]
|
@@ -17,7 +17,7 @@ class SmartCore::Container
|
|
17
17
|
def included(base_klass)
|
18
18
|
base_klass.instance_variable_set(:@__container_definition_commands__, CommandSet.new)
|
19
19
|
base_klass.instance_variable_set(:@__container_instantiation_commands__, CommandSet.new)
|
20
|
-
base_klass.instance_variable_set(:@__container_definition_lock__,
|
20
|
+
base_klass.instance_variable_set(:@__container_definition_lock__, ArbitraryLock.new)
|
21
21
|
base_klass.singleton_class.send(:attr_reader, :__container_definition_commands__)
|
22
22
|
base_klass.singleton_class.send(:attr_reader, :__container_instantiation_commands__)
|
23
23
|
base_klass.extend(ClassMethods)
|
@@ -36,7 +36,7 @@ class SmartCore::Container
|
|
36
36
|
def inherited(child_klass)
|
37
37
|
child_klass.instance_variable_set(:@__container_definition_commands__, CommandSet.new)
|
38
38
|
child_klass.instance_variable_set(:@__container_instantiation_commands__, CommandSet.new)
|
39
|
-
child_klass.instance_variable_set(:@__container_definition_lock__,
|
39
|
+
child_klass.instance_variable_set(:@__container_definition_lock__, ArbitraryLock.new)
|
40
40
|
SmartCore::Container::DefinitionDSL::Inheritance.inherit(base: self, child: child_klass)
|
41
41
|
child_klass.singleton_class.prepend(ClassInheritance)
|
42
42
|
super
|
@@ -18,7 +18,7 @@ class SmartCore::Container::DefinitionDSL::CommandSet
|
|
18
18
|
# @since 0.1.0
|
19
19
|
def initialize
|
20
20
|
@commands = []
|
21
|
-
@access_lock = SmartCore::Container::
|
21
|
+
@access_lock = SmartCore::Container::ArbitraryLock.new
|
22
22
|
end
|
23
23
|
|
24
24
|
# @param [SmartCore::Container::DefinitionDSL::Commands::Base]
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.8.0
|
5
|
+
class SmartCore::Container::DependencyWatcher
|
6
|
+
require_relative 'dependency_watcher/observer'
|
7
|
+
|
8
|
+
# @param container [SmartCore::Container]
|
9
|
+
# @return [void]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.8.0
|
13
|
+
def initialize(container)
|
14
|
+
@container = container
|
15
|
+
@observers = Hash.new { |k, v| k[v] = [] }
|
16
|
+
@access_lock = SmartCore::Container::ArbitraryLock.new
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param entity_path [String, Symbol]
|
20
|
+
# @return [void]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
# @since 0.8.0
|
24
|
+
def notify(entity_path)
|
25
|
+
thread_safe { notify_listeners(entity_path) }
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param entity_path [String, Symbol]
|
29
|
+
# @param observer [Block]
|
30
|
+
# @return [SmartCore::Container::DependencyWatcher::Observer]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
# @since 0.8.0
|
34
|
+
def watch(entity_path, &observer) # TODO: support for pattern-based pathes
|
35
|
+
thread_safe { listen(entity_path, observer) }
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param observer [SmartCore::Container::DependencyWatcher::Observer]
|
39
|
+
# @return [Boolean]
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
# @since 0.8.0
|
43
|
+
def unwatch(observer)
|
44
|
+
thread_safe { remove_listener(observer) }
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param entity_path [String, Symbol, NilClass]
|
48
|
+
# @return [void]
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
# @since 0.8.0
|
52
|
+
def clear_listeners(entity_path = nil) # TODO: support for pattern-based pathes
|
53
|
+
thread_safe { remove_listeners(entity_path) }
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# @return [SmartCore::Container]
|
59
|
+
#
|
60
|
+
# @api private
|
61
|
+
# @since 0.8.0
|
62
|
+
attr_reader :container
|
63
|
+
|
64
|
+
# @return [Hash<String,SmartCore::Container::DependencyWatcher::Observer>]
|
65
|
+
#
|
66
|
+
# @api private
|
67
|
+
# @since 0.8.0
|
68
|
+
attr_reader :observers
|
69
|
+
|
70
|
+
# @param entity_path [String, Symbol]
|
71
|
+
# @return [void]
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
# @since 0.8.0
|
75
|
+
def notify_listeners(entity_path)
|
76
|
+
entity_path = indifferently_accessable_path(entity_path)
|
77
|
+
observers.fetch(entity_path).each(&:notify!) if observers.key?(entity_path)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @param entity_path [String, Symbol]
|
81
|
+
# @param observer [Proc]
|
82
|
+
# @return [SmartCore::Container::DependencyWatcher::Observer]
|
83
|
+
#
|
84
|
+
# @api private
|
85
|
+
# @since 0.8.0
|
86
|
+
def listen(entity_path, observer) # TODO: support for pattern-based pathes
|
87
|
+
raise(SmartCore::Container::ArgumentError, <<~ERROR_MESSAGE) unless observer.is_a?(Proc)
|
88
|
+
Observer is missing: you should provide an observer proc object (block).
|
89
|
+
ERROR_MESSAGE
|
90
|
+
|
91
|
+
entity_path = indifferently_accessable_path(entity_path)
|
92
|
+
Observer.new(container, entity_path, observer).tap { |obs| observers[entity_path] << obs }
|
93
|
+
end
|
94
|
+
|
95
|
+
# @param observer [SmartCore::Container::DependencyWatcher::Observer]
|
96
|
+
# @return [Boolean]
|
97
|
+
#
|
98
|
+
# @api private
|
99
|
+
# @since 0.8.0
|
100
|
+
def remove_listener(observer)
|
101
|
+
unless observer.is_a?(SmartCore::Container::DependencyWatcher::Observer)
|
102
|
+
raise(SmartCore::Container::ArgumentError, <<~ERROR_MESSAGE)
|
103
|
+
You should provide an observer object for unsubscribion
|
104
|
+
(an instance of SmartCore::Container::DependencyWatcher::Observer).
|
105
|
+
ERROR_MESSAGE
|
106
|
+
end
|
107
|
+
|
108
|
+
unsubscribed = false
|
109
|
+
observers.each_value do |observer_list|
|
110
|
+
if observer_list.delete(observer)
|
111
|
+
unsubscribed = true
|
112
|
+
break
|
113
|
+
end
|
114
|
+
end
|
115
|
+
unsubscribed
|
116
|
+
end
|
117
|
+
|
118
|
+
# @param entity_path [String, Symbol]
|
119
|
+
# @return [void]
|
120
|
+
#
|
121
|
+
# @api private
|
122
|
+
# @since 0.8.0
|
123
|
+
def remove_listeners(entity_path) # TODO: support for pattern-based pathes
|
124
|
+
if entity_path.nil?
|
125
|
+
observers.each_value(&:clear)
|
126
|
+
else
|
127
|
+
entity_path = indifferently_accessable_path(entity_path)
|
128
|
+
observers[entity_path].clear if observers.key?(entity_path)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# @param entity_path [String, Symbol]
|
133
|
+
# @return [String]
|
134
|
+
#
|
135
|
+
# @api private
|
136
|
+
# @since 0.8.0
|
137
|
+
def indifferently_accessable_path(entity_path)
|
138
|
+
SmartCore::Container::KeyGuard.indifferently_accessable_key(entity_path)
|
139
|
+
end
|
140
|
+
|
141
|
+
# @param block [Block]
|
142
|
+
# @return [Any]
|
143
|
+
#
|
144
|
+
# @api private
|
145
|
+
# @since 0.8.0
|
146
|
+
def thread_safe(&block)
|
147
|
+
@access_lock.thread_safe(&block)
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.8.0
|
5
|
+
class SmartCore::Container::DependencyWatcher::Observer
|
6
|
+
# @param container [SmartCore::Container]
|
7
|
+
# @param dependency_path [String]
|
8
|
+
# @param callback [Proc]
|
9
|
+
# @return [void]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.8.0
|
13
|
+
def initialize(container, dependency_path, callback)
|
14
|
+
@container = container
|
15
|
+
@dependency_path = dependency_path
|
16
|
+
@callback = callback
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [void]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
# @since 0.8.0
|
23
|
+
def notify!
|
24
|
+
callback.call(dependency_path, container)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# @return [SmartCore::Container]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.8.0
|
33
|
+
attr_reader :container
|
34
|
+
|
35
|
+
# @return [String]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
# @since 0.8.0
|
39
|
+
attr_reader :dependency_path
|
40
|
+
|
41
|
+
# @return [Proc]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
# @since 0.8.0
|
45
|
+
attr_reader :callback
|
46
|
+
end
|
@@ -12,7 +12,7 @@ module SmartCore::Container::Entities
|
|
12
12
|
# @since 0.2.0
|
13
13
|
def initialize(dependency_name, dependency_definition)
|
14
14
|
super(dependency_name, dependency_definition)
|
15
|
-
@lock = SmartCore::Container::
|
15
|
+
@lock = SmartCore::Container::ArbitraryLock.new
|
16
16
|
end
|
17
17
|
|
18
18
|
# @return [Any]
|
@@ -18,7 +18,7 @@ class SmartCore::Container::Entities::Namespace < SmartCore::Container::Entities
|
|
18
18
|
super(namespace_name)
|
19
19
|
@container_klass = Class.new(SmartCore::Container)
|
20
20
|
@container_instance = nil
|
21
|
-
@lock = SmartCore::Container::
|
21
|
+
@lock = SmartCore::Container::ArbitraryLock.new
|
22
22
|
end
|
23
23
|
|
24
24
|
# @return [SmartCore::Container]
|
@@ -11,7 +11,7 @@ module SmartCore::Container::Mixin
|
|
11
11
|
# @since 0.1.0
|
12
12
|
def included(base_klass)
|
13
13
|
# rubocop:disable Layout/LineLength
|
14
|
-
base_klass.instance_variable_set(:@__smart_core_container_access_lock__, SmartCore::Container::
|
14
|
+
base_klass.instance_variable_set(:@__smart_core_container_access_lock__, SmartCore::Container::ArbitraryLock.new)
|
15
15
|
base_klass.instance_variable_set(:@__smart_core_container_klass__, Class.new(SmartCore::Container))
|
16
16
|
base_klass.instance_variable_set(:@__smart_core_container__, nil)
|
17
17
|
# rubocop:enable Layout/LineLength
|
@@ -34,7 +34,7 @@ module SmartCore::Container::Mixin
|
|
34
34
|
inherited_container_klass = Class.new(@__smart_core_container_klass__)
|
35
35
|
|
36
36
|
# rubocop:disable Layout/LineLength
|
37
|
-
child_klass.instance_variable_set(:@__smart_core_container_access_lock__, SmartCore::Container::
|
37
|
+
child_klass.instance_variable_set(:@__smart_core_container_access_lock__, SmartCore::Container::ArbitraryLock.new)
|
38
38
|
child_klass.instance_variable_set(:@__smart_core_container_klass__, inherited_container_klass)
|
39
39
|
child_klass.instance_variable_set(:@__smart_core_container__, nil)
|
40
40
|
# rubocop:enable Layout/LineLength
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_container
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rustam Ibragimov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: smart_engine
|
@@ -129,7 +129,7 @@ files:
|
|
129
129
|
- bin/console
|
130
130
|
- bin/setup
|
131
131
|
- lib/smart_core/container.rb
|
132
|
-
- lib/smart_core/container/
|
132
|
+
- lib/smart_core/container/arbitrary_lock.rb
|
133
133
|
- lib/smart_core/container/definition_dsl.rb
|
134
134
|
- lib/smart_core/container/definition_dsl/command_set.rb
|
135
135
|
- lib/smart_core/container/definition_dsl/commands.rb
|
@@ -149,6 +149,8 @@ files:
|
|
149
149
|
- lib/smart_core/container/dependency_resolver.rb
|
150
150
|
- lib/smart_core/container/dependency_resolver/route.rb
|
151
151
|
- lib/smart_core/container/dependency_resolver/route/cursor.rb
|
152
|
+
- lib/smart_core/container/dependency_watcher.rb
|
153
|
+
- lib/smart_core/container/dependency_watcher/observer.rb
|
152
154
|
- lib/smart_core/container/entities.rb
|
153
155
|
- lib/smart_core/container/entities/base.rb
|
154
156
|
- lib/smart_core/container/entities/dependency.rb
|