smart_ioc 0.1.24 → 0.1.25

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