smart_ioc 0.2.5 → 0.3.6
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 +5 -5
- data/Gemfile +1 -0
- data/Gemfile.lock +27 -26
- data/lib/smart_ioc.rb +23 -3
- data/lib/smart_ioc/args.rb +1 -1
- data/lib/smart_ioc/bean.rb +33 -0
- data/lib/smart_ioc/bean_definition.rb +8 -4
- data/lib/smart_ioc/bean_definitions_storage.rb +27 -6
- data/lib/smart_ioc/bean_factory.rb +38 -179
- data/lib/smart_ioc/container.rb +20 -15
- data/lib/smart_ioc/errors.rb +13 -15
- data/lib/smart_ioc/extra_package_contexts.rb +4 -0
- data/lib/smart_ioc/iocify.rb +78 -16
- data/lib/smart_ioc/version.rb +1 -1
- data/smart_ioc.gemspec +1 -1
- data/spec/smart_ioc/bean_definition_spec.rb +10 -10
- data/spec/smart_ioc/bean_factory_spec.rb +49 -23
- data/spec/smart_ioc/benchmark_mode_spec.rb +13 -0
- data/spec/smart_ioc/example/admins/repository/admins_dao.rb +8 -8
- data/spec/smart_ioc/example/admins/repository/admins_repository.rb +2 -5
- data/spec/smart_ioc/example/users/repository/users_dao.rb +5 -3
- data/spec/smart_ioc/example/users/repository/users_repository.rb +2 -0
- data/spec/smart_ioc/example/utils/config.rb +5 -1
- data/spec/smart_ioc/factory_method_spec.rb +7 -7
- data/spec/smart_ioc/object_spec.rb +1 -1
- data/spec/smart_ioc/recursive_spec.rb +24 -0
- metadata +12 -9
- data/lib/smart_ioc/scopes/bean.rb +0 -13
data/lib/smart_ioc/container.rb
CHANGED
@@ -13,10 +13,6 @@ module SmartIoC
|
|
13
13
|
def clear
|
14
14
|
@container = nil
|
15
15
|
end
|
16
|
-
|
17
|
-
def get_bean(bean_name, package: nil, context: nil)
|
18
|
-
get_instance.get_bean(bean_name, package: package, context: context)
|
19
|
-
end
|
20
16
|
end
|
21
17
|
|
22
18
|
def initialize
|
@@ -36,8 +32,9 @@ module SmartIoC
|
|
36
32
|
# @param path [String] bean file absolute path
|
37
33
|
# @param scope [Symbol] scope value
|
38
34
|
# @param context [Symbol] bean context
|
35
|
+
# @param after_init [Symbol] name of bean method that will be called after bean initialization
|
39
36
|
# @return [SmartIoC::BeanDefinition] bean definition
|
40
|
-
def register_bean(bean_name:, klass:, context:, scope:, path:,
|
37
|
+
def register_bean(bean_name:, klass:, context:, scope:, path:, after_init:,
|
41
38
|
factory_method: nil, package_name: nil, instance: true)
|
42
39
|
context ||= DEFAULT_CONTEXT
|
43
40
|
|
@@ -60,8 +57,6 @@ module SmartIoC
|
|
60
57
|
raise ArgumentError, "bean scope should be one of #{allowed_scopes.inspect}"
|
61
58
|
end
|
62
59
|
|
63
|
-
package_name ||= SmartIoC::BeanLocations.get_bean_package(path)
|
64
|
-
|
65
60
|
if !package_name
|
66
61
|
raise ArgumentError, %Q(
|
67
62
|
Package name should be given for bean :#{bean_name}.
|
@@ -81,7 +76,8 @@ module SmartIoC
|
|
81
76
|
instance: instance,
|
82
77
|
factory_method: factory_method,
|
83
78
|
context: context,
|
84
|
-
scope: scope
|
79
|
+
scope: scope,
|
80
|
+
after_init: after_init,
|
85
81
|
)
|
86
82
|
|
87
83
|
bean_definitions_storage.push(bean_definition)
|
@@ -90,10 +86,12 @@ module SmartIoC
|
|
90
86
|
end
|
91
87
|
|
92
88
|
# Returns bean definition for specific class
|
93
|
-
# @param
|
89
|
+
# @param bean_name [Symbol]
|
90
|
+
# @param package [Symbol]
|
91
|
+
# @param context [Symbol]
|
94
92
|
# return [BeanDefinition]
|
95
|
-
def
|
96
|
-
bean_definitions_storage.
|
93
|
+
def get_bean_definition(bean_name, package, context)
|
94
|
+
bean_definitions_storage.find_bean(bean_name, package, context)
|
97
95
|
end
|
98
96
|
|
99
97
|
# Sets new load proc
|
@@ -116,10 +114,17 @@ module SmartIoC
|
|
116
114
|
|
117
115
|
# @param bean_name [Symbol] bean name
|
118
116
|
# @param optional package [Symbol] package name
|
117
|
+
# @param optional parent_bean_definition [SmartIoc::BeanDefinition] bean definition of parent bean
|
119
118
|
# @param optional context [Symbol] package context
|
120
119
|
# @return bean instance from container
|
121
|
-
def get_bean(bean_name, package: nil, context: nil)
|
122
|
-
bean_factory.get_bean(
|
120
|
+
def get_bean(bean_name, package: nil, context: nil, parent_bean_definition: nil, parent_bean_name: nil)
|
121
|
+
bean_factory.get_bean(
|
122
|
+
bean_name,
|
123
|
+
package: package,
|
124
|
+
parent_bean_definition: parent_bean_definition,
|
125
|
+
context: context,
|
126
|
+
parent_bean_name: parent_bean_name,
|
127
|
+
)
|
123
128
|
end
|
124
129
|
|
125
130
|
def clear_scopes
|
@@ -136,9 +141,9 @@ module SmartIoC
|
|
136
141
|
def require_bean(bean_name)
|
137
142
|
bean_factory.bean_file_loader.require_bean(bean_name)
|
138
143
|
end
|
139
|
-
|
144
|
+
|
140
145
|
private
|
141
|
-
|
146
|
+
|
142
147
|
def bean_factory
|
143
148
|
@bean_factory ||= SmartIoC::BeanFactory.new(bean_definitions_storage, extra_package_contexts)
|
144
149
|
end
|
data/lib/smart_ioc/errors.rb
CHANGED
@@ -5,23 +5,21 @@ 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
|
-
|
18
8
|
class AmbiguousBeanDefinition < StandardError
|
9
|
+
attr_accessor :parent_bean_definition
|
10
|
+
|
19
11
|
def initialize(bean_name, bean_definitions)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
@bean_name = bean_name
|
13
|
+
@bean_definitions = bean_definitions
|
14
|
+
end
|
15
|
+
|
16
|
+
def message
|
17
|
+
<<~EOS
|
18
|
+
Unable to inject bean :#{@bean_name}#{@parent_bean_definition ? " into :#{@parent_bean_definition.name} (package: #{@parent_bean_definition.package})" : ""}.
|
19
|
+
Several bean definitions with name :#{@bean_name} were found:
|
20
|
+
|
21
|
+
#{@bean_definitions.map(&:inspect).join("\n\n")}
|
22
|
+
EOS
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
data/lib/smart_ioc/iocify.rb
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
# Example of usage:
|
3
3
|
# class Bar
|
4
4
|
# bean :bar
|
5
|
+
#
|
6
|
+
# def call
|
7
|
+
# end
|
5
8
|
# end
|
6
9
|
#
|
7
10
|
# class Foo
|
@@ -12,6 +15,7 @@
|
|
12
15
|
# inject :some_bar, ref: bar, from: :repository
|
13
16
|
#
|
14
17
|
# def hello_world
|
18
|
+
# some_bar.call
|
15
19
|
# puts 'Hello world'
|
16
20
|
# end
|
17
21
|
# end
|
@@ -23,17 +27,48 @@ module SmartIoC::Iocify
|
|
23
27
|
end
|
24
28
|
|
25
29
|
module ClassMethods
|
30
|
+
def package(name)
|
31
|
+
raise ArgumentError, "name should be a Symbol" if !name.is_a?(Symbol)
|
32
|
+
@package = name
|
33
|
+
end
|
34
|
+
|
35
|
+
def context(name)
|
36
|
+
raise ArgumentError, "name should be a Symbol" if !name.is_a?(Symbol)
|
37
|
+
@context = name
|
38
|
+
end
|
39
|
+
|
40
|
+
def factory_method(name)
|
41
|
+
raise ArgumentError, "name should be a Symbol" if !name.is_a?(Symbol)
|
42
|
+
@factory_method = name
|
43
|
+
end
|
44
|
+
|
45
|
+
def scope(name)
|
46
|
+
raise ArgumentError, "name should be a Symbol" if !name.is_a?(Symbol)
|
47
|
+
@scope = name
|
48
|
+
end
|
49
|
+
|
50
|
+
def instance
|
51
|
+
@instance = true
|
52
|
+
end
|
53
|
+
|
54
|
+
def after_init(name)
|
55
|
+
raise ArgumentError, "name should be a Symbol" if !name.is_a?(Symbol)
|
56
|
+
@after_init = name
|
57
|
+
end
|
58
|
+
|
26
59
|
# @param bean_name [Symbol] bean name
|
27
60
|
# @param scope [Symbol] bean scope (defaults to :singleton)
|
28
61
|
# @param package [nil or Symbol]
|
29
62
|
# @param factory_method [nil or Symbol] factory method to get bean
|
30
63
|
# @param instance [Boolean] instance based bean or class-based
|
31
64
|
# @param context [Symbol] set bean context (ex: :test)
|
65
|
+
# @param after_init [Symbol] name of bean method that will be called after bean initialization (ex: :test)
|
32
66
|
# @return nil
|
33
|
-
def bean(bean_name, scope: nil, package: nil, instance: true, factory_method: nil, context: nil)
|
34
|
-
file_path
|
35
|
-
|
36
|
-
|
67
|
+
def bean(bean_name, scope: nil, package: nil, instance: true, factory_method: nil, context: nil, after_init: nil, file_path: nil)
|
68
|
+
file_path ||= caller[0].split(':').first
|
69
|
+
package ||= SmartIoC::BeanLocations.get_bean_package(file_path)
|
70
|
+
context ||= SmartIoC::Container::DEFAULT_CONTEXT
|
71
|
+
bean_definition = SmartIoC.get_bean_definition(bean_name, package, context)
|
37
72
|
|
38
73
|
if bean_definition
|
39
74
|
if bean_definition.path == file_path
|
@@ -55,7 +90,8 @@ module SmartIoC::Iocify
|
|
55
90
|
package_name: package,
|
56
91
|
instance: instance,
|
57
92
|
factory_method: factory_method,
|
58
|
-
context: context
|
93
|
+
context: context,
|
94
|
+
after_init: after_init,
|
59
95
|
)
|
60
96
|
|
61
97
|
if bean_definition.is_instance?
|
@@ -66,9 +102,20 @@ module SmartIoC::Iocify
|
|
66
102
|
)
|
67
103
|
end
|
68
104
|
|
105
|
+
self.instance_variable_set(:@bean_definition, bean_definition)
|
106
|
+
|
69
107
|
nil
|
70
108
|
end
|
71
109
|
|
110
|
+
def inject(bean_name, ref: nil, from: nil)
|
111
|
+
if @anonymous_bean
|
112
|
+
@injects ||= []
|
113
|
+
@injects.push({bean_name: bean_name, ref: ref, from: from})
|
114
|
+
else
|
115
|
+
register_inject(bean_name, ref: ref, from: from)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
72
119
|
# @param bean_name [Symbol] injected bean name
|
73
120
|
# @param ref [Symbol] refferece bean to be sef as bean_name
|
74
121
|
# @param from [Symbol] package name
|
@@ -77,29 +124,44 @@ module SmartIoC::Iocify
|
|
77
124
|
# @raise [ArgumentError] if ref provided and ref is not a Symbol
|
78
125
|
# @raise [ArgumentError] if from provided and from is not a Symbol
|
79
126
|
# @raise [ArgumentError] if bean with same name was injected before
|
80
|
-
def
|
81
|
-
bean_definition
|
82
|
-
|
83
|
-
if bean_definition.nil?
|
127
|
+
def register_inject(bean_name, ref: nil, from: nil)
|
128
|
+
if !@bean_definition
|
84
129
|
raise ArgumentError, "#{self.to_s} is not registered as bean. Add `bean :bean_name` declaration"
|
85
130
|
end
|
86
131
|
|
87
|
-
bean_definition
|
132
|
+
bd = @bean_definition
|
133
|
+
|
134
|
+
bd.add_dependency(
|
88
135
|
bean_name: bean_name,
|
89
136
|
ref: ref,
|
90
137
|
package: from
|
91
138
|
)
|
92
139
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
140
|
+
bean_method = Proc.new do
|
141
|
+
bean = instance_variable_get(:"@#{bean_name}")
|
142
|
+
return bean if bean
|
143
|
+
|
144
|
+
klass = self.is_a?(Class) ? self : self.class
|
145
|
+
|
146
|
+
bean = SmartIoC::Container.get_instance.get_bean(
|
147
|
+
ref || bean_name,
|
148
|
+
package: from,
|
149
|
+
parent_bean_definition: bd,
|
150
|
+
parent_bean_name: bd.name,
|
97
151
|
)
|
152
|
+
|
153
|
+
instance_variable_set(:"@#{bean_name}", bean)
|
154
|
+
end
|
155
|
+
|
156
|
+
if bd.is_instance?
|
157
|
+
define_method bean_name, &bean_method
|
158
|
+
private bean_name
|
98
159
|
else
|
160
|
+
define_singleton_method bean_name, &bean_method
|
161
|
+
|
99
162
|
class_eval %Q(
|
100
163
|
class << self
|
101
|
-
private
|
102
|
-
attr_reader :#{bean_name}
|
164
|
+
private :#{bean_name}
|
103
165
|
end
|
104
166
|
)
|
105
167
|
end
|
data/lib/smart_ioc/version.rb
CHANGED
data/smart_ioc.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(spec)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_development_dependency 'bundler'
|
21
|
+
spec.add_development_dependency 'bundler'
|
22
22
|
spec.add_development_dependency 'rake'
|
23
23
|
spec.add_development_dependency "codecov"
|
24
24
|
end
|
@@ -4,19 +4,19 @@ describe SmartIoC::BeanDefinition do
|
|
4
4
|
describe "::inspect" do
|
5
5
|
it {
|
6
6
|
bd = SmartIoC::BeanDefinition.new(
|
7
|
-
name:
|
8
|
-
package:
|
9
|
-
path:
|
10
|
-
klass:
|
11
|
-
scope:
|
12
|
-
context:
|
13
|
-
instance:
|
14
|
-
factory_method: nil
|
7
|
+
name: :test_bean,
|
8
|
+
package: :test_package,
|
9
|
+
path: 'current_dir',
|
10
|
+
klass: Object,
|
11
|
+
scope: :singleton,
|
12
|
+
context: :default,
|
13
|
+
instance: false,
|
14
|
+
factory_method: nil,
|
15
|
+
after_init: nil,
|
15
16
|
)
|
16
17
|
|
17
18
|
str =
|
18
|
-
"
|
19
|
-
name: :test_bean
|
19
|
+
"name: :test_bean
|
20
20
|
package: :test_package
|
21
21
|
context: :default
|
22
22
|
path: current_dir
|
@@ -4,27 +4,42 @@ describe SmartIoC::BeanFactory do
|
|
4
4
|
before :all do
|
5
5
|
SmartIoC.clear
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
bean :repo do
|
8
|
+
context :default
|
9
|
+
package :bean_factory
|
10
|
+
|
11
|
+
def call
|
12
|
+
'default'
|
13
|
+
end
|
10
14
|
end
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
bean :repo do
|
17
|
+
context :test
|
18
|
+
package :bean_factory
|
19
|
+
|
20
|
+
inject :dao
|
21
|
+
|
22
|
+
def call
|
23
|
+
dao.call
|
24
|
+
'test'
|
25
|
+
end
|
15
26
|
end
|
16
27
|
|
17
|
-
|
18
|
-
|
19
|
-
|
28
|
+
bean :dao do
|
29
|
+
context :default
|
30
|
+
package :bean_factory
|
31
|
+
|
32
|
+
def call
|
33
|
+
'dao'
|
34
|
+
end
|
20
35
|
end
|
21
36
|
|
22
37
|
class TestObject
|
23
38
|
end
|
24
39
|
|
25
|
-
|
26
|
-
|
27
|
-
|
40
|
+
bean :factory do
|
41
|
+
factory_method :build_bean
|
42
|
+
package :bean_factory
|
28
43
|
|
29
44
|
def build_bean
|
30
45
|
TestObject.new
|
@@ -32,6 +47,15 @@ describe SmartIoC::BeanFactory do
|
|
32
47
|
end
|
33
48
|
end
|
34
49
|
|
50
|
+
it 'returns benchmark time to load bean' do
|
51
|
+
SmartIoC.benchmark_mode(true)
|
52
|
+
|
53
|
+
SmartIoC.set_extra_context_for_package(:bean_factory, :test)
|
54
|
+
SmartIoC.get_bean(:repo)
|
55
|
+
|
56
|
+
SmartIoC.benchmark_mode(false)
|
57
|
+
end
|
58
|
+
|
35
59
|
it 'returns same instance for singleton scope' do
|
36
60
|
SmartIoC.set_extra_context_for_package(:bean_factory, :test)
|
37
61
|
instance1 = SmartIoC.get_bean(:repo)
|
@@ -47,17 +71,17 @@ describe SmartIoC::BeanFactory do
|
|
47
71
|
|
48
72
|
it 'returns proper bean for test context' do
|
49
73
|
SmartIoC.set_extra_context_for_package(:bean_factory, :test)
|
50
|
-
expect(SmartIoC.get_bean(:repo)).to
|
74
|
+
expect(SmartIoC.get_bean(:repo).call).to eq('test')
|
51
75
|
end
|
52
76
|
|
53
77
|
it 'returns proper bean for default context' do
|
54
78
|
SmartIoC.set_extra_context_for_package(:bean_factory, :default)
|
55
|
-
expect(SmartIoC.get_bean(:repo)).to
|
79
|
+
expect(SmartIoC.get_bean(:repo).call).to eq('default')
|
56
80
|
end
|
57
81
|
|
58
82
|
it 'returns proper bean for test context with fallback to default context' do
|
59
83
|
SmartIoC.set_extra_context_for_package(:bean_factory, :test)
|
60
|
-
expect(SmartIoC.get_bean(:dao)).to
|
84
|
+
expect(SmartIoC.get_bean(:dao).call).to eq('dao')
|
61
85
|
end
|
62
86
|
|
63
87
|
it 'updates dependencies' do
|
@@ -67,7 +91,7 @@ describe SmartIoC::BeanFactory do
|
|
67
91
|
|
68
92
|
inject :prototype_bean
|
69
93
|
|
70
|
-
|
94
|
+
public :prototype_bean
|
71
95
|
end
|
72
96
|
|
73
97
|
class SecondSingletonBean
|
@@ -81,7 +105,7 @@ describe SmartIoC::BeanFactory do
|
|
81
105
|
|
82
106
|
inject :second_singleton_bean
|
83
107
|
|
84
|
-
|
108
|
+
public :second_singleton_bean
|
85
109
|
end
|
86
110
|
|
87
111
|
bean1 = SmartIoC.get_bean(:singleton_bean, package: :test)
|
@@ -95,7 +119,7 @@ describe SmartIoC::BeanFactory do
|
|
95
119
|
second_singleton_bean2_object_id = bean2.prototype_bean.second_singleton_bean.object_id
|
96
120
|
|
97
121
|
expect(bean1_object_id).to eq(bean2_object_id)
|
98
|
-
expect(prototype_bean1_object_id).
|
122
|
+
expect(prototype_bean1_object_id).to eq(prototype_bean2_object_id)
|
99
123
|
expect(second_singleton_bean1_object_id).to eq(second_singleton_bean2_object_id)
|
100
124
|
end
|
101
125
|
|
@@ -108,7 +132,7 @@ describe SmartIoC::BeanFactory do
|
|
108
132
|
inject :prototype_service1
|
109
133
|
inject :prototype_service2
|
110
134
|
|
111
|
-
|
135
|
+
public :prototype_service1, :prototype_service2
|
112
136
|
end
|
113
137
|
|
114
138
|
class PrototypeService1
|
@@ -118,7 +142,7 @@ describe SmartIoC::BeanFactory do
|
|
118
142
|
inject :prototype_repo
|
119
143
|
inject :singleton_repo
|
120
144
|
|
121
|
-
|
145
|
+
public :prototype_repo, :singleton_repo
|
122
146
|
end
|
123
147
|
|
124
148
|
class PrototypeService2
|
@@ -128,22 +152,24 @@ describe SmartIoC::BeanFactory do
|
|
128
152
|
inject :prototype_repo
|
129
153
|
inject :singleton_repo
|
130
154
|
|
131
|
-
|
155
|
+
public :prototype_repo, :singleton_repo
|
132
156
|
end
|
133
157
|
|
134
158
|
class PrototypeRepo
|
135
159
|
include SmartIoC::Iocify
|
160
|
+
|
136
161
|
bean :prototype_repo, scope: :prototype, package: :prototype
|
137
162
|
end
|
138
163
|
|
139
164
|
class SingletonRepo
|
140
165
|
include SmartIoC::Iocify
|
166
|
+
|
141
167
|
bean :singleton_repo, scope: :singleton, package: :prototype
|
142
168
|
end
|
143
169
|
end
|
144
170
|
|
145
171
|
it 'injects prototype beans with different object id' do
|
146
|
-
prototype_bean = SmartIoC.get_bean(:prototype_bean)
|
172
|
+
prototype_bean = SmartIoC.get_bean(:prototype_bean, package: :prototype)
|
147
173
|
repo1_object_id = prototype_bean.prototype_service1.prototype_repo.object_id
|
148
174
|
repo2_object_id = prototype_bean.prototype_service2.prototype_repo.object_id
|
149
175
|
|
@@ -151,7 +177,7 @@ describe SmartIoC::BeanFactory do
|
|
151
177
|
end
|
152
178
|
|
153
179
|
it 'injects singleton beans with same object id' do
|
154
|
-
prototype_bean = SmartIoC.get_bean(:prototype_bean)
|
180
|
+
prototype_bean = SmartIoC.get_bean(:prototype_bean, package: :prototype)
|
155
181
|
repo1_object_id = prototype_bean.prototype_service1.singleton_repo.object_id
|
156
182
|
repo2_object_id = prototype_bean.prototype_service2.singleton_repo.object_id
|
157
183
|
|