smart_injection 0.0.0.alpha
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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +19 -0
- data/.travis.yml +23 -0
- data/CHANGELOG.md +2 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +104 -0
- data/LICENSE.txt +21 -0
- data/README.md +122 -0
- data/Rakefile +21 -0
- data/bin/console +8 -0
- data/bin/setup +8 -0
- data/lib/smart_core/injection.rb +43 -0
- data/lib/smart_core/injection/dsl.rb +87 -0
- data/lib/smart_core/injection/errors.rb +11 -0
- data/lib/smart_core/injection/injector.rb +143 -0
- data/lib/smart_core/injection/injector/container_set.rb +86 -0
- data/lib/smart_core/injection/injector/injection_settings.rb +173 -0
- data/lib/smart_core/injection/injector/injection_settings/incompatability_control.rb +113 -0
- data/lib/smart_core/injection/injector/modulizer.rb +55 -0
- data/lib/smart_core/injection/injector/strategies.rb +7 -0
- data/lib/smart_core/injection/injector/strategies/method_injection.rb +92 -0
- data/lib/smart_core/injection/locator.rb +59 -0
- data/lib/smart_core/injection/locator/container_proxy.rb +73 -0
- data/lib/smart_core/injection/locator/dependency.rb +54 -0
- data/lib/smart_core/injection/locator/factory.rb +53 -0
- data/lib/smart_core/injection/version.rb +11 -0
- data/smart_injection.gemspec +42 -0
- metadata +187 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
module SmartCore::Injection::Injector::InjectionSettings::IncompatabilityControl
|
6
|
+
class << self
|
7
|
+
# @param injectable [Class, Module]
|
8
|
+
# @param imports [Hash<String|Symbol,String>]
|
9
|
+
# @param memoize [Boolean]
|
10
|
+
# @param access [Symbol]
|
11
|
+
# @param bind [Symbol]
|
12
|
+
# @param from [NilClass, SmartCore::Container]
|
13
|
+
# @return [void]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
# @since 0.1.0
|
17
|
+
def prevent_incompatabilities!(injectable, imports, memoize, access, bind, from)
|
18
|
+
prevent_injectable_incompatabilities!(injectable)
|
19
|
+
prevent_imports_incompatabilites!(imports)
|
20
|
+
prevent_memoize_incompatabilites(memoize)
|
21
|
+
prevent_access_incompatabilites(access)
|
22
|
+
prevent_bind_incompatabilites(bind)
|
23
|
+
prevent_from_incompatabilites(from)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# @param injectable [Class, Module]
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.1.0
|
33
|
+
def prevent_injectable_incompatabilities!(injectable)
|
34
|
+
unless injectable.is_a?(Class) || injectable.is_a?(Module)
|
35
|
+
raise(SmartCore::Injection::ArgumentError, <<~ERROR_MESSAGE)
|
36
|
+
ERROR_MESSAGE
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param imports [Hash<String|Symbol,String>]
|
41
|
+
# @return [void]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
# @since 0.1.0
|
45
|
+
def prevent_imports_incompatabilites!(imports)
|
46
|
+
unless imports.is_a?(::Hash)
|
47
|
+
raise(SmartCore::Injection::ArgumentError, <<~ERROR_MESSAGE)
|
48
|
+
Incorrect import list (should be a type of Hash)
|
49
|
+
ERROR_MESSAGE
|
50
|
+
end
|
51
|
+
|
52
|
+
unless imports.keys.all? { |key| key.is_a?(String) || key.is_a?(Symbol) }
|
53
|
+
raise(SmartCore::Injection::ArgumentError, <<~ERROR_MESSAGE)
|
54
|
+
Some method aliases are incorret (they should be a type of String or Symbol)
|
55
|
+
ERROR_MESSAGE
|
56
|
+
end
|
57
|
+
|
58
|
+
unless imports.values.all? { |value| value.is_a?(String) }
|
59
|
+
raise(SmartCore::Injection::ArgumentError, <<~ERROR_MESSAGE)
|
60
|
+
Some injection pathes are incorrect (they should be a type of String)
|
61
|
+
ERROR_MESSAGE
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# @param memoize [Boolean]
|
66
|
+
# @return [void]
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
# @since 0.1.0
|
70
|
+
def prevent_memoize_incompatabilites(memoize)
|
71
|
+
unless memoize.is_a?(::TrueClass) || memoize.is_a?(::FalseClass)
|
72
|
+
raise(SmartCore::Injection::ArgumentError, <<~ERROR_MESSAGE)
|
73
|
+
ERROR_MESSAGE
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# @param access [Symbol]
|
78
|
+
# @return [void]
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
# @since 0.1.0
|
82
|
+
def prevent_access_incompatabilites(access)
|
83
|
+
unless SmartCore::Injection::Injector::InjectionSettings::ACCESS_MARKS.include?(access)
|
84
|
+
raise(SmartCore::Injection::ArgumentError, <<~ERROR_MESSAGE)
|
85
|
+
ERROR_MESSAGE
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# @param bind [Symbol]
|
90
|
+
# @return [void]
|
91
|
+
#
|
92
|
+
# @api private
|
93
|
+
# @since 0.1.0
|
94
|
+
def prevent_bind_incompatabilites(bind)
|
95
|
+
unless SmartCore::Injection::Injector::InjectionSettings::BINDING_STRATEGIES.include?(bind)
|
96
|
+
raise(SmartCore::Injection::ArgumentError, <<~ERROR_MESSAGE)
|
97
|
+
ERROR_MESSAGE
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# @param from [NilClass, SmartCore::Container]
|
102
|
+
# @return [void]
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
# @since 0.1.0
|
106
|
+
def prevent_from_incompatabilites(from)
|
107
|
+
unless from.is_a?(NilClass) || from.is_a?(SmartCore::Container)
|
108
|
+
raise(SmartCore::Injection::ArgumentError, <<~ERROR_MESSAGE)
|
109
|
+
ERROR_MESSAGE
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
module SmartCore::Injection::Injector::Modulizer
|
6
|
+
class << self
|
7
|
+
# @param containers [Array<SmartCore::Container>]
|
8
|
+
# @return [Module]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
# @since 0.1.0
|
12
|
+
def with_containers(containers)
|
13
|
+
prevent_inconsistency!(containers)
|
14
|
+
build_container_injectable_module(containers)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param base_klass [Class, Module]
|
18
|
+
# @return [void]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
# @since 0.1.0
|
22
|
+
def inject_to(base_klass)
|
23
|
+
base_klass.include(::SmartCore::Injection::DSL)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# @param containers [Array<SmartCore::Container>]
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.1.0
|
33
|
+
def prevent_inconsistency!(containers)
|
34
|
+
unless containers.is_a?(Array) && containers.all? { |cont| cont.is_a?(SmartCore::Container) }
|
35
|
+
raise(SmartCore::Injection::ArgumentError, <<~ERROR_MESSAGE)
|
36
|
+
Injectable containers should be a type of SmartCore::Container
|
37
|
+
ERROR_MESSAGE
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param containers [Array<SmartCore::Container>]
|
42
|
+
# @return [Module]
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
# @since 0.1.0
|
46
|
+
def build_container_injectable_module(containers)
|
47
|
+
Module.new do
|
48
|
+
define_singleton_method :included do |base_klass|
|
49
|
+
base_klass.include(::SmartCore::Injection::DSL)
|
50
|
+
base_klass.register_container(*containers)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
module SmartCore::Injection::Injector::Strategies::MethodInjection
|
6
|
+
class << self
|
7
|
+
# @param injection_settings [SmartCore::Injection::Injector::InjectionSettings]
|
8
|
+
# @return [void]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
# @since 0.1.0
|
12
|
+
def inject_instance_method(injection_settings)
|
13
|
+
inject_dependency(injection_settings, injection_settings.instance_level_injectable)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param injection_settings [SmartCore::Injection::Injector::InjectionSettings]
|
17
|
+
# @return [void]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
# @since 0.1.0
|
21
|
+
def inject_class_method(injection_settings)
|
22
|
+
inject_dependency(injection_settings, injection_settings.class_level_injectable)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# @param injection_settings [SmartCore::Injection::Injector::InjectionSettings]
|
28
|
+
# @param injectable [Class, Module]
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.1.0
|
33
|
+
def inject_dependency(injection_settings, injectable)
|
34
|
+
injection_settings.each_import do |import_key, import_path|
|
35
|
+
locator = build_locator(injection_settings, import_key, import_path)
|
36
|
+
process_injection_bindings(injection_settings, locator)
|
37
|
+
injection = build_injection(injection_settings, import_key, locator)
|
38
|
+
inject_injection(injection_settings, injection, injectable)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param injection_settings [SmartCore::Injection::Injector::InjectionSettings]
|
43
|
+
# @param import_key [String, Symbol]
|
44
|
+
# @param import_path [String]
|
45
|
+
# @return [SmartCore::Injection::Locator]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
# @since 0.1.0
|
49
|
+
def build_locator(injection_settings, import_key, import_path)
|
50
|
+
SmartCore::Injection::Locator::Factory.create(injection_settings, import_key, import_path)
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param locator [SmartCore::Injection::Locator]
|
54
|
+
# @return [void]
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
# @since 0.1.0
|
58
|
+
def process_injection_bindings(injection_settings, locator)
|
59
|
+
locator.bind! if injection_settings.bind_static?
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param injection_settings [SmartCore::Injection::Injector::InjectionSettings]
|
63
|
+
# @param import_key [String, Symbol]
|
64
|
+
# @param locator [SmartCore::Injection::Locator]
|
65
|
+
# @return [Module]
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
# @since 0.1.0
|
69
|
+
def build_injection(injection_settings, import_key, locator)
|
70
|
+
Module.new do
|
71
|
+
define_method(import_key) { locator.resolve_dependency }
|
72
|
+
|
73
|
+
case injection_settings.access
|
74
|
+
when :public then public(import_key)
|
75
|
+
when :private then private(import_key)
|
76
|
+
when :protected then protected(import_key)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param injection_settings [SmartCore::Injection::Injector::InjectionSettings]
|
82
|
+
# @param injection [Module]
|
83
|
+
# @param injectable [Class, Module]
|
84
|
+
# @return [void]
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
# @since 0.1.0
|
88
|
+
def inject_injection(injection_settings, injection, injectable)
|
89
|
+
injectable.include(injection)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Injection::Locator
|
6
|
+
require_relative 'locator/container_proxy'
|
7
|
+
require_relative 'locator/dependency'
|
8
|
+
require_relative 'locator/factory'
|
9
|
+
|
10
|
+
# @return [String]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
# @since 0.1.0
|
14
|
+
attr_reader :import_path
|
15
|
+
|
16
|
+
# @param import_path [String]
|
17
|
+
# @param container_proxy [SmartCore::Injection::Locator::ContainerProxy]
|
18
|
+
# @return [void]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
# @since 0.1.0
|
22
|
+
def initialize(import_path, container_proxy)
|
23
|
+
@import_path = import_path
|
24
|
+
@container_proxy = container_proxy
|
25
|
+
@dependency = SmartCore::Injection::Locator::Dependency.new
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Any]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
# @since 0.1.0
|
32
|
+
def resolve_dependency
|
33
|
+
dependency.bind { container_proxy.resolve_dependency(import_path) }
|
34
|
+
end
|
35
|
+
alias_method :bind!, :resolve_dependency
|
36
|
+
|
37
|
+
# @return [Any]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
# @since 0.1.0
|
41
|
+
def rebind_dependency
|
42
|
+
dependency.rebind { container_proxy.resolve(import_path) }
|
43
|
+
end
|
44
|
+
alias_method :rebind!, :rebind_dependency
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# @return [SmartCore::Injection::Locator::Dependency]
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
# @since 0.1.0
|
52
|
+
attr_reader :dependency
|
53
|
+
|
54
|
+
# @return [SmartCore::Injection::Locator::ContainerProxy]
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
# @since 0.1.0
|
58
|
+
attr_reader :container_proxy
|
59
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Injection::Locator::ContainerProxy
|
6
|
+
# @param registered_containers [SmartCore::Injection::Injector::ContainerSet]
|
7
|
+
# @param explicitly_passed_container [NilClass, SmartCore::Container]
|
8
|
+
# @return [void]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
# @since 0.1.0
|
12
|
+
def initialize(registered_containers, explicitly_passed_container)
|
13
|
+
@registered_containers = registered_containers
|
14
|
+
@explicitly_passed_container = explicitly_passed_container
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param dependency_path [String]
|
18
|
+
# @return [Any]
|
19
|
+
#
|
20
|
+
# @raise [SmartCore::Container::ResolvingError]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
# @since 0.1.0
|
24
|
+
def resolve_dependency(dependency_path)
|
25
|
+
resolving_error = nil
|
26
|
+
|
27
|
+
each_container do |container|
|
28
|
+
begin # rubocop:disable Style/RedundantBegin
|
29
|
+
return container.resolve(dependency_path)
|
30
|
+
rescue SmartCore::Container::ResolvingError => error
|
31
|
+
resolving_error = error
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
raise(resolving_error)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param import_path [String]
|
39
|
+
# @param observer [Block]
|
40
|
+
# @return [void]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
# @since 0.1.0
|
44
|
+
def observe(import_path, &observer)
|
45
|
+
# TODO: implement
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# @return [SmartCore::Injection::Injector::ContainerSet]
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
# @since 0.1.0
|
54
|
+
attr_reader :registered_containers
|
55
|
+
|
56
|
+
# @return [NilClass, SmartCore::Container]
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
# @since 0.1.0
|
60
|
+
attr_reader :explicitly_passed_container
|
61
|
+
|
62
|
+
# @param block [Block]
|
63
|
+
# @yield [container]
|
64
|
+
# @yieldparam container [SmartCore::Container]
|
65
|
+
# @return [void]
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
# @since 0.1.0
|
69
|
+
def each_container(&block)
|
70
|
+
yield(explicitly_passed_container) if explicitly_passed_container
|
71
|
+
registered_containers.reverse_each(&block)
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Injection::Locator::Dependency
|
6
|
+
# @return [void]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.1.0
|
10
|
+
def initialize
|
11
|
+
@binded = false
|
12
|
+
@value = nil
|
13
|
+
@barrier = SmartCore::Engine::Lock.new
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param block [Block]
|
17
|
+
# @return [Any]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
# @since 0.1.0
|
21
|
+
def rebind(&block)
|
22
|
+
with_barrier do
|
23
|
+
@bind = false
|
24
|
+
bind(&block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param block [Block]
|
29
|
+
# @return [Any]
|
30
|
+
#
|
31
|
+
# @api public
|
32
|
+
# @since 0.7.0
|
33
|
+
def bind(&block)
|
34
|
+
with_barrier do
|
35
|
+
if @binded
|
36
|
+
@value
|
37
|
+
else
|
38
|
+
@binded = true
|
39
|
+
@value = yield(@value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# @param block [Block]
|
47
|
+
# @return [Any]
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
# @since 0.1.0
|
51
|
+
def with_barrier(&block)
|
52
|
+
@barrier.synchronize(&block)
|
53
|
+
end
|
54
|
+
end
|