dry-auto_inject 0.2.0 → 0.3.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 +4 -4
- data/.travis.yml +2 -2
- data/CHANGELOG.md +86 -0
- data/Gemfile +1 -4
- data/README.md +16 -8
- data/bin/console +3 -7
- data/dry-auto_inject.gemspec +4 -0
- data/lib/dry/auto_inject.rb +7 -143
- data/lib/dry/auto_inject/builder.rb +31 -0
- data/lib/dry/auto_inject/dependency_map.rb +44 -0
- data/lib/dry/auto_inject/injector.rb +23 -0
- data/lib/dry/auto_inject/strategies.rb +19 -0
- data/lib/dry/auto_inject/strategies/args.rb +71 -0
- data/lib/dry/auto_inject/strategies/constructor.rb +60 -0
- data/lib/dry/auto_inject/strategies/hash.rb +38 -0
- data/lib/dry/auto_inject/strategies/kwargs.rb +68 -0
- data/lib/dry/auto_inject/version.rb +2 -2
- metadata +26 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c8a5ebc379dd91da33ab5b74b37b8b5233ce496
|
4
|
+
data.tar.gz: 530f763d2a088affcfba27591b4b414b0005b1e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb55775c7a465d2f796e56421c6098abef986ea5c177b18851e4ba2cce6111bbdf8dad8fd873d52072e674901e7fcaeac23a304cae5cd6198e0581f7c5d32c6a
|
7
|
+
data.tar.gz: 0c9c3d0012f2978420fa74fd536eed7c77cdf0d579d85a28afb05d79399f02d31e770b31718679babe16befc8c1a3de22df0635bda5ef495f2475b12c69e0378
|
data/.travis.yml
CHANGED
@@ -8,8 +8,7 @@ rvm:
|
|
8
8
|
- 2.0
|
9
9
|
- 2.1
|
10
10
|
- 2.2
|
11
|
-
- rbx
|
12
|
-
- jruby
|
11
|
+
- rbx
|
13
12
|
- ruby-head
|
14
13
|
- jruby-head
|
15
14
|
env:
|
@@ -17,6 +16,7 @@ env:
|
|
17
16
|
- JRUBY_OPTS='--dev -J-Xmx1024M'
|
18
17
|
matrix:
|
19
18
|
allow_failures:
|
19
|
+
- rvm: rbx
|
20
20
|
- rvm: ruby-head
|
21
21
|
- rvm: jruby-head
|
22
22
|
notifications:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,89 @@
|
|
1
|
+
# v.0.3.0, 2016-06-02
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* Support for new `kwargs` and `hash` injection strategies
|
6
|
+
|
7
|
+
These strategies can be accessed via methods on the main builder object:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
MyInject = Dry::AutoInect(my_container)
|
11
|
+
|
12
|
+
class MyClass
|
13
|
+
include MyInject.hash["my_dep"]
|
14
|
+
end
|
15
|
+
```
|
16
|
+
* Support for user-provided injection strategies
|
17
|
+
|
18
|
+
All injection strategies are now held in their own `Dry::AutoInject::Strategies` container. You can add register your own strategies to this container, or choose to provide a strategies container of your own:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
class CustomStrategy < Module
|
22
|
+
# Your strategy code goes here :)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Registering your own strategy (globally)
|
26
|
+
Dry::AutoInject::Strategies.register :custom, CustomStrategy
|
27
|
+
|
28
|
+
MyInject = Dry::AutoInject(my_container)
|
29
|
+
|
30
|
+
class MyClass
|
31
|
+
include MyInject.custom["my_dep"]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Providing your own container (keeping the existing strategies in place)
|
35
|
+
class MyStrategies < Dry::AutoInject::Strategies
|
36
|
+
register :custom, CustomStrategy
|
37
|
+
end
|
38
|
+
|
39
|
+
MyInject = Dry::AutoInject(my_container, strategies: MyStrategies)
|
40
|
+
|
41
|
+
class MyClass
|
42
|
+
include MyInject.custom["my_dep"]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Proiding a completely separated container
|
46
|
+
class MyStrategies
|
47
|
+
extend Dry::Container::Mixin
|
48
|
+
register :custom, CustomStrategy
|
49
|
+
end
|
50
|
+
|
51
|
+
MyInject = Dry::AutoInject(my_container, strategies: MyStrategies)
|
52
|
+
|
53
|
+
class MyClass
|
54
|
+
include MyInject.custom["my_dep"]
|
55
|
+
end
|
56
|
+
```
|
57
|
+
* User-specified aliases for dependencies
|
58
|
+
|
59
|
+
These aliases enable you to specify your own name for dependencies, both for their local readers and their keys in the kwargs- and hash-based initializers. Specify aliases by passing a hash of names:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
MyInject = Dry::AutoInect(my_container)
|
63
|
+
|
64
|
+
class MyClass
|
65
|
+
include MyInject[my_dep: "some_other.dep"]
|
66
|
+
|
67
|
+
# Refer to the dependency as `my_dep` inside the class
|
68
|
+
end
|
69
|
+
|
70
|
+
# Pass your own replacements using the `my_dep` initializer key
|
71
|
+
my_obj = MyClass.new(my_dep: something_else)
|
72
|
+
```
|
73
|
+
|
74
|
+
A mix of both regular and aliased dependencies can also be injected:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
include MyInject["some_dep", another_dep: "some_other.dep"]
|
78
|
+
```
|
79
|
+
|
80
|
+
* Inspect the `super` method of the including class’s `#initialize` and send it arguments that will match its own arguments list/arity. This allows auto_inject to be used more easily in existing class inheritance heirarchies.
|
81
|
+
|
82
|
+
### Changed
|
83
|
+
|
84
|
+
* `kwargs` is the new default injection strategy
|
85
|
+
* Rubinius support is not available for the `kwargs` strategy (see [#18](https://github.com/dry-rb/dry-auto_inject/issues/18))
|
86
|
+
|
1
87
|
# v0.2.0 2016-02-09
|
2
88
|
|
3
89
|
### Added
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
[gitter]: https://gitter.im/dry-rb/chat
|
2
|
+
[gem]: https://rubygems.org/gems/dry-auto_inject
|
3
|
+
[travis]: https://travis-ci.org/dry-rb/dry-auto_inject
|
4
|
+
[gemnasium]: https://gemnasium.com/dry-rb/dry-auto_inject
|
5
|
+
[code_climate]: https://codeclimate.com/github/dry-rb/dry-auto_inject
|
6
|
+
[inch]: http://inch-ci.org/github/dry-rb/dry-auto_inject
|
7
|
+
|
8
|
+
# dry-auto_inject [][gitter]
|
9
|
+
|
10
|
+
[][gem]
|
11
|
+
[][travis]
|
12
|
+
[][gemnasium]
|
13
|
+
[][code_climate]
|
14
|
+
[][inch]
|
15
|
+

|
8
16
|
|
9
17
|
A simple extensions which allows you to automatically inject dependencies to your
|
10
18
|
object constructors from a configured container.
|
@@ -73,5 +81,5 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
73
81
|
|
74
82
|
## Contributing
|
75
83
|
|
76
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
84
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/dry-rb/dry-auto_inject.
|
77
85
|
|
data/bin/console
CHANGED
@@ -1,14 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
|
-
require 'dry
|
4
|
+
require 'dry-auto_inject'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require 'irb'
|
14
|
-
IRB.start
|
9
|
+
require 'pry'
|
10
|
+
Pry.start
|
data/dry-auto_inject.gemspec
CHANGED
@@ -17,6 +17,10 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
18
|
spec.require_paths = ['lib']
|
19
19
|
|
20
|
+
spec.required_ruby_version = '>= 2.0.0'
|
21
|
+
|
22
|
+
spec.add_runtime_dependency 'dry-container', '~> 0.3.4'
|
23
|
+
|
20
24
|
spec.add_development_dependency 'bundler'
|
21
25
|
spec.add_development_dependency 'rake'
|
22
26
|
spec.add_development_dependency 'rspec'
|
data/lib/dry/auto_inject.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'dry/auto_inject/
|
1
|
+
require 'dry/auto_inject/builder'
|
2
2
|
|
3
3
|
module Dry
|
4
4
|
# Configure an auto-injection module
|
@@ -38,151 +38,15 @@ module Dry
|
|
38
38
|
# @return [Proc] calling the returned proc builds an auto-injection module
|
39
39
|
#
|
40
40
|
# @api public
|
41
|
-
def self.AutoInject(container)
|
42
|
-
|
41
|
+
def self.AutoInject(container, options = {})
|
42
|
+
AutoInject::Builder.new(container, options)
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
|
-
attr_reader :container, :options
|
47
|
-
|
48
|
-
# @api private
|
49
|
-
def initialize(container, options = {})
|
50
|
-
@container = container
|
51
|
-
@options = options
|
52
|
-
end
|
53
|
-
|
54
|
-
# @api public
|
55
|
-
def hash
|
56
|
-
self.class.new(container, options.merge(type: :hash))
|
57
|
-
end
|
58
|
-
|
59
|
-
# @api public
|
60
|
-
def [](*names)
|
61
|
-
AutoInject.new(names, container, options)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# @api private
|
66
|
-
class AutoInject < Module
|
67
|
-
attr_reader :names
|
68
|
-
|
69
|
-
attr_reader :container
|
70
|
-
|
71
|
-
attr_reader :instance_mod
|
72
|
-
|
73
|
-
attr_reader :ivars
|
74
|
-
|
75
|
-
attr_reader :options
|
76
|
-
|
77
|
-
attr_reader :type
|
78
|
-
|
79
|
-
# @api private
|
80
|
-
def initialize(names, container, options = {})
|
81
|
-
@names = names
|
82
|
-
@container = container
|
83
|
-
@options = options
|
84
|
-
@type = options.fetch(:type, :args)
|
85
|
-
@ivars = names.map(&:to_s).map { |s| s.split('.').last }.map(&:to_sym)
|
86
|
-
@instance_mod = Module.new
|
87
|
-
define_constructor
|
88
|
-
end
|
89
|
-
|
90
|
-
# @api private
|
91
|
-
def included(klass)
|
92
|
-
define_readers
|
93
|
-
define_new_method(klass)
|
94
|
-
define_container(klass)
|
95
|
-
|
96
|
-
klass.send(:include, instance_mod)
|
97
|
-
|
98
|
-
super
|
99
|
-
end
|
100
|
-
|
101
|
-
private
|
102
|
-
|
103
|
-
# @api private
|
104
|
-
def define_container(klass)
|
105
|
-
klass.instance_variable_set('@container', container)
|
106
|
-
|
107
|
-
klass.class_eval do
|
108
|
-
def self.container
|
109
|
-
if superclass.respond_to?(:container)
|
110
|
-
superclass.container
|
111
|
-
else
|
112
|
-
@container
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# @api private
|
119
|
-
def define_new_method(klass)
|
120
|
-
case type
|
121
|
-
when :args then define_new_method_with_args(klass)
|
122
|
-
when :hash then define_new_method_with_hash(klass)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# @api private
|
127
|
-
def define_new_method_with_args(klass)
|
128
|
-
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
129
|
-
def self.new(*args)
|
130
|
-
names = [#{names.map(&:inspect).join(', ')}]
|
131
|
-
deps = names.map.with_index { |_, i| args[i] || container[names[i]] }
|
132
|
-
super(*deps)
|
133
|
-
end
|
134
|
-
RUBY
|
135
|
-
end
|
136
|
-
|
137
|
-
# @api private
|
138
|
-
def define_new_method_with_hash(klass)
|
139
|
-
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
140
|
-
def self.new(options = {})
|
141
|
-
names = [#{names.map(&:inspect).join(', ')}]
|
142
|
-
deps = names.each_with_object({}) { |k, r|
|
143
|
-
r[k.to_s.split('.').last.to_sym] = options[k] || container[k]
|
144
|
-
}.merge(options)
|
145
|
-
super(deps)
|
146
|
-
end
|
147
|
-
RUBY
|
148
|
-
end
|
149
|
-
|
150
|
-
# @api private
|
151
|
-
def define_constructor
|
152
|
-
case type
|
153
|
-
when :args then define_constructor_with_args
|
154
|
-
when :hash then define_constructor_with_hash
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
# @api private
|
159
|
-
def define_constructor_with_args
|
160
|
-
instance_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
161
|
-
def initialize(*args)
|
162
|
-
super()
|
163
|
-
#{ivars.map.with_index { |name, i| "@#{name} = args[#{i}]" }.join("\n")}
|
164
|
-
end
|
165
|
-
RUBY
|
166
|
-
self
|
167
|
-
end
|
168
|
-
|
169
|
-
# @api private
|
170
|
-
def define_constructor_with_hash
|
171
|
-
instance_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
172
|
-
def initialize(options)
|
173
|
-
super()
|
174
|
-
#{ivars.map { |name| "@#{name} = options[:#{name}]" }.join("\n")}
|
175
|
-
end
|
176
|
-
RUBY
|
177
|
-
self
|
178
|
-
end
|
179
|
-
|
45
|
+
module AutoInject
|
180
46
|
# @api private
|
181
|
-
def
|
182
|
-
|
183
|
-
|
184
|
-
RUBY
|
185
|
-
self
|
47
|
+
def self.super_method(klass, method)
|
48
|
+
method = klass.instance_method(method)
|
49
|
+
method unless method.owner.equal?(klass)
|
186
50
|
end
|
187
51
|
end
|
188
52
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'dry/auto_inject/strategies'
|
2
|
+
require 'dry/auto_inject/injector'
|
3
|
+
|
4
|
+
module Dry
|
5
|
+
module AutoInject
|
6
|
+
class Builder
|
7
|
+
# @api private
|
8
|
+
attr_reader :container
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
attr_reader :strategies
|
12
|
+
|
13
|
+
def initialize(container, options = {})
|
14
|
+
@container = container
|
15
|
+
@strategies = options.fetch(:strategies) { Strategies }
|
16
|
+
|
17
|
+
strategies.keys.each do |strategy_name|
|
18
|
+
define_singleton_method(strategy_name) do
|
19
|
+
strategy = strategies[strategy_name]
|
20
|
+
Injector.new(container, strategy)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api public
|
26
|
+
def [](*dependency_names)
|
27
|
+
default[*dependency_names]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Dry
|
2
|
+
module AutoInject
|
3
|
+
DuplicateDependencyError = Class.new(StandardError)
|
4
|
+
|
5
|
+
class DependencyMap
|
6
|
+
def initialize(*dependencies)
|
7
|
+
@map = {}
|
8
|
+
|
9
|
+
dependencies = dependencies.dup
|
10
|
+
aliases = dependencies.last.is_a?(Hash) ? dependencies.pop : {}
|
11
|
+
|
12
|
+
dependencies.each do |identifier|
|
13
|
+
name = identifier.to_s.split(".").last
|
14
|
+
add_dependency(name, identifier)
|
15
|
+
end
|
16
|
+
|
17
|
+
aliases.each do |name, identifier|
|
18
|
+
add_dependency(name, identifier)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
@map.inspect
|
24
|
+
end
|
25
|
+
|
26
|
+
def names
|
27
|
+
@map.keys
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_h
|
31
|
+
@map.dup.to_h
|
32
|
+
end
|
33
|
+
alias_method :to_hash, :to_h
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def add_dependency(name, identifier)
|
38
|
+
name = name.to_sym
|
39
|
+
raise DuplicateDependencyError, "name +#{name}+ is already used" if @map.key?(name)
|
40
|
+
@map[name] = identifier
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'dry/auto_inject/strategies'
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module AutoInject
|
5
|
+
class Injector
|
6
|
+
# @api private
|
7
|
+
attr_reader :container
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
attr_reader :strategy
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
def initialize(container, strategy)
|
14
|
+
@container = container
|
15
|
+
@strategy = strategy
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](*dependency_names)
|
19
|
+
strategy.new(container, *dependency_names)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'dry-container'
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module AutoInject
|
5
|
+
class Strategies
|
6
|
+
extend Dry::Container::Mixin
|
7
|
+
|
8
|
+
# @api public
|
9
|
+
def self.register_default(name, strategy)
|
10
|
+
register name, strategy
|
11
|
+
register :default, strategy
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'dry/auto_inject/strategies/args'
|
18
|
+
require 'dry/auto_inject/strategies/hash'
|
19
|
+
require 'dry/auto_inject/strategies/kwargs'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'dry/auto_inject/strategies/constructor'
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module AutoInject
|
5
|
+
class Strategies
|
6
|
+
# @api private
|
7
|
+
class Args < Constructor
|
8
|
+
private
|
9
|
+
|
10
|
+
def define_new(klass)
|
11
|
+
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
12
|
+
def self.new(*args)
|
13
|
+
names = #{dependency_map.inspect}
|
14
|
+
deps = names.values.map.with_index { |identifier, i| args[i] || container[identifier] }
|
15
|
+
super(*deps, *args[deps.size..-1])
|
16
|
+
end
|
17
|
+
RUBY
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_initialize(klass)
|
21
|
+
super_method = find_super(klass, :initialize)
|
22
|
+
|
23
|
+
if super_method.nil? || super_method.parameters.empty?
|
24
|
+
define_initialize_with_params
|
25
|
+
else
|
26
|
+
define_initialize_with_splat(super_method)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def define_initialize_with_params
|
31
|
+
initialize_args = dependency_map.names.join(', ')
|
32
|
+
|
33
|
+
instance_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
34
|
+
def initialize(#{initialize_args})
|
35
|
+
super()
|
36
|
+
#{dependency_map.names.map { |name| "@#{name} = #{name}" }.join("\n")}
|
37
|
+
end
|
38
|
+
RUBY
|
39
|
+
end
|
40
|
+
|
41
|
+
def define_initialize_with_splat(super_method)
|
42
|
+
super_params = if super_method.parameters.any? { |type, _| type == :rest }
|
43
|
+
'*args'
|
44
|
+
else
|
45
|
+
"*args[0..#{super_method.parameters.length - 1}]"
|
46
|
+
end
|
47
|
+
|
48
|
+
instance_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
49
|
+
def initialize(*args)
|
50
|
+
super(#{super_params})
|
51
|
+
#{dependency_map.names.map.with_index { |name, i| "@#{name} = args[#{i}]" }.join("\n")}
|
52
|
+
end
|
53
|
+
RUBY
|
54
|
+
end
|
55
|
+
|
56
|
+
def find_super(klass, method_name)
|
57
|
+
super_method = Dry::AutoInject.super_method(klass, method_name)
|
58
|
+
|
59
|
+
# Look upwards past `def foo(*)` methods until we get an explicit list of parameters
|
60
|
+
while super_method && super_method.parameters == [[:rest]]
|
61
|
+
super_method = Dry::AutoInject.super_method(super_method.owner, :initialize)
|
62
|
+
end
|
63
|
+
|
64
|
+
super_method
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
register :args, Args
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'dry/auto_inject/dependency_map'
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module AutoInject
|
5
|
+
class Strategies
|
6
|
+
class Constructor < Module
|
7
|
+
ClassMethods = Class.new(Module) do
|
8
|
+
def initialize(container)
|
9
|
+
super()
|
10
|
+
define_method(:container) { container }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
InstanceMethods = Class.new(Module)
|
15
|
+
|
16
|
+
attr_reader :container
|
17
|
+
attr_reader :dependency_map
|
18
|
+
attr_reader :instance_mod
|
19
|
+
attr_reader :class_mod
|
20
|
+
|
21
|
+
def initialize(container, *dependency_names)
|
22
|
+
@container = container
|
23
|
+
@dependency_map = DependencyMap.new(*dependency_names)
|
24
|
+
@instance_mod = InstanceMethods.new
|
25
|
+
@class_mod = ClassMethods.new(container)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
def included(klass)
|
30
|
+
define_readers
|
31
|
+
|
32
|
+
define_new(klass)
|
33
|
+
define_initialize(klass)
|
34
|
+
|
35
|
+
klass.send(:include, instance_mod)
|
36
|
+
klass.extend(class_mod)
|
37
|
+
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def define_readers
|
44
|
+
instance_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
45
|
+
attr_reader #{dependency_map.names.map { |name| ":#{name}" }.join(', ')}
|
46
|
+
RUBY
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def define_new(klass)
|
51
|
+
raise NotImplementedError, "must be implemented by a subclass"
|
52
|
+
end
|
53
|
+
|
54
|
+
def define_initialize(klass)
|
55
|
+
raise NotImplementedError, "must be implemented by a subclass"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'dry/auto_inject/strategies/constructor'
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module AutoInject
|
5
|
+
class Strategies
|
6
|
+
# @api private
|
7
|
+
class Hash < Constructor
|
8
|
+
private
|
9
|
+
|
10
|
+
def define_new(_klass)
|
11
|
+
class_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
12
|
+
def new(options = {})
|
13
|
+
names = #{dependency_map.inspect}
|
14
|
+
deps = names.each_with_object({}) { |(name, identifier), obj|
|
15
|
+
obj[name] = options[name] || container[identifier]
|
16
|
+
}.merge(options)
|
17
|
+
super(deps)
|
18
|
+
end
|
19
|
+
RUBY
|
20
|
+
end
|
21
|
+
|
22
|
+
def define_initialize(klass)
|
23
|
+
super_method = Dry::AutoInject.super_method(klass, :initialize)
|
24
|
+
super_params = super_method.nil? || super_method.parameters.empty? ? '' : 'options'
|
25
|
+
|
26
|
+
instance_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
27
|
+
def initialize(options)
|
28
|
+
super(#{super_params})
|
29
|
+
#{dependency_map.names.map { |name| "@#{name} = options[:#{name}]" }.join("\n")}
|
30
|
+
end
|
31
|
+
RUBY
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
register :hash, Hash
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'dry/auto_inject/strategies/constructor'
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module AutoInject
|
5
|
+
class Strategies
|
6
|
+
# @api private
|
7
|
+
class Kwargs < Constructor
|
8
|
+
private
|
9
|
+
|
10
|
+
def define_new(_klass)
|
11
|
+
class_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
12
|
+
def new(**args)
|
13
|
+
names = #{dependency_map.inspect}
|
14
|
+
deps = names.each_with_object({}) { |(name, identifier), obj|
|
15
|
+
obj[name] = args[name] || container[identifier]
|
16
|
+
}.merge(args)
|
17
|
+
super(**deps)
|
18
|
+
end
|
19
|
+
RUBY
|
20
|
+
end
|
21
|
+
|
22
|
+
def define_initialize(klass)
|
23
|
+
super_method = Dry::AutoInject.super_method(klass, :initialize)
|
24
|
+
|
25
|
+
if super_method.nil? || super_method.parameters.empty?
|
26
|
+
define_initialize_with_keywords
|
27
|
+
else
|
28
|
+
define_initialize_with_splat(super_method)
|
29
|
+
end
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def define_initialize_with_keywords
|
35
|
+
initialize_params = dependency_map.names.map { |name| "#{name}: nil" }.join(', ')
|
36
|
+
|
37
|
+
instance_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
38
|
+
def initialize(#{initialize_params})
|
39
|
+
super()
|
40
|
+
#{dependency_map.names.map { |name| "@#{name} = #{name}" }.join("\n")}
|
41
|
+
end
|
42
|
+
RUBY
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def define_initialize_with_splat(super_method)
|
47
|
+
super_kwarg_names = super_method.parameters.select { |type, _| [:key, :keyreq].include?(type) }.map(&:last)
|
48
|
+
super_params = super_kwarg_names.map { |name| "#{name}: args[:#{name}]" }.join(', ')
|
49
|
+
|
50
|
+
# Pass through any non-dependency args if the super method accepts `**args`
|
51
|
+
if super_method.parameters.any? { |type, _| type == :keyrest }
|
52
|
+
super_params += ', **args'
|
53
|
+
end
|
54
|
+
|
55
|
+
instance_mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
56
|
+
def initialize(**args)
|
57
|
+
super(#{super_params})
|
58
|
+
#{dependency_map.names.map { |name| "@#{name} = args[:#{name}]" }.join("\n")}
|
59
|
+
end
|
60
|
+
RUBY
|
61
|
+
self
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
register_default :kwargs, Kwargs
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-auto_inject
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dry-container
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.3.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.4
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,6 +87,14 @@ files:
|
|
73
87
|
- dry-auto_inject.gemspec
|
74
88
|
- lib/dry-auto_inject.rb
|
75
89
|
- lib/dry/auto_inject.rb
|
90
|
+
- lib/dry/auto_inject/builder.rb
|
91
|
+
- lib/dry/auto_inject/dependency_map.rb
|
92
|
+
- lib/dry/auto_inject/injector.rb
|
93
|
+
- lib/dry/auto_inject/strategies.rb
|
94
|
+
- lib/dry/auto_inject/strategies/args.rb
|
95
|
+
- lib/dry/auto_inject/strategies/constructor.rb
|
96
|
+
- lib/dry/auto_inject/strategies/hash.rb
|
97
|
+
- lib/dry/auto_inject/strategies/kwargs.rb
|
76
98
|
- lib/dry/auto_inject/version.rb
|
77
99
|
- rakelib/rubocop.rake
|
78
100
|
homepage: https://github.com/dryrb/dry-auto_inject
|
@@ -86,7 +108,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
108
|
requirements:
|
87
109
|
- - ">="
|
88
110
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
111
|
+
version: 2.0.0
|
90
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
113
|
requirements:
|
92
114
|
- - ">="
|
@@ -94,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
116
|
version: '0'
|
95
117
|
requirements: []
|
96
118
|
rubyforge_project:
|
97
|
-
rubygems_version: 2.
|
119
|
+
rubygems_version: 2.5.1
|
98
120
|
signing_key:
|
99
121
|
specification_version: 4
|
100
122
|
summary: Container-agnostic automatic constructor injection
|