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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/smart_ioc/bean_definition.rb +1 -1
- data/lib/smart_ioc/bean_factory.rb +100 -51
- data/lib/smart_ioc/errors.rb +11 -1
- data/lib/smart_ioc/scopes/bean.rb +13 -0
- data/lib/smart_ioc/version.rb +1 -1
- data/lib/smart_ioc.rb +1 -0
- data/spec/smart_ioc/bean_factory_spec.rb +60 -0
- data/spec/smart_ioc/factory_method_spec.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0198db2374679046b00a1332fee4de0aad13c129
|
4
|
+
data.tar.gz: c50b72b48d02dabb4fa56f7b1cfeca2d4a5673a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f39126254e35139b03f025db25560c059bfa563a1ca9fbf261b3ab96bc7ee38d5db7a92dee3312ba6e2790e1bc380d81c4419fcbb1e43992e44db578d1066bb7
|
7
|
+
data.tar.gz: 73141b108b4f4946f6933a4ce000c8f4e863973ae442520a5ede89a0a1f11b086126ba754a7f7acbbdb1e9c3417f0a39324907b980d5212774a7ff7e0efcdb50
|
data/Gemfile.lock
CHANGED
@@ -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
|
-
|
48
|
+
scope_bean = scope.get_bean(bean_definition.klass)
|
49
|
+
is_recursive = history.include?(bean_name)
|
43
50
|
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
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]
|
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 =
|
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
|
-
|
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
|
155
|
-
beans_cache[
|
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
|
-
|
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[
|
198
|
+
return if beans_cache[:scope_bean]
|
170
199
|
|
171
200
|
scope = get_scope(bean_definition)
|
172
|
-
|
201
|
+
scope_bean = scope.get_bean(bean_definition.klass)
|
173
202
|
|
174
|
-
if
|
175
|
-
beans_cache[
|
176
|
-
return
|
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
|
-
|
186
|
-
beans_cache[bean_definition] = bean
|
214
|
+
scope_bean = SmartIoC::Scopes::Bean.new(bean, !bean_definition.has_factory_method?)
|
187
215
|
|
188
|
-
|
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
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
207
|
-
|
208
|
-
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
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
|
-
|
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
|
-
|
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[
|
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
|
|
data/lib/smart_ioc/errors.rb
CHANGED
@@ -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
|
data/lib/smart_ioc/version.rb
CHANGED
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
|
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.
|
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-
|
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
|