smart_injection 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Injection::Injector::ContainerSet
6
+ require_relative 'container_set/adding_listener'
7
+
8
+ # @since 0.1.0
9
+ include Enumerable
10
+
11
+ # @return [void]
12
+ #
13
+ # @api private
14
+ # @since 0.1.0
15
+ def initialize
16
+ @containers = [] # NOTE: we use Array cuz we need an ordered set
17
+ @adding_listeners = []
18
+ @access_lock = SmartCore::Engine::Lock.new
19
+ end
20
+
21
+ # @param container [SmartCore::Container]
22
+ # @return [void]
23
+ #
24
+ # @api private
25
+ # @since 0.1.0
26
+ def add(container)
27
+ thread_safe { append_container(container) }
28
+ end
29
+ alias_method :<<, :add
30
+
31
+ # @param listener [Block]
32
+ # @yield [container]
33
+ # @yieldparam container [SmartCore::Container]
34
+ # @return [void]
35
+ #
36
+ # @api private
37
+ # @since 0.1.0
38
+ def listen_addings(&listener)
39
+ thread_safe { add_adding_listener(listener) }
40
+ end
41
+
42
+ # @param block [Block]
43
+ # @yield [container]
44
+ # @yieldparam container [SmartCore::Container]
45
+ # @return [Enumerator]
46
+ #
47
+ # @api private
48
+ # @since 0.1.0
49
+ def each(&block)
50
+ thread_safe { block_given? ? containers.each(&block) : containers.each }
51
+ end
52
+
53
+ # @param block [Block]
54
+ # @yield [container]
55
+ # @yieldparam container [SmartCore::Container]
56
+ # @return [Enumerator]
57
+ #
58
+ # @api private
59
+ # @since 0.1.0
60
+ def reverse_each(&block)
61
+ thread_safe { block_given? ? containers.reverse_each(&block) : containers.reverse_each }
62
+ end
63
+
64
+ # @return [Array<SmartCore::Container>]
65
+ #
66
+ # @api private
67
+ # @since 0.1.0
68
+ def list
69
+ thread_safe { containers.dup }
70
+ end
71
+
72
+ private
73
+
74
+ # @return [Array<SmartCore::Container>]
75
+ #
76
+ # @api private
77
+ # @since 0.1.0
78
+ attr_reader :containers
79
+
80
+ # @return [Array<SmartCore::Injection::Injector::ContainerSet::AddingListener>]
81
+ attr_reader :adding_listeners
82
+
83
+ # @param listener [Proc]
84
+ # @return [void]
85
+ #
86
+ # @api private
87
+ # @since 0.1.0
88
+ def add_adding_listener(listener)
89
+ adding_listeners << SmartCore::Injection::Injector::ContainerSet::AddingListener.new(listener)
90
+ end
91
+
92
+ # @param container [SmartCore::Container]
93
+ # @return [void]
94
+ #
95
+ # @api private
96
+ # @since 0.1.0
97
+ def append_container(container)
98
+ # NOTE:
99
+ # - #concant is used to prevent container duplications in ordered set;
100
+ # - @containers should have an ordered unified container list;
101
+ containers.concat([container])
102
+ adding_listeners.each { |listener| listener.notify(container) }
103
+ end
104
+
105
+ # @param block [Block]
106
+ # @return [Any]
107
+ #
108
+ # @api private
109
+ # @since 0.1.0
110
+ def thread_safe(&block)
111
+ @access_lock.synchronize(&block)
112
+ end
113
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Injection::Injector::ContainerSet::AddingListener
6
+ # @param listener [Proc]
7
+ # @return [void]
8
+ #
9
+ # @api private
10
+ # @since 0.1.0
11
+ def initialize(listener)
12
+ @listener = listener
13
+ end
14
+
15
+ # @param cotnainer [SmartCore::Container]
16
+ #
17
+ # @api private
18
+ # @since 0.1.0
19
+ def notify(container)
20
+ listener.call(container)
21
+ end
22
+
23
+ private
24
+
25
+ # @return [Proc]
26
+ #
27
+ # @api private
28
+ # @since 0.1.0
29
+ attr_reader :listener
30
+ 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
@@ -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