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,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'smart_core/container'
4
+ require 'set'
5
+
6
+ # @api public
7
+ # @since 0.1.0
8
+ module SmartCore
9
+ # TODO: обязательно учесть наследование
10
+
11
+ class << self
12
+ # @param containers [Array<SmartCore::Container>]
13
+ # @return [Module]
14
+ #
15
+ # @api public
16
+ # @since 0.1.0
17
+ # rubocop:disable Naming/MethodName
18
+ def Injection(*containers)
19
+ ::SmartCore::Injection::Injector::Modulizer.with_containers(containers)
20
+ end
21
+ # rubocop:enable Naming/MethodName
22
+ end
23
+
24
+ # @api public
25
+ # @since 0.1.0
26
+ module Injection
27
+ require_relative 'injection/version'
28
+ require_relative 'injection/injector'
29
+ require_relative 'injection/locator'
30
+ require_relative 'injection/dsl'
31
+
32
+ class << self
33
+ # @param base_klass [Class, Module]
34
+ # @return [void]
35
+ #
36
+ # @api private
37
+ # @since 0.1.0
38
+ def included(base_klass)
39
+ ::SmartCore::Injection::Injector::Modulizer.inject_to(base_klass)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ module SmartCore::Injection::DSL
6
+ class << self
7
+ # @param base_klass [Class, Module]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def included(base_klass)
13
+ base_klass.instance_variable_set(
14
+ :@__smart_injection_injector__,
15
+ SmartCore::Injection::Injector.new(base_klass)
16
+ )
17
+ base_klass.extend(ClassMethods)
18
+ end
19
+ end
20
+
21
+ # @api private
22
+ # @since 0.1.0
23
+ module ClassMethods
24
+ # @param imports [Hash<String|Symbol,String>]
25
+ # @option memoize [Boolean]
26
+ # @option access [Symbol]
27
+ # @option bind [Symbol]
28
+ # @option from [NilClass, SmartCore::Container]
29
+ # @return [void]
30
+ #
31
+ # @api public
32
+ # @sincd 0.1.0
33
+ def import(
34
+ imports,
35
+ memoize: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_MEMOIZE,
36
+ access: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_ACCESS,
37
+ bind: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_BINDING_STRATEGY,
38
+ from: SmartCore::Injection::Injector::InjectionSettings::EMPTY_CONTAINER_DESTINATION
39
+ )
40
+ __smart_injection_injector__.inject(imports, memoize, access, bind, from)
41
+ end
42
+
43
+ # @param imports [Hash<String|Symbol,String>]
44
+ # @option memoize [Boolean]
45
+ # @option access [Symbol]
46
+ # @option bind [Symbol]
47
+ # @option from [NilClass, SmartCore::Container]
48
+ # @return [void]
49
+ #
50
+ # @api public
51
+ # @sincd 0.1.0
52
+ def import_static(
53
+ imports,
54
+ memoize: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_MEMOIZE,
55
+ access: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_ACCESS,
56
+ bind: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_BINDING_STRATEGY,
57
+ from: SmartCore::Injection::Injector::InjectionSettings::EMPTY_CONTAINER_DESTINATION
58
+ )
59
+ __smart_injection_injector__.inject_static(imports, memoize, access, bind, from)
60
+ end
61
+
62
+ # @param containers [Array<SmartCore::Container>]
63
+ # @return [void]
64
+ #
65
+ # @api public
66
+ # @since 0.1.0
67
+ def register_container(*containers)
68
+ __smart_injection_injector__.register_container(containers)
69
+ end
70
+
71
+ # @return [Array<SmartCore::Container>]
72
+ #
73
+ # @api public
74
+ # @since 0.1.0
75
+ def linked_containers
76
+ __smart_injection_injector__.associated_containers
77
+ end
78
+
79
+ private
80
+
81
+ # @return [SmartCore::Injection::Injector]
82
+ #
83
+ # @api private
84
+ # @since 0.1.0
85
+ attr_reader :__smart_injection_injector__
86
+ end
87
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartCore::Injection
4
+ # @api public
5
+ # @since 0.1.0
6
+ Error = Class.new(SmartCore::Error)
7
+
8
+ # @api public
9
+ # @since 0.1.0
10
+ ArgumentError = Class.new(SmartCore::ArgumentError)
11
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Injection::Injector
6
+ require_relative 'injector/container_set'
7
+ require_relative 'injector/injection_settings'
8
+ require_relative 'injector/modulizer'
9
+ require_relative 'injector/strategies'
10
+
11
+ # @param injectable [Class, Module]
12
+ # @return [void]
13
+ #
14
+ # @api private
15
+ # @since 0.1.0
16
+ def initialize(injectable)
17
+ @injectable = injectable
18
+ @linked_containers = SmartCore::Injection::Injector::ContainerSet.new
19
+ @access_lock = SmartCore::Engine::Lock.new
20
+ end
21
+
22
+ # @param imports [Hash<String|Symbol,String>]
23
+ # @param memoize [Boolean]
24
+ # @param access [Symbol]
25
+ # @param bind [Symbol]
26
+ # @param from [NilClass, SmartCore::Container]
27
+ # @return [void]
28
+ #
29
+ # @api private
30
+ # @since 0.1.0
31
+ def inject(imports, memoize, access, bind, from)
32
+ thread_safe { inject_instance_method(imports, memoize, access, bind, from) }
33
+ end
34
+
35
+ # @param imports [Hash<String|Symbol,String>]
36
+ # @param memoize [Boolean]
37
+ # @param access [Symbol]
38
+ # @param bind [Symbol]
39
+ # @param from [NilClass, SmartCore::Container]
40
+ # @return [void]
41
+ #
42
+ # @api private
43
+ # @since 0.1.0
44
+ def inject_static(imports, memoize, access, bind, from)
45
+ thread_safe { inject_class_method(imports, memoize, access, bind, from) }
46
+ end
47
+
48
+ # @param containers [Array<SmartCore::Container>]
49
+ # @return [void]
50
+ #
51
+ # @api private
52
+ # @since 0.1.0
53
+ def register_container(containers)
54
+ thread_safe { link_container(containers) }
55
+ end
56
+
57
+ # @return [Array<SmartCore::Container>]
58
+ #
59
+ # @api private
60
+ # @since 0.1.0
61
+ def associated_containers
62
+ thread_safe { linked_containers.list }
63
+ end
64
+
65
+ private
66
+
67
+ # @return [Class, Module]
68
+ #
69
+ # @api private
70
+ # @since 0.1.0
71
+ attr_reader :injectable
72
+
73
+ # @return [Array<SmartCore::Container>]
74
+ #
75
+ # @api private
76
+ # @since 0.1.0
77
+ attr_reader :linked_containers
78
+
79
+ # @param imports [Hash<String|Symbol,String>]
80
+ # @param memoize [Boolean]
81
+ # @param access [Symbol]
82
+ # @param bind [Symbol]
83
+ # @param from [NilClass, SmartCore::Container]
84
+ # @return [void]
85
+ #
86
+ # @api private
87
+ # @since 0.1.0
88
+ def inject_instance_method(imports, memoize, access, bind, from)
89
+ SmartCore::Injection::Injector::Strategies::MethodInjection.inject_instance_method(
90
+ SmartCore::Injection::Injector::InjectionSettings.new(
91
+ injectable,
92
+ linked_containers,
93
+ imports,
94
+ memoize: memoize,
95
+ access: access,
96
+ bind: bind,
97
+ from: from
98
+ )
99
+ )
100
+ end
101
+
102
+ # @param imports [Hash<String|Symbol,String>]
103
+ # @param memoize [Boolean]
104
+ # @param access [Symbol]
105
+ # @param bind [Symbol]
106
+ # @param from [NilClass, SmartCore::Container]
107
+ # @return [void]
108
+ #
109
+ # @api private
110
+ # @since 0.1.0
111
+ def inject_class_method(imports, memoize, access, bind, from)
112
+ SmartCore::Injection::Injector::Strategies::MethodInjection.inject_class_method(
113
+ SmartCore::Injection::Injector::InjectionSettings.new(
114
+ injectable,
115
+ linked_containers,
116
+ imports,
117
+ memoize: memoize,
118
+ access: access,
119
+ bind: bind,
120
+ from: from
121
+ )
122
+ )
123
+ end
124
+
125
+ # @param containers [Array<SmartCore::Container>]
126
+ # @return [void]
127
+ #
128
+ # @api private
129
+ # @since 0.1.0
130
+ def link_container(containers)
131
+ containers.each do |container|
132
+ linked_containers.add(container)
133
+ end
134
+ end
135
+
136
+ # @return [Any]
137
+ #
138
+ # @api private
139
+ # @since 0.1.0
140
+ def thread_safe(&block)
141
+ @access_lock.synchronize(&block)
142
+ end
143
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Injection::Injector::ContainerSet
6
+ # @since 0.1.0
7
+ include Enumerable
8
+
9
+ # @return [void]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ def initialize
14
+ @containers = [] # NOTE: we use Array cuz we need an ordered set
15
+ @access_lock = SmartCore::Engine::Lock.new
16
+ end
17
+
18
+ # @param container [SmartCore::Container]
19
+ # @return [void]
20
+ #
21
+ # @api private
22
+ # @since 0.1.0
23
+ def add(container)
24
+ thread_safe { append_container(container) }
25
+ end
26
+ alias_method :<<, :add
27
+
28
+ # @param block [Block]
29
+ # @yield [container]
30
+ # @yieldparam container [SmartCore::Container]
31
+ # @return [Enumerator]
32
+ #
33
+ # @api private
34
+ # @since 0.1.0
35
+ def each(&block)
36
+ thread_safe { block_given? ? containers.each(&block) : containers.each }
37
+ end
38
+
39
+ # @param block [Block]
40
+ # @yield [container]
41
+ # @yieldparam container [SmartCore::Container]
42
+ # @return [Enumerator]
43
+ #
44
+ # @api private
45
+ # @since 0.1.0
46
+ def reverse_each(&block)
47
+ thread_safe { block_given? ? containers.reverse_each(&block) : containers.reverse_each }
48
+ end
49
+
50
+ # @return [Array<SmartCore::Container>]
51
+ #
52
+ # @api private
53
+ # @since 0.1.0
54
+ def list
55
+ thread_safe { containers.dup }
56
+ end
57
+
58
+ private
59
+
60
+ # @return [Array<SmartCore::Container>]
61
+ #
62
+ # @api private
63
+ # @since 0.1.0
64
+ attr_reader :containers
65
+
66
+ # @param container [SmartCore::Container]
67
+ # @return [void]
68
+ #
69
+ # @api private
70
+ # @since 0.1.0
71
+ def append_container(container)
72
+ # NOTE:
73
+ # - #concant is used to prevent container duplications in ordered set;
74
+ # - @containers should have an ordered unified container list;
75
+ containers.concat([container])
76
+ end
77
+
78
+ # @param block [Block]
79
+ # @return [Any]
80
+ #
81
+ # @api private
82
+ # @since 0.1.0
83
+ def thread_safe(&block)
84
+ @access_lock.synchronize(&block)
85
+ end
86
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Injection::Injector::InjectionSettings
6
+ require_relative 'injection_settings/incompatability_control'
7
+
8
+ # @return [Hash<String|Symbol,String>]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ DEFAULT_IMPORTS = {}.freeze
13
+
14
+ # @return [Symbol]
15
+ #
16
+ # @api private
17
+ # @since 0.1.0
18
+ DEFAULT_ACCESS = :public
19
+
20
+ # @return [Array<Symbol>]
21
+ #
22
+ # @api private
23
+ # @since 0.1.0
24
+ ACCESS_MARKS = %i[public protected private].freeze
25
+
26
+ # @return [Symbol]
27
+ #
28
+ # @api private
29
+ # @since 0.1.0
30
+ DEFAULT_BINDING_STRATEGY = :dynamic
31
+
32
+ # @return [Array<Symbol>]
33
+ #
34
+ # @api private
35
+ # @since 0.1.0
36
+ BINDING_STRATEGIES = %i[static dynamic].freeze
37
+
38
+ # @return [Boolean]
39
+ #
40
+ # @api private
41
+ # @since 0.1.0
42
+ DEFAULT_MEMOIZE = false
43
+
44
+ # @return [NilClass]
45
+ #
46
+ # @api private
47
+ # @since 0.1.0
48
+ EMPTY_CONTAINER_DESTINATION = nil
49
+
50
+ # @return [Hash<String|Symbol,String>]
51
+ #
52
+ # @api private
53
+ # @since 0.1.0
54
+ attr_reader :imports
55
+
56
+ # @return [Symbol]
57
+ #
58
+ # @api private
59
+ # @since 0.1.0
60
+ attr_reader :access
61
+
62
+ # @return [Symbol]
63
+ #
64
+ # @api private
65
+ # @since 0.1.0
66
+ attr_reader :bind
67
+
68
+ # @return [NilClass, <SmartCore::Container>]
69
+ #
70
+ # @api private
71
+ # @since 0.1.0
72
+ attr_reader :from
73
+
74
+ # @return [Boolean]
75
+ #
76
+ # @api private
77
+ # @since 0.1.0
78
+ attr_reader :memoize
79
+
80
+ # @return [SmartCore::Injection::Injector::ContainerSet]
81
+ #
82
+ # @api private
83
+ # @since 0.1.0
84
+ attr_reader :container_set
85
+
86
+ # @return [Class, Module]
87
+ #
88
+ # @api private
89
+ # @since 0.1.0
90
+ attr_reader :injectable
91
+
92
+ # @param injectable [Class, Module]
93
+ # @param container_set [SmartCore::Injection::Injector::ContainerSet]
94
+ # @param import [Hash<String|Symbol,String>]
95
+ # @option memoize [Boolean]
96
+ # @option access [Symbol]
97
+ # @option bind [Symbol]
98
+ # @option from [NilClass, SmartCore::Container]
99
+ # @return [void]
100
+ #
101
+ # @api private
102
+ # @since 0.1.0
103
+ def initialize(
104
+ injectable,
105
+ container_set,
106
+ imports,
107
+ memoize: DEFAULT_MEMOIZE,
108
+ access: DEFAULT_ACCESS,
109
+ bind: DEFAULT_BINDING_STRATEGY,
110
+ from: EMPTY_CONTAINER_DESTINATION
111
+ )
112
+ IncompatabilityControl.prevent_incompatabilities!(
113
+ injectable,
114
+ imports,
115
+ memoize,
116
+ access,
117
+ bind,
118
+ from
119
+ )
120
+
121
+ @injectable = injectable
122
+ @container_set = container_set
123
+ @imports = imports
124
+ @memoize = memoize
125
+ @access = access
126
+ @bind = bind
127
+ @from = from
128
+ end
129
+
130
+ # @return [Class, Module]
131
+ #
132
+ # @api private
133
+ # @since 0.1.0
134
+ def instance_level_injectable
135
+ injectable
136
+ end
137
+
138
+ # @return [Class]
139
+ #
140
+ # @api private
141
+ # @since 0.1.0
142
+ def class_level_injectable
143
+ class << injectable; self; end
144
+ end
145
+
146
+ # @return [Boolean]
147
+ #
148
+ # @api private
149
+ # @since 0.1.0
150
+ def bind_dynamic?
151
+ bind == :dynamic
152
+ end
153
+
154
+ # @return [Boolean]
155
+ #
156
+ # @api private
157
+ # @since 0.1.0
158
+ def bind_static?
159
+ bind == :static
160
+ end
161
+
162
+ # @param block [Block]
163
+ # @yield [import_key, import_path]
164
+ # @yieldparam import_key [String, Symbol]
165
+ # @yieldparam import_path [String]
166
+ # @return [Enumerable]
167
+ #
168
+ # @api private
169
+ # @since 0.1.0
170
+ def each_import(&block)
171
+ block_given? ? imports.each_pair(&block) : imports.each_pair
172
+ end
173
+ end