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