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.
@@ -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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module SmartCore::Injection::Injector::Strategies
6
+ require_relative 'strategies/method_injection'
7
+ 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