smart_ioc 0.1.24 → 0.1.25

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
  SHA1:
3
- metadata.gz: fe545eaedb9fcf8e79eb588a1ae17a8c4c0715b4
4
- data.tar.gz: 4a5346a0354dd07c85ab0e8f0acc24d08e986000
3
+ metadata.gz: 0198db2374679046b00a1332fee4de0aad13c129
4
+ data.tar.gz: c50b72b48d02dabb4fa56f7b1cfeca2d4a5673a6
5
5
  SHA512:
6
- metadata.gz: 67408406b25290d15c3b09e04279b1c48ece7ac8c579f3464f91864003c30db073b0ed0941c4531f768e3c3ce31325f0d37276da992cd5acbbcc584d865122e0
7
- data.tar.gz: 3e4da384c7d5ab400faf863eb6f7921da529626265f25544a5243303cfcfd5e6a0122162d54a98791d46c75bef37450cce13f1ff40b09770f4e9723bf8844905
6
+ metadata.gz: f39126254e35139b03f025db25560c059bfa563a1ca9fbf261b3ab96bc7ee38d5db7a92dee3312ba6e2790e1bc380d81c4419fcbb1e43992e44db578d1066bb7
7
+ data.tar.gz: 73141b108b4f4946f6933a4ce000c8f4e863973ae442520a5ede89a0a1f11b086126ba754a7f7acbbdb1e9c3417f0a39324907b980d5212774a7ff7e0efcdb50
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_ioc (0.1.24)
4
+ smart_ioc (0.1.25)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,6 +1,6 @@
1
1
  class SmartIoC::BeanDefinition
2
2
  include SmartIoC::Args
3
-
3
+
4
4
  attr_reader :name, :package, :path, :klass, :scope, :instance, :factory_method,
5
5
  :context, :dependencies
6
6
 
@@ -34,27 +34,48 @@ class SmartIoC::BeanFactory
34
34
  check_arg(package, :package, Symbol) if package
35
35
  check_arg(context, :context, Symbol) if context
36
36
 
37
+ get_or_build_bean(bean_name, package, context)
38
+ end
39
+
40
+ private
41
+
42
+ def get_or_build_bean(bean_name, package, context, history = Set.new)
37
43
  @bean_file_loader.require_bean(bean_name)
38
44
 
39
45
  context = autodetect_context(bean_name, package, context)
40
46
  bean_definition = @bean_definitions_storage.find(bean_name, package, context)
41
47
  scope = get_scope(bean_definition)
42
- bean = scope.get_bean(bean_definition.klass)
48
+ scope_bean = scope.get_bean(bean_definition.klass)
49
+ is_recursive = history.include?(bean_name)
43
50
 
44
- if bean
45
- update_dependencies(bean, bean_definition)
46
- bean
51
+ history << bean_name
52
+
53
+ if scope_bean
54
+ update_dependencies(scope_bean.bean, bean_definition)
55
+ scope_bean.bean
47
56
  else
57
+ if is_recursive
58
+ raise LoadRecursion.new(bean_definition)
59
+ end
60
+
48
61
  dependency_cache = {}
49
- beans_cache = {}
62
+ beans_cache = init_bean_definition_cache(bean_definition)
50
63
 
51
64
  autodetect_bean_definitions_for_dependencies(bean_definition, dependency_cache)
52
- preload_beans(bean_definition, dependency_cache, beans_cache)
65
+ preload_beans(bean_definition, dependency_cache, beans_cache[bean_definition])
53
66
  load_bean(bean_definition, dependency_cache, beans_cache)
54
67
  end
55
68
  end
56
69
 
57
- private
70
+ def init_bean_definition_cache(bean_definition)
71
+ {
72
+ bean_definition => {
73
+ scope_bean: nil,
74
+ dependencies: {
75
+ }
76
+ }
77
+ }
78
+ end
58
79
 
59
80
  def update_dependencies(bean, bean_definition, updated_beans = {})
60
81
  bean_definition.dependencies.each do |dependency|
@@ -63,15 +84,20 @@ class SmartIoC::BeanFactory
63
84
  )
64
85
 
65
86
  scope = get_scope(bean_definition)
66
- dep_bean = updated_beans[bd] || scope.get_bean(bd.klass)
87
+ dep_bean = updated_beans[bd]
88
+
89
+ if !dep_bean && scope_bean = scope.get_bean(bd.klass)
90
+ dep_bean = scope_bean.bean
91
+ end
67
92
 
68
93
  if !dep_bean
69
- dep_bean = get_bean(
70
- bd.name, package: bd.package, context: bd.context
71
- )
94
+ dep_bean = get_or_build_bean(bd.name, bd.package, bd.context)
72
95
 
73
96
  bean.instance_variable_set(:"@#{dependency.bean}", dep_bean)
74
- updated_beans[bd] = dep_bean
97
+
98
+ if !scope.is_a?(SmartIoC::Scopes::Prototype)
99
+ updated_beans[bd] = dep_bean
100
+ end
75
101
  else
76
102
  update_dependencies(dep_bean, bd, updated_beans)
77
103
  end
@@ -151,8 +177,8 @@ class SmartIoC::BeanFactory
151
177
  def preload_beans(bean_definition, dependency_cache, beans_cache)
152
178
  scope = get_scope(bean_definition)
153
179
 
154
- if bean = scope.get_bean(bean_definition.klass)
155
- beans_cache[bean_definition] = bean
180
+ if scope_bean = scope.get_bean(bean_definition.klass)
181
+ beans_cache[:scope_bean] = scope_bean
156
182
  else
157
183
  preload_bean_instance(bean_definition, beans_cache)
158
184
  end
@@ -160,20 +186,23 @@ class SmartIoC::BeanFactory
160
186
  bean_definition.dependencies.each do |dependency|
161
187
  bd = dependency_cache[dependency]
162
188
 
163
- next if beans_cache.has_key?(bd)
164
- preload_beans(bd, dependency_cache, beans_cache)
189
+ next if beans_cache[:dependencies].has_key?(bd)
190
+
191
+ dep_bean_cache = init_bean_definition_cache(bd)
192
+ beans_cache[:dependencies].merge!(dep_bean_cache)
193
+ preload_beans(bd, dependency_cache, dep_bean_cache[bd])
165
194
  end
166
195
  end
167
196
 
168
197
  def preload_bean_instance(bean_definition, beans_cache)
169
- return beans_cache[bean_definition] if beans_cache.has_key?(bean_definition)
198
+ return if beans_cache[:scope_bean]
170
199
 
171
200
  scope = get_scope(bean_definition)
172
- bean = scope.get_bean(bean_definition.klass)
201
+ scope_bean = scope.get_bean(bean_definition.klass)
173
202
 
174
- if bean
175
- beans_cache[bean_definition] = bean
176
- return bean
203
+ if scope_bean
204
+ beans_cache[:scope_bean] = scope_bean
205
+ return scope_bean
177
206
  end
178
207
 
179
208
  bean = if bean_definition.is_instance?
@@ -182,54 +211,74 @@ class SmartIoC::BeanFactory
182
211
  bean_definition.klass
183
212
  end
184
213
 
185
- scope.save_bean(bean_definition.klass, bean)
186
- beans_cache[bean_definition] = bean
214
+ scope_bean = SmartIoC::Scopes::Bean.new(bean, !bean_definition.has_factory_method?)
187
215
 
188
- bean
216
+ scope.save_bean(bean_definition.klass, scope_bean)
217
+ beans_cache[:scope_bean] = scope_bean
218
+
219
+ scope_bean
189
220
  end
190
221
 
191
- def load_bean(bean_definition, dependency_cache, beans_cache)
192
- # first let's setup beans with factory_methods
193
- zero_dep_bd_with_factory_methods = []
194
- bd_with_factory_methods = []
195
-
196
- beans_cache.each do |bean_definition, bean|
197
- if bean_definition.has_factory_method?
198
- if bean_definition.dependencies.size == 0
199
- zero_dep_bd_with_factory_methods << bean_definition
200
- else
201
- bd_with_factory_methods << bean_definition
202
- end
222
+ def init_factory_bean(bean_definition, bd_opts)
223
+ scope_bean = bd_opts[:scope_bean]
224
+
225
+ if !scope_bean.loaded
226
+ scope_bean.set_bean(scope_bean.bean.send(bean_definition.factory_method), true)
227
+ end
228
+ end
229
+
230
+ def init_zero_dep_factory_beans(beans_cache)
231
+ beans_cache.each do |bean_definition, bd_opts|
232
+ if bean_definition.has_factory_method? && bean_definition.dependencies.size == 0
233
+ init_factory_bean(bean_definition, bd_opts)
203
234
  end
235
+ init_zero_dep_factory_beans(bd_opts[:dependencies]) if !bd_opts[:dependencies].empty?
204
236
  end
237
+ end
205
238
 
206
- bd_with_factory_methods.each do |bean_definition|
207
- if cross_refference_bd = get_cross_refference(bd_with_factory_methods, bean_definition, dependency_cache)
208
- raise ArgumentError, "Factory method beans should not cross refference each other. Bean :#{bean_definition.name} cross refferences bean :#{cross_refference_bd.name}."
239
+ def collect_dependent_factory_beans(beans_cache, collection)
240
+ beans_cache.each do |bean_definition, bd_opts|
241
+ if bean_definition.has_factory_method? && bean_definition.dependencies.size > 0
242
+ collection << bean_definition
209
243
  end
244
+ collect_dependent_factory_beans(bd_opts[:dependencies], collection)
210
245
  end
211
246
 
212
- (zero_dep_bd_with_factory_methods + bd_with_factory_methods).each do |bean_definition|
213
- inject_beans(bean_definition, dependency_cache, beans_cache)
214
- bean = beans_cache[bean_definition]
215
- bean = bean.send(bean_definition.factory_method) if bean.is_a?(bean_definition.klass)
216
- beans_cache[bean_definition] = bean
217
- scope = get_scope(bean_definition)
218
- scope.save_bean(bean_definition.klass, bean)
247
+ collection
248
+ end
249
+
250
+ def init_dependent_factory_beans(beans_cache, dependency_cache)
251
+ dependent_factory_beans = collect_dependent_factory_beans(beans_cache, [])
252
+
253
+ dependent_factory_beans.each do |bean_definition|
254
+ if cross_refference_bd = get_cross_refference(dependent_factory_beans, bean_definition, dependency_cache)
255
+ raise ArgumentError, "Factory method beans should not cross refference each other. Bean :#{bean_definition.name} cross refferences bean :#{cross_refference_bd.name}."
256
+ end
219
257
  end
220
258
 
221
- inject_beans(bean_definition, dependency_cache, beans_cache)
259
+ beans_cache.each do |bean_definition, bd_opts|
260
+ if bean_definition.has_factory_method? && bean_definition.dependencies.size > 0
261
+ inject_beans(bean_definition, dependency_cache, bd_opts)
262
+ init_factory_bean(bean_definition, bd_opts)
263
+ end
264
+ init_dependent_factory_beans(bd_opts[:dependencies], dependency_cache)
265
+ end
266
+ end
222
267
 
223
- beans_cache[bean_definition]
268
+ def load_bean(bean_definition, dependency_cache, beans_cache)
269
+ init_zero_dep_factory_beans(beans_cache)
270
+ init_dependent_factory_beans(beans_cache, dependency_cache)
271
+ inject_beans(bean_definition, dependency_cache, beans_cache[bean_definition])
272
+ beans_cache[bean_definition][:scope_bean].bean
224
273
  end
225
274
 
226
275
  def inject_beans(bean_definition, dependency_cache, beans_cache)
227
- bean = beans_cache[bean_definition]
276
+ bean = beans_cache[:scope_bean].bean
228
277
  bean_definition.dependencies.each do |dependency|
229
278
  bd = dependency_cache[dependency]
230
- dep_bean = beans_cache[bd]
279
+ dep_bean = beans_cache[:dependencies][bd][:scope_bean].bean
231
280
  bean.instance_variable_set(:"@#{dependency.bean}", dep_bean)
232
- inject_beans(bd, dependency_cache, beans_cache)
281
+ inject_beans(bd, dependency_cache, beans_cache[:dependencies][bd])
233
282
  end
234
283
  end
235
284
 
@@ -5,6 +5,16 @@ module SmartIoC::Errors
5
5
  end
6
6
  end
7
7
 
8
+ class LoadRecursion < StandardError
9
+ def initialize(bean_definition)
10
+ super(%Q(
11
+ Unable to create bean :#{bean_definitions.name}.
12
+ Recursion found during bean load.
13
+ #{bean_definition.inspect}
14
+ ))
15
+ end
16
+ end
17
+
8
18
  class AmbiguousBeanDefinition < StandardError
9
19
  def initialize(bean_name, bean_definitions)
10
20
  super(%Q(
@@ -14,4 +24,4 @@ module SmartIoC::Errors
14
24
  ))
15
25
  end
16
26
  end
17
- end
27
+ end
@@ -0,0 +1,13 @@
1
+ class SmartIoC::Scopes::Bean
2
+ attr_reader :bean, :loaded
3
+
4
+ def initialize(bean, loaded)
5
+ @bean = bean
6
+ @loaded = loaded
7
+ end
8
+
9
+ def set_bean(bean, loaded)
10
+ @bean = bean
11
+ @loaded = loaded
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module SmartIoC
2
- VERSION = "0.1.24"
2
+ VERSION = "0.1.25"
3
3
  end
data/lib/smart_ioc.rb CHANGED
@@ -17,6 +17,7 @@ module SmartIoC
17
17
  autoload :Scopes, 'smart_ioc/scopes'
18
18
 
19
19
  module Scopes
20
+ autoload :Bean, 'smart_ioc/scopes/bean'
20
21
  autoload :Prototype, 'smart_ioc/scopes/prototype'
21
22
  autoload :Singleton, 'smart_ioc/scopes/singleton'
22
23
  autoload :Request, 'smart_ioc/scopes/request'
@@ -98,4 +98,64 @@ describe SmartIoC::BeanFactory do
98
98
  expect(prototype_bean1_object_id).not_to eq(prototype_bean2_object_id)
99
99
  expect(second_singleton_bean1_object_id).to eq(second_singleton_bean2_object_id)
100
100
  end
101
+
102
+ describe 'prototype scope' do
103
+ before :all do
104
+ class PrototypeBean
105
+ include SmartIoC::Iocify
106
+ bean :prototype_bean, scope: :prototype, package: :prototype
107
+
108
+ inject :prototype_service1
109
+ inject :prototype_service2
110
+
111
+ attr_reader :prototype_service1, :prototype_service2
112
+ end
113
+
114
+ class PrototypeService1
115
+ include SmartIoC::Iocify
116
+ bean :prototype_service1, scope: :prototype, package: :prototype
117
+
118
+ inject :prototype_repo
119
+ inject :singleton_repo
120
+
121
+ attr_reader :prototype_repo, :singleton_repo
122
+ end
123
+
124
+ class PrototypeService2
125
+ include SmartIoC::Iocify
126
+ bean :prototype_service2, scope: :prototype, package: :prototype
127
+
128
+ inject :prototype_repo
129
+ inject :singleton_repo
130
+
131
+ attr_reader :prototype_repo, :singleton_repo
132
+ end
133
+
134
+ class PrototypeRepo
135
+ include SmartIoC::Iocify
136
+ bean :prototype_repo, scope: :prototype, package: :prototype
137
+ end
138
+
139
+ class SingletonRepo
140
+ include SmartIoC::Iocify
141
+ bean :singleton_repo, scope: :singleton, package: :prototype
142
+ end
143
+ end
144
+
145
+ it 'injects prototype beans with different object id' do
146
+ prototype_bean = SmartIoC.get_bean(:prototype_bean)
147
+ repo1_object_id = prototype_bean.prototype_service1.prototype_repo.object_id
148
+ repo2_object_id = prototype_bean.prototype_service2.prototype_repo.object_id
149
+
150
+ expect(repo1_object_id).not_to eq(repo2_object_id)
151
+ end
152
+
153
+ it 'injects singleton beans with same object id' do
154
+ prototype_bean = SmartIoC.get_bean(:prototype_bean)
155
+ repo1_object_id = prototype_bean.prototype_service1.singleton_repo.object_id
156
+ repo2_object_id = prototype_bean.prototype_service2.singleton_repo.object_id
157
+
158
+ expect(repo1_object_id).to eq(repo2_object_id)
159
+ end
160
+ end
101
161
  end
@@ -46,4 +46,4 @@ describe 'Factory Method' do
46
46
  it 'assigns bean with factory method' do
47
47
  expect(@other_service.test_config).to be_a(TestConfig::Config)
48
48
  end
49
- end
49
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_ioc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.24
4
+ version: 0.1.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-05 00:00:00.000000000 Z
11
+ date: 2017-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -85,6 +85,7 @@ files:
85
85
  - lib/smart_ioc/inject_metadata.rb
86
86
  - lib/smart_ioc/iocify.rb
87
87
  - lib/smart_ioc/scopes.rb
88
+ - lib/smart_ioc/scopes/bean.rb
88
89
  - lib/smart_ioc/scopes/prototype.rb
89
90
  - lib/smart_ioc/scopes/request.rb
90
91
  - lib/smart_ioc/scopes/singleton.rb