smart_ioc 0.2.4 → 0.3.5

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