smart_container 0.4.0 → 0.8.1

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
2
  SHA256:
3
- metadata.gz: bb1bc1e5f80263730638b0b0387105364777f87e957b5f673c27c219f206273d
4
- data.tar.gz: 0d1a505edb3b4456ab44ecfe52071b1cb5555f51680d3a48de68fb12bd11dcad
3
+ metadata.gz: fbae5c2d40dc40e3114d685c1f13d6cbfb7003a1c8fda862ef5dbcfa432cf5cd
4
+ data.tar.gz: dd288fa47167c0da4e2aae656478170d0dd78b142eef52a351c461ddbc92bf29
5
5
  SHA512:
6
- metadata.gz: 3959674748c1dcc2564bd6edc9ee0acdc3770b0bd260d50c7a1bba5906fee6725ff577e90a2b36b0a81910c423020431810b2a052f42c65826bfc8dcabe7dc22
7
- data.tar.gz: f01f97eda299d91b22f730de1eba90e546f9f4de0362218bc0b8f86d8800acd6abf3d2214e223c0246f5c1d4b4742b71c7223ada409a3665765c088c88ab207e
6
+ metadata.gz: 27129a91c84f8aad432c5462c2d3a921284b2b8e3b1fb4b0a215295f6f88d94063946cc24f2d065f6da9ba6e64baf421f2a192b68fa63ebda879a81715e2c88f
7
+ data.tar.gz: 5e6839adcfe1e3c31513b622fc3e46aab37ab3ec35a992c8a3b9c7ff029c976dbf331619d3df20da7ffe3d712a8839f04ac83f3055f9e2426869e9b9ecf556f6
@@ -5,11 +5,11 @@ inherit_gem:
5
5
  - lib/rubocop.rspec.yml
6
6
 
7
7
  AllCops:
8
- TargetRubyVersion: 2.4.9
8
+ TargetRubyVersion: 2.7.1
9
9
  Include:
10
10
  - lib/**/*.rb
11
11
  - spec/**/*.rb
12
12
  - Gemfile
13
13
  - Rakefile
14
- - siege.gemspec
14
+ - smart_container.gemspec
15
15
  - bin/console
@@ -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 -v 2.1.2
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.9
14
- - rvm: 2.5.7
15
- - rvm: 2.6.5
16
- - rvm: 2.7.0
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:
@@ -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
@@ -1,83 +1,98 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_container (0.4.0)
5
- smart_engine (~> 0.2)
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
- armitage-rubocop (0.78.0)
11
- rubocop (= 0.78.0)
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.4.1)
14
- rubocop-rake (= 0.5.0)
15
- rubocop-rspec (= 1.37.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
- json (2.3.0)
22
- method_source (0.9.2)
30
+ method_source (1.0.0)
31
+ minitest (5.14.0)
23
32
  parallel (1.19.1)
24
- parser (2.7.0.1)
33
+ parser (2.7.1.0)
25
34
  ast (~> 2.4.0)
26
- pry (0.12.2)
27
- coderay (~> 1.1.0)
28
- method_source (~> 0.9.0)
29
- rack (2.0.8)
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.0)
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.78.0)
55
+ rubocop (0.81.0)
46
56
  jaro_winkler (~> 1.5.1)
47
57
  parallel (~> 1.10)
48
- parser (>= 2.6)
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, < 1.7)
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.4.1)
65
+ rubocop-rails (2.5.2)
66
+ activesupport
55
67
  rack (>= 1.1)
56
68
  rubocop (>= 0.72.0)
57
- rubocop-rake (0.5.0)
69
+ rubocop-rake (0.5.1)
58
70
  rubocop
59
- rubocop-rspec (1.37.1)
71
+ rubocop-rspec (1.38.1)
60
72
  rubocop (>= 0.68.1)
61
73
  ruby-progressbar (1.10.1)
62
- simplecov (0.17.1)
74
+ simplecov (0.18.5)
63
75
  docile (~> 1.1)
64
- json (>= 1.8, < 3)
65
- simplecov-html (~> 0.10.0)
66
- simplecov-html (0.10.2)
67
- smart_engine (0.2.0)
68
- unicode-display_width (1.6.0)
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.78)
89
+ armitage-rubocop (~> 0.81)
75
90
  bundler (~> 2.1)
76
- pry (~> 0.12)
91
+ pry (~> 0.13)
77
92
  rake (~> 13.0)
78
93
  rspec (~> 3.9)
79
- simplecov (~> 0.17)
94
+ simplecov (~> 0.18)
80
95
  smart_container!
81
96
 
82
97
  BUNDLED WITH
83
- 2.1.2
98
+ 2.1.4
data/README.md CHANGED
@@ -22,9 +22,27 @@ require 'smart_core/container'
22
22
 
23
23
  ---
24
24
 
25
- ## Synopsis (demo)
25
+ ## Table of cotnents
26
26
 
27
- - container class creation:
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
- - container instantiation and dependency resolving:
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
- - container keys (dependency names):
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 )