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