smart_container 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 919cbfa847aa6931a64cf70c07269a0883ac0b5f47e9b84243854b0ea626f49e
4
- data.tar.gz: b9fcfbf5060a973bf1aa8e81d8a78cbdabf243e585dea583e64904e698c094dc
3
+ metadata.gz: 6670714cdeb503df6debb42135ee26283aef48a012fcf2469487668390a675f3
4
+ data.tar.gz: ba0ad291f05bdebb5d5af7fc46554c30c0748753243e04ac6277abf74886acb6
5
5
  SHA512:
6
- metadata.gz: 282c7f32da7c8029518b72f94b1047ed71046db44b0e18c9eef2557158bbf3ad97bb5ed658af9a836105964175fa2fd5a5b6ddb0568700b39ed471e7b6ec4c28
7
- data.tar.gz: bfabb455faa37954f0700d2f910e6de93ed4194bb9bb63d45918af7e81de92a5f07f3edf503c922a363d682d6a227cad64a5e5f4c53b355db0b8018757397bb4
6
+ metadata.gz: 29b1566aaff6a6227ed13a03a0b65110ce319c4b08bccc50b8c346793cb258174ee611fa19e3950e339049ab50b5819fc31ae6164b2e6d715c8a51d72a29a44f
7
+ data.tar.gz: cd38836e86ef48c860e58e55af5a30b8f3babdb7724658f96dee7a42ee953a122667688b29bdbb50aeccb94fc4026c1dc17d922524f21a32b20ab67ad7f3ca58
@@ -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
@@ -1,28 +1,22 @@
1
1
  ---
2
2
  language: ruby
3
3
  cache: bundler
4
+ os: linux
5
+ dist: xenial
4
6
  before_install:
5
- - gem install bundler -v 2.1.2
7
+ - gem install bundler
6
8
  script:
7
9
  - bundle exec rake rubocop
8
10
  - bundle exec rake rspec
9
11
  jobs:
10
12
  fast_finish: true
11
13
  include:
12
- - rvm: 2.4.9
13
- os: [linux, osx]
14
- - rvm: 2.5.7
15
- os: [linux, osx]
16
- - rvm: 2.6.5
17
- os: [linux, osx]
18
- - rvm: 2.7.0
19
- os: [linux, osx]
14
+ - rvm: 2.4.10
15
+ - rvm: 2.5.8
16
+ - rvm: 2.6.6
17
+ - rvm: 2.7.1
20
18
  - rvm: ruby-head
21
- os: [linux, osx]
22
19
  - rvm: jruby-head
23
- os: [linux, osx]
24
20
  allow_failures:
25
21
  - rvm: ruby-head
26
- os: [linux, osx]
27
22
  - rvm: jruby-head
28
- os: [linux, osx]
@@ -1,6 +1,37 @@
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
+
11
+ ## [0.7.0] - 2020-06-20
12
+ ### Added
13
+ - `SmartCore::Container.define {}` - an ability to avoid explicit class definition that allows
14
+ to create container instances from an anonymous container class imidietly
15
+
16
+ ## [0.6.0] - 2020-01-12
17
+ ### Added
18
+ - Missing memoization flag `:memoize` for runtime-based dependency registration:
19
+ - `memoize: false` by default;
20
+ - signature: `SmartCore::Container#register(dependency_name, memoize: false, &dependency)`
21
+
22
+ ## [0.5.0] - 2020-01-07
23
+ ### Added
24
+ - Key predicates (`#key?(key)`, `#dependency?(path, memoized: nil/true/false)`, `#namespace?(path)`);
25
+
26
+ ## [0.4.0] - 2020-01-06
27
+ ### Added
28
+ - `#keys(all_variants: false)` - return a list of dependency keys
29
+ (`all_variants: true` is mean "including namespace kaeys");
30
+ - `#each_dependency(yield_all: false) { |key, value| }` - iterate over conteiner's dependencies
31
+ (`yield_all: true` will include nested containers to iteration process);
32
+ ### Fixed
33
+ - `SmartCore::Container::ResolvingError` class has incorrect message attribute name;
34
+
4
35
  ## [0.3.0] - 2020-01-05
5
36
  ### Changed
6
37
  - Dependency resolving is not memoized by default (previously: totally memoized 😱);
@@ -1,83 +1,98 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_container (0.3.0)
5
- smart_engine (~> 0.2)
4
+ smart_container (0.8.0)
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,7 +22,27 @@ require 'smart_core/container'
22
22
 
23
23
  ---
24
24
 
25
- ## Synopsis (demo)
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)
40
+
41
+ ---
42
+
43
+ ## Functionality
44
+
45
+ #### container class creation
26
46
 
27
47
  ```ruby
28
48
  class Container < SmartCore::Container
@@ -41,20 +61,279 @@ class Container < SmartCore::Container
41
61
  # dependencies are not memoized by default (memoize: false)
42
62
  register(:random) { rand(1000) }
43
63
  end
64
+ ```
65
+
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
+ ---
44
89
 
90
+ #### container instantiation and dependency resolving
91
+
92
+ ```ruby
45
93
  container = Container.new # create container instance
94
+ ```
46
95
 
96
+ ```ruby
47
97
  container['database.resolver'] # => #<SomeDatabaseResolver:0x00007f0f0f1d6332>
48
98
  container['database.cache.redis'] # => #<RedisClient:0x00007f0f0f1d0158>
49
99
  container['logger'] # => #<Logger:0x00007f5f0f2f0158>
50
100
 
101
+ container.resolve('logger') # #resolve(path) is an alias for #[](path)
102
+
51
103
  # non-memoized dependency
52
104
  container['random'] # => 352
53
105
  container['random'] # => 57
106
+
107
+ # trying to resolve a namespace as dependency
108
+ container['database'] # => SmartCore::Container::ResolvingError
109
+
110
+ # but you can fetch any depenendency type (internal containers and values) via #fetch
111
+ container.fetch('database') # => SmartCore::Container (nested container)
112
+ container.fetch('database.resolver') # => #<SomeDatabaseResolver:0x00007f0f0f1d6332>
113
+ ```
114
+
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):
133
+
134
+ ```ruby
135
+ # get dependnecy keys (only dependencies)
136
+ container.keys
137
+ # => result:
138
+ [
139
+ 'database.resolver',
140
+ 'database.cache.memcached',
141
+ 'database.cache.redis',
142
+ 'logger',
143
+ 'random'
144
+ ]
145
+ ```
146
+ ```ruby
147
+ # get all keys (namespaces and dependencies)
148
+ container.keys(all_variants: true)
149
+ # => result:
150
+ [
151
+ 'database', # namespace
152
+ 'database.resolver',
153
+ 'database.cache', # namespace
154
+ 'database.cache.memcached',
155
+ 'database.cache.redis',
156
+ 'logger',
157
+ 'random'
158
+ ]
159
+ ```
160
+
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?
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
54
186
  ```
55
187
 
56
188
  ---
57
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
+ #### 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
+
307
+ ## Roadmap
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
+
315
+ - support for instant dependency registration:
316
+
317
+ ```ruby
318
+ # common (dynamic) way:
319
+ register('dependency_name') { dependency_value }
320
+
321
+ # instant way:
322
+ register('dependency_name', dependency_value)
323
+ ```
324
+
325
+ - support for memoization ignorance during dependency resolving:
326
+
327
+ ```ruby
328
+ resolve('logger', :allocate) # Draft
329
+ ```
330
+
331
+ - container composition;
332
+
333
+ - support for fallback block in `.resolve` operation (similar to `Hash#fetch` works);
334
+
335
+ ---
336
+
58
337
  ## Contributing
59
338
 
60
339
  - Fork it ( https://github.com/smart-rb/smart_container/fork )