smart_container 0.3.0 → 0.8.0

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: 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 )