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.
@@ -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 klass [Class] class name
89
+ # @param bean_name [Symbol]
90
+ # @param package [Symbol]
91
+ # @param context [Symbol]
94
92
  # return [BeanDefinition]
95
- def get_bean_definition_by_class(klass)
96
- bean_definitions_storage.find_by_class(klass)
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(bean_name, package: package, context: context)
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
@@ -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
- super(%Q(
21
- Unable to create bean :#{bean_name}.
22
- Several definitions were found.
23
- #{bean_definitions.map(&:inspect).join("\n\n")}
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
@@ -14,6 +14,10 @@ class SmartIoC::ExtraPackageContexts
14
14
  @data[package_name] = context
15
15
  end
16
16
 
17
+ def package_context(package_name)
18
+ @data[package_name]
19
+ end
20
+
17
21
  def get_context(package_name)
18
22
  @data[package_name] || SmartIoC::Container::DEFAULT_CONTEXT
19
23
  end
@@ -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 = caller[0].split(':').first
35
-
36
- bean_definition = SmartIoC.get_bean_definition_by_class(self)
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 inject(bean_name, ref: nil, from: nil)
81
- bean_definition = SmartIoC::Container.get_instance.get_bean_definition_by_class(self)
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.add_dependency(
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
- if bean_definition.is_instance?
94
- class_eval %Q(
95
- private
96
- attr_reader :#{bean_name}
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
@@ -1,3 +1,3 @@
1
1
  module SmartIoC
2
- VERSION = "0.2.5"
2
+ VERSION = "0.3.6"
3
3
  end
@@ -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', '~> 1.3'
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: :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
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
- "class: Object
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
- class Repo
8
- include SmartIoC::Iocify
9
- bean :repo, context: :default, package: :bean_factory
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
- class TestRepo
13
- include SmartIoC::Iocify
14
- bean :repo, context: :test, package: :bean_factory
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
- class DAO
18
- include SmartIoC::Iocify
19
- bean :dao, context: :default, package: :bean_factory
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
- class Factory
26
- include SmartIoC::Iocify
27
- bean :factory, factory_method: :build_bean, package: :bean_factory
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 be_a(TestRepo)
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 be_a(Repo)
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 be_a(DAO)
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
- attr_reader :prototype_bean
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
- attr_reader :second_singleton_bean
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).not_to eq(prototype_bean2_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
- attr_reader :prototype_service1, :prototype_service2
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
- attr_reader :prototype_repo, :singleton_repo
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
- attr_reader :prototype_repo, :singleton_repo
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