smart_injection 0.0.0 → 0.1.0

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