smart_container 0.4.0 → 0.8.1
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/.rubocop.yml +2 -2
- data/.travis.yml +6 -5
- data/CHANGELOG.md +32 -0
- data/Gemfile.lock +46 -31
- data/README.md +248 -4
- data/Rakefile +2 -1
- data/lib/smart_core/container.rb +132 -7
- 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/definition_dsl/commands/definition/register.rb +1 -1
- data/lib/smart_core/container/dependency_resolver.rb +80 -6
- data/lib/smart_core/container/dependency_watcher.rb +151 -0
- data/lib/smart_core/container/dependency_watcher/observer.rb +46 -0
- data/lib/smart_core/container/entities/dependency.rb +3 -1
- data/lib/smart_core/container/entities/dependency_builder.rb +27 -59
- data/lib/smart_core/container/entities/memoized_dependency.rb +4 -2
- data/lib/smart_core/container/entities/namespace.rb +23 -6
- data/lib/smart_core/container/entities/namespace_builder.rb +14 -34
- data/lib/smart_core/container/host.rb +77 -0
- data/lib/smart_core/container/mixin.rb +2 -2
- data/lib/smart_core/container/registry.rb +15 -6
- data/lib/smart_core/container/version.rb +2 -2
- data/smart_container.gemspec +5 -5
- metadata +15 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbae5c2d40dc40e3114d685c1f13d6cbfb7003a1c8fda862ef5dbcfa432cf5cd
|
4
|
+
data.tar.gz: dd288fa47167c0da4e2aae656478170d0dd78b142eef52a351c461ddbc92bf29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27129a91c84f8aad432c5462c2d3a921284b2b8e3b1fb4b0a215295f6f88d94063946cc24f2d065f6da9ba6e64baf421f2a192b68fa63ebda879a81715e2c88f
|
7
|
+
data.tar.gz: 5e6839adcfe1e3c31513b622fc3e46aab37ab3ec35a992c8a3b9c7ff029c976dbf331619d3df20da7ffe3d712a8839f04ac83f3055f9e2426869e9b9ecf556f6
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -2,18 +2,19 @@
|
|
2
2
|
language: ruby
|
3
3
|
cache: bundler
|
4
4
|
os: linux
|
5
|
+
dist: xenial
|
5
6
|
before_install:
|
6
|
-
- gem install bundler
|
7
|
+
- gem install bundler
|
7
8
|
script:
|
8
9
|
- bundle exec rake rubocop
|
9
10
|
- bundle exec rake rspec
|
10
11
|
jobs:
|
11
12
|
fast_finish: true
|
12
13
|
include:
|
13
|
-
- rvm: 2.4.
|
14
|
-
- rvm: 2.5.
|
15
|
-
- rvm: 2.6.
|
16
|
-
- rvm: 2.7.
|
14
|
+
- rvm: 2.4.10
|
15
|
+
- rvm: 2.5.8
|
16
|
+
- rvm: 2.6.6
|
17
|
+
- rvm: 2.7.1
|
17
18
|
- rvm: ruby-head
|
18
19
|
- rvm: jruby-head
|
19
20
|
allow_failures:
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,38 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [0.8.1] - 2020-07-09
|
5
|
+
### Changed
|
6
|
+
- *Core*
|
7
|
+
- refactored `SmartCore::Container::Entities::NamespaceBuilder` and `SmartCore::Container::Entities::DependencyBuilder`
|
8
|
+
(from stateful-based logic on instances to stateless-based logic on modules);
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
- Subscription to the nested dependency changement doesn't work
|
12
|
+
(incomplete nested dependency path in watcher notification);
|
13
|
+
|
14
|
+
## [0.8.0] - 2020-07-08
|
15
|
+
### Added
|
16
|
+
- An ability to observe dependency re-registrations:
|
17
|
+
- `#observe(path, &observer) # => observer object` - listen specific dependency path;
|
18
|
+
- `#unobserve(observer)` - unsubscribe concrete observer object;
|
19
|
+
- `#clear_observers(path = nil)` - unsubscribe specific listenr or all listeners (`nil` parameter);
|
20
|
+
|
21
|
+
## [0.7.0] - 2020-06-20
|
22
|
+
### Added
|
23
|
+
- `SmartCore::Container.define {}` - an ability to avoid explicit class definition that allows
|
24
|
+
to create container instances from an anonymous container class imidietly
|
25
|
+
|
26
|
+
## [0.6.0] - 2020-01-12
|
27
|
+
### Added
|
28
|
+
- Missing memoization flag `:memoize` for runtime-based dependency registration:
|
29
|
+
- `memoize: false` by default;
|
30
|
+
- signature: `SmartCore::Container#register(dependency_name, memoize: false, &dependency)`
|
31
|
+
|
32
|
+
## [0.5.0] - 2020-01-07
|
33
|
+
### Added
|
34
|
+
- Key predicates (`#key?(key)`, `#dependency?(path, memoized: nil/true/false)`, `#namespace?(path)`);
|
35
|
+
|
4
36
|
## [0.4.0] - 2020-01-06
|
5
37
|
### Added
|
6
38
|
- `#keys(all_variants: false)` - return a list of dependency keys
|
data/Gemfile.lock
CHANGED
@@ -1,83 +1,98 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
smart_container (0.
|
5
|
-
smart_engine (~> 0.
|
4
|
+
smart_container (0.8.1)
|
5
|
+
smart_engine (~> 0.5)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
11
|
-
|
10
|
+
activesupport (6.0.2.2)
|
11
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
|
+
i18n (>= 0.7, < 2)
|
13
|
+
minitest (~> 5.1)
|
14
|
+
tzinfo (~> 1.1)
|
15
|
+
zeitwerk (~> 2.2)
|
16
|
+
armitage-rubocop (0.81.0)
|
17
|
+
rubocop (= 0.81.0)
|
12
18
|
rubocop-performance (= 1.5.2)
|
13
|
-
rubocop-rails (= 2.
|
14
|
-
rubocop-rake (= 0.5.
|
15
|
-
rubocop-rspec (= 1.
|
19
|
+
rubocop-rails (= 2.5.2)
|
20
|
+
rubocop-rake (= 0.5.1)
|
21
|
+
rubocop-rspec (= 1.38.1)
|
16
22
|
ast (2.4.0)
|
17
23
|
coderay (1.1.2)
|
24
|
+
concurrent-ruby (1.1.6)
|
18
25
|
diff-lcs (1.3)
|
19
26
|
docile (1.3.2)
|
27
|
+
i18n (1.8.2)
|
28
|
+
concurrent-ruby (~> 1.0)
|
20
29
|
jaro_winkler (1.5.4)
|
21
|
-
|
22
|
-
|
30
|
+
method_source (1.0.0)
|
31
|
+
minitest (5.14.0)
|
23
32
|
parallel (1.19.1)
|
24
|
-
parser (2.7.0
|
33
|
+
parser (2.7.1.0)
|
25
34
|
ast (~> 2.4.0)
|
26
|
-
pry (0.
|
27
|
-
coderay (~> 1.1
|
28
|
-
method_source (~>
|
29
|
-
rack (2.
|
35
|
+
pry (0.13.1)
|
36
|
+
coderay (~> 1.1)
|
37
|
+
method_source (~> 1.0)
|
38
|
+
rack (2.2.2)
|
30
39
|
rainbow (3.0.0)
|
31
40
|
rake (13.0.1)
|
41
|
+
rexml (3.2.4)
|
32
42
|
rspec (3.9.0)
|
33
43
|
rspec-core (~> 3.9.0)
|
34
44
|
rspec-expectations (~> 3.9.0)
|
35
45
|
rspec-mocks (~> 3.9.0)
|
36
46
|
rspec-core (3.9.1)
|
37
47
|
rspec-support (~> 3.9.1)
|
38
|
-
rspec-expectations (3.9.
|
48
|
+
rspec-expectations (3.9.1)
|
39
49
|
diff-lcs (>= 1.2.0, < 2.0)
|
40
50
|
rspec-support (~> 3.9.0)
|
41
51
|
rspec-mocks (3.9.1)
|
42
52
|
diff-lcs (>= 1.2.0, < 2.0)
|
43
53
|
rspec-support (~> 3.9.0)
|
44
54
|
rspec-support (3.9.2)
|
45
|
-
rubocop (0.
|
55
|
+
rubocop (0.81.0)
|
46
56
|
jaro_winkler (~> 1.5.1)
|
47
57
|
parallel (~> 1.10)
|
48
|
-
parser (>= 2.
|
58
|
+
parser (>= 2.7.0.1)
|
49
59
|
rainbow (>= 2.2.2, < 4.0)
|
60
|
+
rexml
|
50
61
|
ruby-progressbar (~> 1.7)
|
51
|
-
unicode-display_width (>= 1.4.0, <
|
62
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
52
63
|
rubocop-performance (1.5.2)
|
53
64
|
rubocop (>= 0.71.0)
|
54
|
-
rubocop-rails (2.
|
65
|
+
rubocop-rails (2.5.2)
|
66
|
+
activesupport
|
55
67
|
rack (>= 1.1)
|
56
68
|
rubocop (>= 0.72.0)
|
57
|
-
rubocop-rake (0.5.
|
69
|
+
rubocop-rake (0.5.1)
|
58
70
|
rubocop
|
59
|
-
rubocop-rspec (1.
|
71
|
+
rubocop-rspec (1.38.1)
|
60
72
|
rubocop (>= 0.68.1)
|
61
73
|
ruby-progressbar (1.10.1)
|
62
|
-
simplecov (0.
|
74
|
+
simplecov (0.18.5)
|
63
75
|
docile (~> 1.1)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
76
|
+
simplecov-html (~> 0.11)
|
77
|
+
simplecov-html (0.12.2)
|
78
|
+
smart_engine (0.7.0)
|
79
|
+
thread_safe (0.3.6)
|
80
|
+
tzinfo (1.2.7)
|
81
|
+
thread_safe (~> 0.1)
|
82
|
+
unicode-display_width (1.7.0)
|
83
|
+
zeitwerk (2.3.0)
|
69
84
|
|
70
85
|
PLATFORMS
|
71
86
|
ruby
|
72
87
|
|
73
88
|
DEPENDENCIES
|
74
|
-
armitage-rubocop (~> 0.
|
89
|
+
armitage-rubocop (~> 0.81)
|
75
90
|
bundler (~> 2.1)
|
76
|
-
pry (~> 0.
|
91
|
+
pry (~> 0.13)
|
77
92
|
rake (~> 13.0)
|
78
93
|
rspec (~> 3.9)
|
79
|
-
simplecov (~> 0.
|
94
|
+
simplecov (~> 0.18)
|
80
95
|
smart_container!
|
81
96
|
|
82
97
|
BUNDLED WITH
|
83
|
-
2.1.
|
98
|
+
2.1.4
|
data/README.md
CHANGED
@@ -22,9 +22,27 @@ require 'smart_core/container'
|
|
22
22
|
|
23
23
|
---
|
24
24
|
|
25
|
-
##
|
25
|
+
## Table of cotnents
|
26
26
|
|
27
|
-
-
|
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
|
+
- [subscribe to dependency changements](#subscribe-to-dependency-changements)
|
39
|
+
- [Roadmap](#roadmap)
|
40
|
+
|
41
|
+
---
|
42
|
+
|
43
|
+
## Functionality
|
44
|
+
|
45
|
+
#### container class creation
|
28
46
|
|
29
47
|
```ruby
|
30
48
|
class Container < SmartCore::Container
|
@@ -45,7 +63,31 @@ class Container < SmartCore::Container
|
|
45
63
|
end
|
46
64
|
```
|
47
65
|
|
48
|
-
|
66
|
+
---
|
67
|
+
|
68
|
+
#### mixin
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
# full documentaiton is coming;
|
72
|
+
|
73
|
+
class Application
|
74
|
+
include SmartCore::Container::Mixin
|
75
|
+
|
76
|
+
dependencies do
|
77
|
+
namespace(:database) do
|
78
|
+
register(:cache) { MemcachedClient.new }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# access:
|
84
|
+
Application.container
|
85
|
+
Application.new.container # NOTE: the same instance as Application.container
|
86
|
+
```
|
87
|
+
|
88
|
+
---
|
89
|
+
|
90
|
+
#### container instantiation and dependency resolving
|
49
91
|
|
50
92
|
```ruby
|
51
93
|
container = Container.new # create container instance
|
@@ -70,7 +112,24 @@ container.fetch('database') # => SmartCore::Container (nested container)
|
|
70
112
|
container.fetch('database.resolver') # => #<SomeDatabaseResolver:0x00007f0f0f1d6332>
|
71
113
|
```
|
72
114
|
|
73
|
-
|
115
|
+
---
|
116
|
+
|
117
|
+
#### runtime-level dependency/namespace registration
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
container.namespace(:api) do
|
121
|
+
register(:provider) { GoogleProvider } # without memoization
|
122
|
+
end
|
123
|
+
|
124
|
+
container.register('game_api', memoize: true) { 'overwatch' } # with memoization
|
125
|
+
|
126
|
+
container['api.provider'] # => GoogleProvider
|
127
|
+
container['game_api'] # => 'overwatch'
|
128
|
+
```
|
129
|
+
|
130
|
+
---
|
131
|
+
|
132
|
+
#### container keys (dependency names):
|
74
133
|
|
75
134
|
```ruby
|
76
135
|
# get dependnecy keys (only dependencies)
|
@@ -101,6 +160,191 @@ container.keys(all_variants: true)
|
|
101
160
|
|
102
161
|
---
|
103
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?
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
container.key?('database') # => true
|
173
|
+
container.key?('database.cache.memcached') # => true
|
174
|
+
|
175
|
+
container.dependency?('database') # => false
|
176
|
+
container.dependency?('database.resolver') # => true
|
177
|
+
|
178
|
+
container.namespace?('database') # => true
|
179
|
+
container.namespace?('database.resolver') # => false
|
180
|
+
|
181
|
+
container.dependency?('database.resolver', memoized: true) # => true
|
182
|
+
container.dependency?('database.resolver', memoized: false) # => false
|
183
|
+
|
184
|
+
container.dependency?('random', memoized: true) # => false
|
185
|
+
container.dependency?('random', memoized: false) # => true
|
186
|
+
```
|
187
|
+
|
188
|
+
---
|
189
|
+
|
190
|
+
#### state freeze
|
191
|
+
|
192
|
+
- state freeze (`#freeze!`, `.#frozen?`):
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
# documentation is coming;
|
196
|
+
```
|
197
|
+
|
198
|
+
---
|
199
|
+
|
200
|
+
#### reloading
|
201
|
+
|
202
|
+
- reloading (`#reload!`):
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
# documentation is coming;
|
206
|
+
```
|
207
|
+
|
208
|
+
---
|
209
|
+
|
210
|
+
#### hash tree
|
211
|
+
|
212
|
+
- hash tree (`#hash_tree`, `#hash_tree(resolve_dependencies: true)`):
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
# documentation is coming;
|
216
|
+
```
|
217
|
+
|
218
|
+
---
|
219
|
+
|
220
|
+
#### explicit class definition
|
221
|
+
|
222
|
+
- `SmartCore::Container.define` - avoid explicit class definition (allows to create container instance from an anonymous container class immidietly):
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
# - create from empty container class -
|
226
|
+
|
227
|
+
AppContainer = SmartCore::Container.define do
|
228
|
+
namespace :database do
|
229
|
+
register(:logger) { Logger.new }
|
230
|
+
end
|
231
|
+
end # => an instance of Class<SmartCore::Container>
|
232
|
+
|
233
|
+
AppContainer.resolve('database.logger') # => #<Logger:0x00007f5f0f2f0158>
|
234
|
+
AppContainer['database.logger'] # => #<Logger:0x00007f5f0f2f0158>
|
235
|
+
```
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
# - create from another container class with a custom sub-definitions -
|
239
|
+
|
240
|
+
class BasicContainer < SmartCore::Container
|
241
|
+
namespace(:api) do
|
242
|
+
register(:client) { Kickbox.new }
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
AppContainer = BasicContainer.define do
|
247
|
+
register(:db_driver) { Sequel }
|
248
|
+
end
|
249
|
+
# --- or ---
|
250
|
+
AppContainer = SmartCore::Container.define(BasicContainer) do
|
251
|
+
register(:db_driver) { Sequel }
|
252
|
+
end
|
253
|
+
|
254
|
+
AppContainer['api.client'] # => #<Kickbox:0x00007f5f0f2f0158> (BasicContainer dependency)
|
255
|
+
AppContainer['db_driver'] # => Sequel (AppContainer dependency)
|
256
|
+
```
|
257
|
+
|
258
|
+
---
|
259
|
+
|
260
|
+
#### subscribe to dependency changements
|
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.fetch('database').register('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.fetch('database').register('stats') = 'pek' # no one to listen this changement... :)
|
302
|
+
container.namespace('database') {} # no one to listen this changement... :)
|
303
|
+
```
|
304
|
+
|
305
|
+
---
|
306
|
+
|
307
|
+
## Roadmap
|
308
|
+
|
309
|
+
- convinient way to rebind registered dependnecies:
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
# PoC
|
313
|
+
|
314
|
+
container['dependency.path'] = 'pek' # simplest instant dependency registration without memoization
|
315
|
+
# --- or/and ---
|
316
|
+
container.rebind('dependency.path', memoize: true/false) { 'pek' } # bind with dynamic dependency registration
|
317
|
+
container.rebind('dependency.path', memoize: true/false, 'pek') # bind with instant dependency registration
|
318
|
+
```
|
319
|
+
|
320
|
+
- pattern-based pathes in dependency changement observing;
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
container.observe('path.*') { puts 'kek!' } # subscribe to all changements in `path` namespace;
|
324
|
+
```
|
325
|
+
|
326
|
+
- support for instant dependency registration:
|
327
|
+
|
328
|
+
```ruby
|
329
|
+
# common (dynamic) way:
|
330
|
+
register('dependency_name') { dependency_value }
|
331
|
+
|
332
|
+
# instant way:
|
333
|
+
register('dependency_name', dependency_value)
|
334
|
+
```
|
335
|
+
|
336
|
+
- support for memoization ignorance during dependency resolving:
|
337
|
+
|
338
|
+
```ruby
|
339
|
+
resolve('logger', :allocate) # Draft
|
340
|
+
```
|
341
|
+
|
342
|
+
- container composition;
|
343
|
+
|
344
|
+
- support for fallback block in `.resolve` operation (similar to `Hash#fetch` works);
|
345
|
+
|
346
|
+
---
|
347
|
+
|
104
348
|
## Contributing
|
105
349
|
|
106
350
|
- Fork it ( https://github.com/smart-rb/smart_container/fork )
|