smart_ioc 0.2.4 → 0.3.5

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
- SHA1:
3
- metadata.gz: 81383d74ab85a917a839bd753f21154948881011
4
- data.tar.gz: 7d0e016b96264f7e48e42f94ec592109f9309fb4
2
+ SHA256:
3
+ metadata.gz: de564b00fb136146fd0f4d4182fe58f7cd9f1bd56c01a23ccc7aca185befc7e8
4
+ data.tar.gz: d9cb0e43111c988b77d8454fc3b7f45cf4aa2109a76839f2da17135eaef57e52
5
5
  SHA512:
6
- metadata.gz: 0fb8b1b59d3a435c7e675c49365f52edcd7eaf845aeb222c210a92236369c6ec7f5f31e911c5d87532e246337cf205ac45b94f62bac24bfcea87e6006ee54f23
7
- data.tar.gz: b74b9a016020a0e0d0ca23adb4055b117827f1b59ca3ac8af7b0604307fa8679116c769f0a2a72398902c65c988111ce97397ac0142da4778fc2513589b2e5d4
6
+ metadata.gz: 4a5a9d63019c4a0fabda18691014bbaf510ef703e1592a00a97bae1a582f523cfa8328c826a331764602664346771033ef3bf2d49bb3b27a98d9830e2f465f98
7
+ data.tar.gz: 9ae3b6e48602c173ca5ef0544c587c156d10e89616bbcdfb53ae293c98a4b6d047a3d2e01712b072ecfdc6bd519391735b20b12425ce513c9ebd6abb8d87d118
data/Gemfile CHANGED
@@ -6,4 +6,5 @@ gemspec
6
6
  group :test do
7
7
  gem 'rspec'
8
8
  gem 'simplecov'
9
+ gem 'byebug'
9
10
  end
@@ -1,44 +1,45 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_ioc (0.2.4)
4
+ smart_ioc (0.3.5)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- codecov (0.1.10)
9
+ byebug (11.1.3)
10
+ codecov (0.2.5)
11
+ colorize
10
12
  json
11
13
  simplecov
12
- url
13
- diff-lcs (1.3)
14
- docile (1.1.5)
15
- json (2.0.3)
16
- rake (12.0.0)
17
- rspec (3.5.0)
18
- rspec-core (~> 3.5.0)
19
- rspec-expectations (~> 3.5.0)
20
- rspec-mocks (~> 3.5.0)
21
- rspec-core (3.5.4)
22
- rspec-support (~> 3.5.0)
23
- rspec-expectations (3.5.0)
14
+ colorize (0.8.1)
15
+ diff-lcs (1.4.4)
16
+ docile (1.3.2)
17
+ json (2.3.1)
18
+ rake (13.0.1)
19
+ rspec (3.9.0)
20
+ rspec-core (~> 3.9.0)
21
+ rspec-expectations (~> 3.9.0)
22
+ rspec-mocks (~> 3.9.0)
23
+ rspec-core (3.9.2)
24
+ rspec-support (~> 3.9.3)
25
+ rspec-expectations (3.9.2)
24
26
  diff-lcs (>= 1.2.0, < 2.0)
25
- rspec-support (~> 3.5.0)
26
- rspec-mocks (3.5.0)
27
+ rspec-support (~> 3.9.0)
28
+ rspec-mocks (3.9.1)
27
29
  diff-lcs (>= 1.2.0, < 2.0)
28
- rspec-support (~> 3.5.0)
29
- rspec-support (3.5.0)
30
- simplecov (0.14.1)
31
- docile (~> 1.1.0)
32
- json (>= 1.8, < 3)
33
- simplecov-html (~> 0.10.0)
34
- simplecov-html (0.10.0)
35
- url (0.3.2)
30
+ rspec-support (~> 3.9.0)
31
+ rspec-support (3.9.3)
32
+ simplecov (0.18.5)
33
+ docile (~> 1.1)
34
+ simplecov-html (~> 0.11)
35
+ simplecov-html (0.12.2)
36
36
 
37
37
  PLATFORMS
38
38
  ruby
39
39
 
40
40
  DEPENDENCIES
41
- bundler (~> 1.3)
41
+ bundler
42
+ byebug
42
43
  codecov
43
44
  rake
44
45
  rspec
@@ -46,4 +47,4 @@ DEPENDENCIES
46
47
  smart_ioc!
47
48
 
48
49
  BUNDLED WITH
49
- 1.16.1
50
+ 1.17.2
@@ -1,4 +1,5 @@
1
1
  require 'smart_ioc/version'
2
+ require 'benchmark'
2
3
 
3
4
  module SmartIoC
4
5
  autoload :Args, 'smart_ioc/args'
@@ -29,15 +30,32 @@ module SmartIoC
29
30
  require 'smart_ioc/railtie' if defined?(Rails)
30
31
 
31
32
  class << self
33
+ def is_benchmark_mode
34
+ @benchmark_mode
35
+ end
36
+
32
37
  # @param package_name [String or Symbol] package name for bean definitions
33
38
  # @param dir [String] absolute path with bean definitions
34
39
  # @return nil
35
40
  def find_package_beans(package_name, dir)
36
- bean_locator = SmartIoC::BeanLocator.new
37
- bean_locator.locate_beans(package_name.to_sym, dir)
41
+ time = Benchmark.realtime do
42
+ bean_locator = SmartIoC::BeanLocator.new
43
+ bean_locator.locate_beans(package_name.to_sym, dir)
44
+ end
45
+
46
+ time *= 1000
47
+
48
+ if is_benchmark_mode
49
+ puts "Search finished for '#{package_name}'. Time taken: #{"%.2f ms" % time}"
50
+ end
51
+
38
52
  nil
39
53
  end
40
54
 
55
+ def benchmark_mode(flag)
56
+ @benchmark_mode = !!flag
57
+ end
58
+
41
59
  # Load all beans (usually required for production env)
42
60
  def load_all_beans
43
61
  BeanLocations.all_bean_names.each do |bean|
@@ -55,7 +73,7 @@ module SmartIoC
55
73
  Container.get_instance
56
74
  end
57
75
 
58
- [:register_bean, :get_bean_definition_by_class,
76
+ [:register_bean, :get_bean_definition,
59
77
  :set_extra_context_for_package, :get_bean, :clear_scopes,
60
78
  :force_clear_scopes, :set_load_proc].each do |name|
61
79
  define_method name do |*args, &block|
@@ -64,3 +82,5 @@ module SmartIoC
64
82
  end
65
83
  end
66
84
  end
85
+
86
+ require 'smart_ioc/bean'
@@ -1,7 +1,7 @@
1
1
  module SmartIoC::Args
2
2
  def check_arg(value, name, klass)
3
3
  if !value.is_a?(klass)
4
- raise ArgumentError, ":#{name} should be a #{klass}"
4
+ raise ArgumentError, ":#{name} should be a #{klass}. Got #{value.class}: #{value.inspect}"
5
5
  end
6
6
  end
7
7
 
@@ -0,0 +1,29 @@
1
+ def bean(bean_name, &proc)
2
+ raise ArgumentError, "name should be a Symbol" if !bean_name.is_a?(Symbol)
3
+ raise ArgumentError, "proc should be provided" if !block_given?
4
+
5
+ klass = Class.new do
6
+ include SmartIoC::Iocify
7
+ end
8
+
9
+ klass.instance_variable_set(:@anonymous_bean, true)
10
+ klass.instance_exec(&proc)
11
+
12
+ klass.instance_exec do
13
+ bean(
14
+ bean_name,
15
+ scope: instance_variable_get(:@scope) || nil,
16
+ package: instance_variable_get(:@package) || nil,
17
+ instance: instance_variable_get(:@instance) || false,
18
+ factory_method: instance_variable_get(:@factory_method) || nil,
19
+ context: instance_variable_get(:@context) || nil,
20
+ after_init: instance_variable_get(:@after_init) || nil
21
+ )
22
+ end
23
+
24
+ (klass.instance_variable_get(:@injects) || []).each do |inject|
25
+ klass.register_inject(inject[:bean_name], ref: inject[:ref], from: inject[:from])
26
+ end
27
+
28
+ klass
29
+ end
@@ -2,9 +2,9 @@ class SmartIoC::BeanDefinition
2
2
  include SmartIoC::Args
3
3
 
4
4
  attr_reader :name, :package, :path, :klass, :scope, :instance, :factory_method,
5
- :context, :dependencies
5
+ :context, :dependencies, :after_init
6
6
 
7
- def initialize(name:, package:, path:, klass:, scope:, context:, instance:, factory_method:)
7
+ def initialize(name:, package:, path:, klass:, scope:, context:, instance:, factory_method:, after_init:)
8
8
  not_nil(name, :name)
9
9
  not_nil(package, :package)
10
10
  not_nil(path, :path)
@@ -20,6 +20,7 @@ class SmartIoC::BeanDefinition
20
20
  @scope = scope
21
21
  @instance = instance
22
22
  @factory_method = factory_method
23
+ @after_init = after_init
23
24
  @context = context
24
25
 
25
26
  @dependencies = []
@@ -46,12 +47,15 @@ class SmartIoC::BeanDefinition
46
47
  end
47
48
 
48
49
  def ==(bean_definition)
49
- bean_definition.klass == @klass
50
+ bean_definition.name == @name && bean_definition.package == @package && bean_definition.context == @context
51
+ end
52
+
53
+ def singleton?
54
+ SmartIoC::Scopes::Singleton::VALUE == @scope
50
55
  end
51
56
 
52
57
  def inspect
53
58
  str = []
54
- str << "class: #{@klass}"
55
59
  str << "name: :#{@name}"
56
60
  str << "package: :#{@package}"
57
61
  str << "context: :#{@context}"
@@ -46,8 +46,16 @@ Existing bean details:
46
46
  # @param klass [Class] bean class
47
47
  # @return bean definition [BeanDefinition] or nil
48
48
  def find_by_class(klass)
49
- klass_str = klass.to_s
50
- @collection.detect {|bd| bd.klass.to_s == klass_str}
49
+ @collection.detect {|bd| bd.klass == klass}
50
+ end
51
+
52
+ # Returns bean definition for specific class
53
+ # @param bean_name [Symbol]
54
+ # @param package [Symbol]
55
+ # @param context [Symbol]
56
+ # @return bean definition [BeanDefinition] or nil
57
+ def find_bean(bean_name, package, context)
58
+ @collection.detect {|bd| bd.name == bean_name && bd.package == package && bd.context == context}
51
59
  end
52
60
 
53
61
  def filter_by(bean_name, package = nil, context = nil)
@@ -73,10 +81,21 @@ Existing bean details:
73
81
  # @bean_name [Symbol] bean name
74
82
  # @package [Symbol, nil] package name
75
83
  # @context [Symbol, nil] context
84
+ # @package [Symbol, nil] parent_package name of parent package
76
85
  # @raises AmbiguousBeanDefinition if multiple bean definitions are found
77
- def find(bean_name, package = nil, context = nil)
86
+ def find(bean_name, package = nil, context = nil, parent_package = nil)
78
87
  bds = filter_by_with_drop_to_default_context(bean_name, package, context)
79
88
 
89
+ if bds.size > 1 && parent_package
90
+ bean_definition = bds.detect do |bd|
91
+ bd.package == parent_package
92
+ end
93
+
94
+ if bean_definition
95
+ bds = [bean_definition]
96
+ end
97
+ end
98
+
80
99
  if bds.size > 1
81
100
  raise AmbiguousBeanDefinition.new(bean_name, bds)
82
101
  elsif bds.size == 0
@@ -1,5 +1,3 @@
1
- require 'thread'
2
-
3
1
  # Instantiates beans according to their scopes
4
2
  class SmartIoC::BeanFactory
5
3
  include SmartIoC::Errors
@@ -28,142 +26,68 @@ class SmartIoC::BeanFactory
28
26
  # Get bean from the container by it's name, package, context
29
27
  # @param bean_name [Symbol] bean name
30
28
  # @param package [Symbol] package name
29
+ # @param parent_bean_definition [SmartIoC::BeanDefinition] parent bean definition
31
30
  # @param context [Symbol] context
32
31
  # @return bean instance
33
32
  # @raise [ArgumentError] if bean is not found
34
33
  # @raise [ArgumentError] if ambiguous bean definition was found
35
- def get_bean(bean_name, package: nil, context: nil)
34
+ def get_bean(bean_name, package: nil, parent_bean_definition: nil, context: nil, parent_bean_name: nil)
36
35
  check_arg(bean_name, :bean_name, Symbol)
37
36
  check_arg(package, :package, Symbol) if package
37
+ check_arg(parent_bean_definition, :parent_bean_definition, SmartIoC::BeanDefinition) if parent_bean_definition
38
38
  check_arg(context, :context, Symbol) if context
39
39
 
40
- @semaphore.synchronize do
41
- result = get_or_build_bean(bean_name, package, context)
42
- end
43
- end
44
-
45
- private
46
-
47
- def get_or_build_bean(bean_name, package, context, history = Set.new)
48
40
  @bean_file_loader.require_bean(bean_name)
49
41
 
50
- context = autodetect_context(bean_name, package, context)
51
- bean_definition = @bean_definitions_storage.find(bean_name, package, context)
52
- scope = get_scope(bean_definition)
53
- scope_bean = scope.get_bean(bean_definition.klass)
54
- is_recursive = history.include?(bean_name)
55
-
56
- history << bean_name
57
-
58
- if scope_bean && scope_bean.loaded
59
- update_dependencies(scope_bean.bean, bean_definition)
60
- scope_bean.bean
61
- else
62
- if is_recursive
63
- raise LoadRecursion.new(bean_definition)
64
- end
65
-
66
- beans_cache = init_bean_definition_cache(bean_definition)
42
+ parent_package_name = parent_bean_definition ? parent_bean_definition.package : nil
43
+ context = autodetect_context(bean_name, package, parent_package_name, context, parent_bean_name)
44
+ bean_definition = @bean_definitions_storage.find(bean_name, package, context, parent_package_name)
45
+ scope = get_scope(bean_definition)
46
+ bean = scope.get_bean(bean_definition.klass)
67
47
 
68
- autodetect_bean_definitions_for_dependencies(bean_definition)
69
- preload_beans(bean_definition, beans_cache[bean_definition])
70
- load_bean(bean_definition, beans_cache)
48
+ if !bean
49
+ bean = init_bean(bean_definition)
71
50
  end
72
- end
73
51
 
74
- def load_bean(bean_definition, beans_cache)
75
- bd_opts = beans_cache[bean_definition]
76
- scope_bean = bd_opts[:scope_bean]
52
+ scope.save_bean(bean_definition.klass, bean)
53
+ bean
54
+ rescue SmartIoC::Errors::AmbiguousBeanDefinition => e
55
+ e.parent_bean_definition = parent_bean_definition
56
+ raise e
57
+ end
77
58
 
78
- bean_definition.dependencies.each do |dependency|
79
- bd = dependency.bean_definition
80
- dep_db_opts = bd_opts[:dependencies][dependency.bean_definition]
81
- dep_scope_bean = dep_db_opts[:scope_bean]
82
- dep_bean = load_bean(bd, bd_opts[:dependencies])
59
+ private
83
60
 
84
- scope_bean.bean.instance_variable_set(:"@#{dependency.bean}", dep_bean)
61
+ def init_bean(bean_definition)
62
+ bean = if bean_definition.is_instance?
63
+ bean_definition.klass.allocate
64
+ else
65
+ bean_definition.klass
85
66
  end
86
67
 
87
- if !scope_bean.loaded
88
- scope_bean.set_bean(scope_bean.bean.send(bean_definition.factory_method), true)
68
+ if bean_definition.has_factory_method?
69
+ bean = bean.send(bean_definition.factory_method)
89
70
  end
90
71
 
91
- scope_bean.bean
92
- end
93
-
94
- def inject_beans(bean_definition, beans_cache)
95
- bean = beans_cache[:scope_bean].bean
96
- bean_definition.dependencies.each do |dependency|
97
- bd = dependency.bean_definition
98
- dep_bean = beans_cache[:dependencies][bd][:scope_bean].bean
99
- bean.instance_variable_set(:"@#{dependency.bean}", dep_bean)
100
- inject_beans(bd, beans_cache[:dependencies][bd])
72
+ if bean_definition.after_init
73
+ bean.send(bean_definition.after_init)
101
74
  end
102
- end
103
-
104
- def init_bean_definition_cache(bean_definition)
105
- {
106
- bean_definition => {
107
- scope_bean: nil,
108
- dependencies: {
109
- }
110
- }
111
- }
112
- end
113
-
114
- def update_dependencies(bean, bean_definition, updated_beans = {})
115
- bean_definition.dependencies.each do |dependency|
116
- bd = autodetect_bean_definition(
117
- dependency.ref, dependency.package, bean_definition.package
118
- )
119
-
120
- scope = get_scope(bean_definition)
121
- dep_bean = updated_beans[bd]
122
-
123
- if !dep_bean && scope_bean = scope.get_bean(bd.klass)
124
- dep_bean = scope_bean.bean
125
- end
126
-
127
- if !dep_bean
128
- dep_bean = get_or_build_bean(bd.name, bd.package, bd.context)
129
75
 
130
- bean.instance_variable_set(:"@#{dependency.bean}", dep_bean)
131
-
132
- if !scope.is_a?(SmartIoC::Scopes::Prototype)
133
- updated_beans[bd] = dep_bean
134
- end
135
- else
136
- update_dependencies(dep_bean, bd, updated_beans)
137
- end
138
- end
76
+ bean
139
77
  end
140
78
 
141
- def autodetect_context(bean_name, package, context)
79
+ def autodetect_context(bean_name, package, parent_bean_package, context, parent_bean_name)
142
80
  return context if context
143
81
 
144
82
  if package
145
83
  @extra_package_contexts.get_context(package)
146
84
  else
147
- bean_definition = autodetect_bean_definition(bean_name, package, nil)
148
- bean_definition.context
149
- end
150
- end
151
-
152
- def autodetect_bean_definitions_for_dependencies(bean_definition)
153
- bean_definition.dependencies.each do |dependency|
154
- next if dependency.bean_definition
155
-
156
- @bean_file_loader.require_bean(dependency.ref)
157
-
158
- dependency.bean_definition = autodetect_bean_definition(
159
- dependency.ref, dependency.package, bean_definition.package
160
- )
161
-
162
- autodetect_bean_definitions_for_dependencies(dependency.bean_definition)
85
+ bean_definition = autodetect_bean_definition(bean_name, package, parent_bean_package, parent_bean_name)
86
+ @extra_package_contexts.get_context(bean_definition.package)
163
87
  end
164
88
  end
165
89
 
166
- def autodetect_bean_definition(bean, package, parent_bean_package)
90
+ def autodetect_bean_definition(bean, package, parent_bean_package, parent_bean_name)
167
91
  if package
168
92
  bean_context = @extra_package_contexts.get_context(package)
169
93
  bds = @bean_definitions_storage.filter_by_with_drop_to_default_context(bean, package, bean_context)
@@ -196,7 +120,15 @@ class SmartIoC::BeanFactory
196
120
  end
197
121
 
198
122
  if smart_bds.size > 1
199
- raise ArgumentError, "Unable to autodetect bean :#{bean}.\nSeveral definitions were found.\n#{smart_bds.map(&:inspect).join("\n\n")}. Set package directly for injected dependency"
123
+ require 'byebug'
124
+ debugger
125
+ raise ArgumentError.new(
126
+ %Q(Unable to autodetect bean :#{bean}#{parent_bean_name ? " for bean :#{parent_bean_name}" : ''}.
127
+ Several definitions were found:\n
128
+ #{smart_bds.map(&:inspect).join("\n\n")}.
129
+ Set package directly for injected dependency
130
+ )
131
+ )
200
132
  end
201
133
 
202
134
  if smart_bds.size == 0
@@ -206,77 +138,6 @@ class SmartIoC::BeanFactory
206
138
  return smart_bds.first
207
139
  end
208
140
 
209
- def preload_beans(bean_definition, beans_cache)
210
- scope = get_scope(bean_definition)
211
-
212
- if scope_bean = scope.get_bean(bean_definition.klass)
213
- beans_cache[:scope_bean] = scope_bean
214
- else
215
- preload_bean_instance(bean_definition, beans_cache)
216
- end
217
-
218
- bean_definition.dependencies.each do |dependency|
219
- bd = dependency.bean_definition
220
-
221
- next if beans_cache[:dependencies].has_key?(bd)
222
-
223
- dep_bean_cache = init_bean_definition_cache(bd)
224
- beans_cache[:dependencies].merge!(dep_bean_cache)
225
- preload_beans(bd, dep_bean_cache[bd])
226
- end
227
- end
228
-
229
- def preload_bean_instance(bean_definition, beans_cache)
230
- return if beans_cache[:scope_bean]
231
-
232
- scope = get_scope(bean_definition)
233
- scope_bean = scope.get_bean(bean_definition.klass)
234
-
235
- if scope_bean
236
- beans_cache[:scope_bean] = scope_bean
237
- return scope_bean
238
- end
239
-
240
- bean = if bean_definition.is_instance?
241
- bean_definition.klass.allocate
242
- else
243
- bean_definition.klass
244
- end
245
-
246
- scope_bean = SmartIoC::Scopes::Bean.new(bean, !bean_definition.has_factory_method?)
247
-
248
- scope.save_bean(bean_definition.klass, scope_bean)
249
- beans_cache[:scope_bean] = scope_bean
250
-
251
- scope_bean
252
- end
253
-
254
- def init_factory_bean(bean_definition, bd_opts)
255
- scope_bean = bd_opts[:scope_bean]
256
-
257
- if !scope_bean.loaded
258
- scope_bean.set_bean(scope_bean.bean.send(bean_definition.factory_method), true)
259
- end
260
- end
261
-
262
- def get_cross_refference(refer_bean_definitions, current_bean_definition, seen_bean_definitions = [])
263
- current_bean_definition.dependencies.each do |dependency|
264
- bd = dependency.bean_definition
265
-
266
- next if seen_bean_definitions.include?(bd)
267
-
268
- if refer_bean_definitions.include?(bd)
269
- return bd
270
- end
271
-
272
- if crbd = get_cross_refference(refer_bean_definitions, bd, seen_bean_definitions + [bd])
273
- return crbd
274
- end
275
- end
276
-
277
- nil
278
- end
279
-
280
141
  def all_scopes
281
142
  [@singleton_scope, @prototype_scope, @thread_scope]
282
143
  end