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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f48169147897c8ce8f66b9f89612932e7f4928dfbd841a71333952e36fa2d8e
4
- data.tar.gz: d8516b07187415d826c6370f3b03c7200c3c8df59cc04cba455aa815beda0f1e
3
+ metadata.gz: a205772dafa117f100cd5c63816db14f1c2c39dc294dfc9d92abd77eec24f3b9
4
+ data.tar.gz: ba602f4127dcccb4579550a2884f84dc35623f3a9f9fef5cce4881c40b5bfe85
5
5
  SHA512:
6
- metadata.gz: 6258aebce545dafba8aaef29d7f137f322e097c60d7003d2dfd3bdc8d111845493f52909918c71bc233abc54c5c5c3b55dd7fd4b83d753f238bdf6a92c8c3704
7
- data.tar.gz: 3f27d11d72af45e20fd2fbf393765be6414a2bb5e91b9dff4a797c13870fd36752702cc03cb9fd7e13acbea3632b2712e967ddf6e6bab6ef22c24e52bd70fad3
6
+ metadata.gz: 34094f99543b3643f706f9fe21c0a9d5b9d30e47bbc1f06104a1a83f282149194cc97fe690c5f73bd4f2ba0fcbd1c7c66d48a528b34df2f0880d0b69b9017e30
7
+ data.tar.gz: 01dcae384d39e0ff46dc299bd55cfb94571b18462c924767d9b2ce8268c9d318d8352386909209c7d0e2387f9867c7fc3e7d70509a8529546605fad0c372046c
@@ -1,2 +1,6 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
+
4
+ # [0.1.0] - 2020-07-09
5
+
6
+ - Release :)
@@ -1,34 +1,41 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_injection (0.0.0)
4
+ smart_injection (0.0.0.alpha2)
5
+ smart_container (~> 0.8, >= 0.8.1)
6
+ smart_engine (~> 0.7)
5
7
 
6
8
  GEM
7
9
  remote: https://rubygems.org/
8
10
  specs:
9
- activesupport (6.0.3.1)
11
+ activesupport (6.0.3.2)
10
12
  concurrent-ruby (~> 1.0, >= 1.0.2)
11
13
  i18n (>= 0.7, < 2)
12
14
  minitest (~> 5.1)
13
15
  tzinfo (~> 1.1)
14
16
  zeitwerk (~> 2.2, >= 2.2.2)
15
- armitage-rubocop (0.85.0)
16
- rubocop (= 0.85.0)
17
+ armitage-rubocop (0.85.1)
18
+ rubocop (= 0.85.1)
17
19
  rubocop-performance (= 1.6.1)
18
- rubocop-rails (= 2.5.2)
20
+ rubocop-rails (= 2.6.0)
19
21
  rubocop-rake (= 0.5.1)
20
- rubocop-rspec (= 1.39.0)
22
+ rubocop-rspec (= 1.40.0)
21
23
  ast (2.4.1)
24
+ coderay (1.1.3)
22
25
  concurrent-ruby (1.1.6)
23
- diff-lcs (1.3)
26
+ diff-lcs (1.4.4)
24
27
  docile (1.3.2)
25
28
  i18n (1.8.3)
26
29
  concurrent-ruby (~> 1.0)
30
+ method_source (1.0.0)
27
31
  minitest (5.14.1)
28
- parallel (1.19.1)
29
- parser (2.7.1.3)
30
- ast (~> 2.4.0)
31
- rack (2.2.2)
32
+ parallel (1.19.2)
33
+ parser (2.7.1.4)
34
+ ast (~> 2.4.1)
35
+ pry (0.13.1)
36
+ coderay (~> 1.1)
37
+ method_source (~> 1.0)
38
+ rack (2.2.3)
32
39
  rainbow (3.0.0)
33
40
  rake (13.0.1)
34
41
  regexp_parser (1.7.1)
@@ -46,7 +53,7 @@ GEM
46
53
  diff-lcs (>= 1.2.0, < 2.0)
47
54
  rspec-support (~> 3.9.0)
48
55
  rspec-support (3.9.3)
49
- rubocop (0.85.0)
56
+ rubocop (0.85.1)
50
57
  parallel (~> 1.10)
51
58
  parser (>= 2.7.0.1)
52
59
  rainbow (>= 2.2.2, < 4.0)
@@ -55,28 +62,31 @@ GEM
55
62
  rubocop-ast (>= 0.0.3)
56
63
  ruby-progressbar (~> 1.7)
57
64
  unicode-display_width (>= 1.4.0, < 2.0)
58
- rubocop-ast (0.0.3)
65
+ rubocop-ast (0.1.0)
59
66
  parser (>= 2.7.0.1)
60
67
  rubocop-performance (1.6.1)
61
68
  rubocop (>= 0.71.0)
62
- rubocop-rails (2.5.2)
63
- activesupport
69
+ rubocop-rails (2.6.0)
70
+ activesupport (>= 4.2.0)
64
71
  rack (>= 1.1)
65
- rubocop (>= 0.72.0)
72
+ rubocop (>= 0.82.0)
66
73
  rubocop-rake (0.5.1)
67
74
  rubocop
68
- rubocop-rspec (1.39.0)
75
+ rubocop-rspec (1.40.0)
69
76
  rubocop (>= 0.68.1)
70
77
  ruby-progressbar (1.10.1)
71
78
  simplecov (0.18.5)
72
79
  docile (~> 1.1)
73
80
  simplecov-html (~> 0.11)
74
81
  simplecov-html (0.12.2)
82
+ smart_container (0.8.1)
83
+ smart_engine (~> 0.5)
84
+ smart_engine (0.7.0)
75
85
  thread_safe (0.3.6)
76
86
  tzinfo (1.2.7)
77
87
  thread_safe (~> 0.1)
78
88
  unicode-display_width (1.7.0)
79
- zeitwerk (2.3.0)
89
+ zeitwerk (2.3.1)
80
90
 
81
91
  PLATFORMS
82
92
  ruby
@@ -84,6 +94,7 @@ PLATFORMS
84
94
  DEPENDENCIES
85
95
  armitage-rubocop (~> 0.85)
86
96
  bundler (~> 2.1)
97
+ pry (~> 0.13)
87
98
  rake (~> 13.0)
88
99
  rspec (~> 3.9)
89
100
  simplecov (~> 0.18)
data/README.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  Dependency injection principles and idioms realized in scope of Ruby.
4
4
 
5
+ ---
6
+
7
+ ## Major Features
8
+
9
+ - `method-injection` strategy
10
+ - `soon:` constructor injection strategy;
11
+ - `soon:` property injection strategy;
12
+ - realized as a mixin;
13
+ - instance-method dependency injection;
14
+ - class-method dependency injection;
15
+ - multiple IoC-container registration;
16
+ - static and dynamic bindings;
17
+ - support for memoization with run-time dependency-switchable re-memoization;
18
+ - an ability to import dependencies from the list of IoC-containers
19
+ - an ability to import from the pre-configured default IoC-container(s);
20
+ - an ability to import from any manually passed IoC-container;
21
+ - privacy control of injected dependency (public/private/protected);
22
+
23
+ ---
24
+
5
25
  ## Installation
6
26
 
7
27
  ```ruby
@@ -20,6 +40,71 @@ require 'smart_core/injection'
20
40
 
21
41
  ---
22
42
 
43
+ ## Synopsis
44
+
45
+ Create some containers:
46
+
47
+ ```ruby
48
+ AppContainer = SmartCore::Container.define do
49
+ namespace(:data_storage) do
50
+ register(:main) { Sequel::Model.db }
51
+ register(:cache) { Redis.new }
52
+ end
53
+ end
54
+
55
+ ServiceContainer = SmartCore::Container.define do
56
+ namespace(:rands) do
57
+ register(:alphanum) { -> { SeureRandom.alphanumeric } }
58
+ register(:hex) { -> { SecureRandom.hex } }
59
+ end
60
+ end
61
+
62
+ GlobalContainer = SmartCore::Container.define do
63
+ namespace(:phone_clients) do
64
+ register(:nexmo) { Nexmo.new }
65
+ register(:twilio) { Twilio.new }
66
+ end
67
+ end
68
+ ```
69
+
70
+ And work with dependency injection:
71
+
72
+ ```ruby
73
+ class MiniService
74
+ include SmartCore::Injection
75
+
76
+ register_container(AppContainer)
77
+ register_container(ServiceContainer)
78
+
79
+ # --- or ---
80
+ include SmartCore::Injection(AppContainer, ServiceContainer)
81
+
82
+ # --- or ---
83
+ include SmartCore::Injection
84
+ register_container(AppContainer, ServiceContainer)
85
+
86
+ # import dependencies to an instance
87
+ import({ db: 'data_storage.main' }, bind: :dynamic, access: :private)
88
+ import({ rnd: 'rands.alphanum' }, bind: :static, memoize: true)
89
+
90
+ # import dependencies to a class
91
+ import_static({ cache: 'data_storage.cache', hexer: 'rands.hex' }, bind: :static)
92
+
93
+ # import from a non-registered container
94
+ import({ phone_client: 'phone_clients.nexmo' }, from: GlobalContainer)
95
+
96
+ def call
97
+ db # => returns data_storage.main
98
+ rnd # => returns rands.alphanum
99
+ self.class.cache # => returns data_storage.cache
100
+ self.class.hexer # => returns rands.hexer
101
+ phone_client # => returns phone_clients.nexmo
102
+ end
103
+ end
104
+ ```
105
+
106
+ ---
107
+
23
108
  ## Contributing
24
109
 
25
110
  - Fork it ( https://github.com/smart-rb/smart_injection )
@@ -1,11 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'smart_core/container'
4
+ require 'set'
5
+
3
6
  # @api public
4
7
  # @since 0.1.0
5
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
+
6
24
  # @api public
7
25
  # @since 0.1.0
8
26
  module Injection
9
27
  require_relative 'injection/version'
28
+ require_relative 'injection/errors'
29
+ require_relative 'injection/injector'
30
+ require_relative 'injection/locator'
31
+ require_relative 'injection/dsl'
32
+
33
+ class << self
34
+ # @param base_klass [Class, Module]
35
+ # @return [void]
36
+ #
37
+ # @api private
38
+ # @since 0.1.0
39
+ def included(base_klass)
40
+ ::SmartCore::Injection::Injector::Modulizer.inject_to(base_klass)
41
+ end
42
+ end
10
43
  end
11
44
  end
@@ -0,0 +1,107 @@
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
+
18
+ base_klass.extend(ClassMethods)
19
+ base_klass.singleton_class.prepend(ClassInheritance)
20
+ end
21
+ end
22
+
23
+ # @api private
24
+ # @since 0.1.0
25
+ module ClassInheritance
26
+ # @param child_klass [Class]
27
+ # @return [void]
28
+ #
29
+ # @api private
30
+ # @since 0.1.0
31
+ def inherited(child_klass)
32
+ child_klass.instance_variable_set(
33
+ :@__smart_injection_injector__,
34
+ __smart_injection_injector__.duplicate_for(child_klass)
35
+ )
36
+ child_klass.singleton_class.prepend(ClassInheritance)
37
+ super
38
+ end
39
+ end
40
+
41
+ # @api private
42
+ # @since 0.1.0
43
+ module ClassMethods
44
+ # @param imports [Hash<String|Symbol,String>]
45
+ # @option memoize [Boolean]
46
+ # @option access [Symbol]
47
+ # @option bind [Symbol]
48
+ # @option from [NilClass, SmartCore::Container]
49
+ # @return [void]
50
+ #
51
+ # @api public
52
+ # @sincd 0.1.0
53
+ def import(
54
+ imports,
55
+ memoize: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_MEMOIZE,
56
+ access: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_ACCESS,
57
+ bind: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_BINDING_STRATEGY,
58
+ from: SmartCore::Injection::Injector::InjectionSettings::EMPTY_CONTAINER_DESTINATION
59
+ )
60
+ __smart_injection_injector__.inject(imports, memoize, access, bind, from)
61
+ end
62
+
63
+ # @param imports [Hash<String|Symbol,String>]
64
+ # @option memoize [Boolean]
65
+ # @option access [Symbol]
66
+ # @option bind [Symbol]
67
+ # @option from [NilClass, SmartCore::Container]
68
+ # @return [void]
69
+ #
70
+ # @api public
71
+ # @sincd 0.1.0
72
+ def import_static(
73
+ imports,
74
+ memoize: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_MEMOIZE,
75
+ access: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_ACCESS,
76
+ bind: SmartCore::Injection::Injector::InjectionSettings::DEFAULT_BINDING_STRATEGY,
77
+ from: SmartCore::Injection::Injector::InjectionSettings::EMPTY_CONTAINER_DESTINATION
78
+ )
79
+ __smart_injection_injector__.inject_static(imports, memoize, access, bind, from)
80
+ end
81
+
82
+ # @param containers [Array<SmartCore::Container>]
83
+ # @return [void]
84
+ #
85
+ # @api public
86
+ # @since 0.1.0
87
+ def register_container(*containers)
88
+ __smart_injection_injector__.register_container(*containers)
89
+ end
90
+
91
+ # @return [Array<SmartCore::Container>]
92
+ #
93
+ # @api public
94
+ # @since 0.1.0
95
+ def linked_containers
96
+ __smart_injection_injector__.associated_containers
97
+ end
98
+
99
+ # @return [SmartCore::Injection::Injector]
100
+ #
101
+ # @api private
102
+ # @since 0.1.0
103
+ def __smart_injection_injector__
104
+ @__smart_injection_injector__
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,15 @@
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
+
12
+ # @api public
13
+ # @since 0.1.0
14
+ NoRegisteredContainersError = Class.new(Error)
15
+ end
@@ -0,0 +1,165 @@
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
+ # @param another_injectable [Class, Module]
66
+ # @return [SmartCore::Injection::Injector]
67
+ #
68
+ # @api private
69
+ # @since 0.1.0
70
+ def duplicate_for(another_injectable)
71
+ thread_safe { create_duplicate(another_injectable) }
72
+ end
73
+
74
+ private
75
+
76
+ # @return [Class, Module]
77
+ #
78
+ # @api private
79
+ # @since 0.1.0
80
+ attr_reader :injectable
81
+
82
+ # @return [Array<SmartCore::Container>]
83
+ #
84
+ # @api private
85
+ # @since 0.1.0
86
+ attr_reader :linked_containers
87
+
88
+ # @param another_injectable [Class, Module]
89
+ # @return [SmartCore::Injection::Injector]
90
+ #
91
+ # @api private
92
+ # @since 0.1.0
93
+ def create_duplicate(another_injectable)
94
+ self.class.new(another_injectable).tap do |duplicate|
95
+ linked_containers.each do |container|
96
+ duplicate.register_container(container)
97
+ end
98
+ end
99
+ end
100
+
101
+ # @param imports [Hash<String|Symbol,String>]
102
+ # @param memoize [Boolean]
103
+ # @param access [Symbol]
104
+ # @param bind [Symbol]
105
+ # @param from [NilClass, SmartCore::Container]
106
+ # @return [void]
107
+ #
108
+ # @api private
109
+ # @since 0.1.0
110
+ def inject_instance_method(imports, memoize, access, bind, from)
111
+ SmartCore::Injection::Injector::Strategies::MethodInjection.inject_instance_method(
112
+ SmartCore::Injection::Injector::InjectionSettings.new(
113
+ injectable,
114
+ linked_containers,
115
+ imports,
116
+ memoize: memoize,
117
+ access: access,
118
+ bind: bind,
119
+ from: from
120
+ )
121
+ )
122
+ end
123
+
124
+ # @param imports [Hash<String|Symbol,String>]
125
+ # @param memoize [Boolean]
126
+ # @param access [Symbol]
127
+ # @param bind [Symbol]
128
+ # @param from [NilClass, SmartCore::Container]
129
+ # @return [void]
130
+ #
131
+ # @api private
132
+ # @since 0.1.0
133
+ def inject_class_method(imports, memoize, access, bind, from)
134
+ SmartCore::Injection::Injector::Strategies::MethodInjection.inject_class_method(
135
+ SmartCore::Injection::Injector::InjectionSettings.new(
136
+ injectable,
137
+ linked_containers,
138
+ imports,
139
+ memoize: memoize,
140
+ access: access,
141
+ bind: bind,
142
+ from: from
143
+ )
144
+ )
145
+ end
146
+
147
+ # @param containers [Array<SmartCore::Container>]
148
+ # @return [void]
149
+ #
150
+ # @api private
151
+ # @since 0.1.0
152
+ def link_container(containers)
153
+ containers.each do |container|
154
+ linked_containers.add(container)
155
+ end
156
+ end
157
+
158
+ # @return [Any]
159
+ #
160
+ # @api private
161
+ # @since 0.1.0
162
+ def thread_safe(&block)
163
+ @access_lock.synchronize(&block)
164
+ end
165
+ end