dry-auto_inject 1.1.0 → 1.2.1
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/CHANGELOG.md +118 -85
- data/LICENSE +1 -1
- data/README.md +12 -13
- data/config/default.yml +21 -0
- data/dry-auto_inject.gemspec +20 -16
- data/lib/dry/auto_inject/method_parameters.rb +17 -10
- data/lib/dry/auto_inject/strategies/kwargs.rb +15 -9
- data/lib/dry/auto_inject/version.rb +1 -1
- data/lib/dry/auto_inject.rb +2 -1
- data/lib/dry-auto_inject.rb +6 -0
- data/lib/rubocop/cop/dry_auto_inject/dependency_order.rb +126 -0
- data/lib/rubocop/cop/dry_auto_inject/mixin.rb +163 -0
- data/lib/rubocop/cop/dry_auto_inject/redundant_alias.rb +68 -0
- data/lib/rubocop/dry-auto_inject.rb +3 -0
- data/lib/rubocop/dry_auto_inject/plugin.rb +36 -0
- data/lib/rubocop/dry_auto_inject.rb +5 -0
- metadata +62 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 853aca224dbd544893d1a4caeb49018aba110e1f4cfcd023f2f85667dc7d27ce
|
|
4
|
+
data.tar.gz: 0cf91111ef31cff7501f53777cfee05f2e5a40d415e8af8eeed351c75325f4cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b5c2b63eb20ed3cfb196485019f95562b0722ccabac0c459db8e7c93ed731bb0ced4061d7c067920972e0d732e6248980e677730098ea675593e9965ab1cd8c4
|
|
7
|
+
data.tar.gz: 7b8a64deb8484800b0c8836892ba346483ed33bd6dc2eae35c09bfefc7abe75e73843d520833f3daa212e4b55f512a0458a2a2d5a0cb506cb04fcce920674c32
|
data/CHANGELOG.md
CHANGED
|
@@ -1,110 +1,158 @@
|
|
|
1
|
-
|
|
1
|
+
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Break Versioning](https://www.taoensso.com/break-versioning).
|
|
7
|
+
|
|
8
|
+
## [1.2.1] - 2026-05-26
|
|
5
9
|
|
|
6
10
|
### Fixed
|
|
7
11
|
|
|
8
|
-
-
|
|
12
|
+
- Load cop classes when the RuboCop plugin is required, so offenses are
|
|
13
|
+
actually reported (@flash-gordon in #100)
|
|
9
14
|
|
|
15
|
+
[1.2.1]: https://github.com/dry-rb/dry-auto_inject/compare/v1.2.0...v1.2.1
|
|
10
16
|
|
|
11
|
-
[
|
|
17
|
+
## [1.2.0] - 2026-05-19
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
### Added
|
|
14
20
|
|
|
21
|
+
- Ship a `DryAutoInject/DependencyOrder` rubocop cop that enforces a configurable
|
|
22
|
+
order for dependencies inside `Import[...]` calls. Non-aliased deps are
|
|
23
|
+
emitted first, then aliased ones; within each section, deps are grouped by
|
|
24
|
+
the configured `Order` patterns and sorted alphabetically inside a group.
|
|
25
|
+
Supported pattern forms: `'*'` (catch-all, at most one and implicitly
|
|
26
|
+
appended), `'prefix.*'`, `/regex/flags`, or an exact path. The cop also
|
|
27
|
+
autocorrects. (@flash-gordon in #96)
|
|
28
|
+
|
|
29
|
+
Enable it from your `.rubocop.yml` using RuboCop's plugin system
|
|
30
|
+
(requires RuboCop 1.72+):
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
plugins:
|
|
34
|
+
- dry-auto_inject
|
|
35
|
+
|
|
36
|
+
DryAutoInject/DependencyOrder:
|
|
37
|
+
Enabled: true
|
|
38
|
+
InjectorModules: # Default is [Import, *::Import, Deps, *::Deps]
|
|
39
|
+
- Deps # exact constant
|
|
40
|
+
- "*::Deps" # match any namespace ending in `::Deps`
|
|
41
|
+
Order:
|
|
42
|
+
- "web.*"
|
|
43
|
+
- "*"
|
|
44
|
+
- "core.*"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- Ship a `DryAutoInject/RedundantAlias` rubocop cop that flags
|
|
48
|
+
`Import[foo: 'some.path.foo']`-style imports where the alias matches the
|
|
49
|
+
last segment of the path, since dry-auto_inject already derives the
|
|
50
|
+
dependency key from that segment. The cop autocorrects by promoting
|
|
51
|
+
redundant aliases to non-aliased deps, preserving the original quoting.
|
|
52
|
+
(@flash-gordon in #98)
|
|
15
53
|
|
|
16
54
|
### Fixed
|
|
17
55
|
|
|
18
|
-
-
|
|
56
|
+
- Ancestor parameter detection for smart kwarg forwarding is no longer obscured by injections in a parent class. (@alassek in #97)
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
19
59
|
|
|
60
|
+
- Update minimum Ruby version to 3.3. (@timriley)
|
|
20
61
|
|
|
21
|
-
[
|
|
62
|
+
[1.2.0]: https://github.com/dry-rb/dry-auto_inject/compare/v1.1.0...v1.2.0
|
|
22
63
|
|
|
23
|
-
## 1.
|
|
64
|
+
## [1.1.0] - 2025-01-07
|
|
24
65
|
|
|
66
|
+
### Fixed
|
|
25
67
|
|
|
26
|
-
|
|
68
|
+
- Update minimal ruby version to 3.1. (@flash-gordon)
|
|
27
69
|
|
|
28
|
-
|
|
29
|
-
- This version uses zeitwerk for autoloading (@flash-gordon)
|
|
70
|
+
[1.1.0]: https://github.com/dry-rb/dry-auto_inject/compare/v1.0.1...v1.1.0
|
|
30
71
|
|
|
31
|
-
[
|
|
72
|
+
## [1.0.1] - 2023-02-13
|
|
73
|
+
|
|
74
|
+
### Fixed
|
|
32
75
|
|
|
33
|
-
|
|
76
|
+
- Update passthrough parameters list to support ruby 3.2.1. (@hieuk09 in #88)
|
|
34
77
|
|
|
78
|
+
[1.0.1]: https://github.com/dry-rb/dry-auto_inject/compare/v1.0.0...v1.0.1
|
|
79
|
+
|
|
80
|
+
## [1.0.0] - 2022-11-18
|
|
35
81
|
|
|
36
82
|
### Changed
|
|
37
83
|
|
|
38
|
-
-
|
|
39
|
-
|
|
84
|
+
- This version is compatible with recently released dry-rb dependencies. (@flash-gordon)
|
|
85
|
+
- This version uses zeitwerk for autoloading. (@flash-gordon)
|
|
40
86
|
|
|
41
|
-
|
|
87
|
+
[1.0.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.9.0...v1.0.0
|
|
42
88
|
|
|
43
|
-
[
|
|
89
|
+
## [0.9.0] - 2022-01-26
|
|
44
90
|
|
|
45
|
-
|
|
91
|
+
### Changed
|
|
46
92
|
|
|
93
|
+
- [BREAKING] Support for ... was changed, now constructors with such signature are not considered
|
|
94
|
+
as pass-through because they can forward arguments to another method. (@flash-gordon in #78)
|
|
95
|
+
- [BREAKING] Support for 2.6 was dropped
|
|
96
|
+
|
|
97
|
+
[0.9.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.8.0...v0.9.0
|
|
98
|
+
|
|
99
|
+
## [0.8.0] - 2021-06-06
|
|
47
100
|
|
|
48
101
|
### Added
|
|
49
102
|
|
|
50
|
-
- Support For `...` passthrough-args (@ytaben)
|
|
103
|
+
- Support For `...` passthrough-args. (@ytaben)
|
|
51
104
|
|
|
52
105
|
### Fixed
|
|
53
106
|
|
|
54
|
-
- Constructors with kwargs strategy properly forward blocks to super (mintyfresh in
|
|
107
|
+
- Constructors with kwargs strategy properly forward blocks to super. (@mintyfresh in #68)
|
|
55
108
|
|
|
56
109
|
### Changed
|
|
57
110
|
|
|
58
111
|
- [BREAKING] Support for 2.4 and 2.5 was dropped
|
|
59
112
|
|
|
60
|
-
[
|
|
61
|
-
|
|
62
|
-
## 0.7.0 2019-12-28
|
|
113
|
+
[0.8.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.7.0...v0.8.0
|
|
63
114
|
|
|
115
|
+
## [0.7.0] - 2019-12-28
|
|
64
116
|
|
|
65
117
|
### Fixed
|
|
66
118
|
|
|
67
|
-
- Keyword warnings issued by Ruby 2.7 in certain contexts (flash-gordon)
|
|
119
|
+
- Keyword warnings issued by Ruby 2.7 in certain contexts. (@flash-gordon)
|
|
68
120
|
|
|
69
121
|
### Changed
|
|
70
122
|
|
|
71
123
|
- [BREAKING] Support for 2.3 was dropped
|
|
72
124
|
|
|
73
|
-
[
|
|
74
|
-
|
|
75
|
-
## 0.6.1 2019-04-16
|
|
125
|
+
[0.7.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.6.1...v0.7.0
|
|
76
126
|
|
|
127
|
+
## [0.6.1] - 2019-04-16
|
|
77
128
|
|
|
78
129
|
### Fixed
|
|
79
130
|
|
|
80
|
-
- Allow explicit injection of falsey values (timriley in
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
[Compare v0.6.0...v0.6.1](https://github.com/dry-rb/dry-auto_inject/compare/v0.6.0...v0.6.1)
|
|
131
|
+
- Allow explicit injection of falsey values. (@timriley in #58)
|
|
84
132
|
|
|
85
|
-
|
|
133
|
+
[0.6.1]: https://github.com/dry-rb/dry-auto_inject/compare/v0.6.0...v0.6.1
|
|
86
134
|
|
|
135
|
+
## [0.6.0] - 2018-11-29
|
|
87
136
|
|
|
88
137
|
### Added
|
|
89
138
|
|
|
90
|
-
- Enhanced support for integrating with existing constructors. The kwargs strategy will now pass dependencies up to the next constructor if it accepts an arbitrary number of arguments with `*args`. Note that this change may break existing code though we think it's unlikely to happen. If something doesn't work for you please report and we'll try to sort it out (flash-gordon + timriley in
|
|
139
|
+
- Enhanced support for integrating with existing constructors. The kwargs strategy will now pass dependencies up to the next constructor if it accepts an arbitrary number of arguments with `*args`. Note that this change may break existing code though we think it's unlikely to happen. If something doesn't work for you please report and we'll try to sort it out. (@flash-gordon + @timriley in #48)
|
|
91
140
|
|
|
92
141
|
### Fixed
|
|
93
142
|
|
|
94
|
-
- A couple of regressions were fixed along the way, see [#46](https://github.com/dry-rb/dry-auto_inject/issues/46) and [#49](https://github.com/dry-rb/dry-auto_inject/issues/49) (flash-gordon + timriley in
|
|
143
|
+
- A couple of regressions were fixed along the way, see [#46](https://github.com/dry-rb/dry-auto_inject/issues/46) and [#49](https://github.com/dry-rb/dry-auto_inject/issues/49). (@flash-gordon + @timriley in #48)
|
|
95
144
|
|
|
96
145
|
### Changed
|
|
97
146
|
|
|
98
147
|
- [BREAKING] 0.6.0 supports Ruby 2.3 and above. If you're on 2.3 keep in mind its EOL is scheduled at the end of March, 2019
|
|
99
148
|
|
|
100
|
-
[
|
|
101
|
-
|
|
102
|
-
## 0.5.0 2018-11-09
|
|
149
|
+
[0.6.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.5.0...v0.6.0
|
|
103
150
|
|
|
151
|
+
## [0.5.0] - 2018-11-09
|
|
104
152
|
|
|
105
153
|
### Changed
|
|
106
154
|
|
|
107
|
-
- Only assign `nil` dependency instance variables from generated `#initialize` if the instance variable has not been previously defined. This improves compatibility with objects initialized in non-conventional ways (see example below) (timriley in
|
|
155
|
+
- Only assign `nil` dependency instance variables from generated `#initialize` if the instance variable has not been previously defined. This improves compatibility with objects initialized in non-conventional ways (see example below). (@timriley in #47)
|
|
108
156
|
|
|
109
157
|
```ruby
|
|
110
158
|
module SomeFramework
|
|
@@ -136,72 +184,61 @@ as pass-through because they can forward arguments to another method (flash-gord
|
|
|
136
184
|
end
|
|
137
185
|
```
|
|
138
186
|
|
|
139
|
-
[
|
|
140
|
-
|
|
141
|
-
## 0.4.6 2018-03-27
|
|
187
|
+
[0.5.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.4.6...v0.5.0
|
|
142
188
|
|
|
189
|
+
## [0.4.6] - 2018-03-27
|
|
143
190
|
|
|
144
191
|
### Changed
|
|
145
192
|
|
|
146
|
-
- In injector-generated `#initialize` methods, set dependency instance variables before calling `super
|
|
193
|
+
- In injector-generated `#initialize` methods, set dependency instance variables before calling `super`. (@timriley)
|
|
147
194
|
|
|
148
|
-
[
|
|
149
|
-
|
|
150
|
-
## 0.4.5 2018-01-02
|
|
195
|
+
[0.4.6]: https://github.com/dry-rb/dry-auto_inject/compare/v0.4.5...v0.4.6
|
|
151
196
|
|
|
197
|
+
## [0.4.5] - 2018-01-02
|
|
152
198
|
|
|
153
199
|
### Added
|
|
154
200
|
|
|
155
|
-
- Improved handling of kwargs being passed to #initialize’s super method (timriley)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
[Compare v0.4.4...v0.4.5](https://github.com/dry-rb/dry-auto_inject/compare/v0.4.4...v0.4.5)
|
|
201
|
+
- Improved handling of kwargs being passed to #initialize’s super method. (@timriley)
|
|
159
202
|
|
|
160
|
-
|
|
203
|
+
[0.4.5]: https://github.com/dry-rb/dry-auto_inject/compare/v0.4.4...v0.4.5
|
|
161
204
|
|
|
205
|
+
## [0.4.4] - 2017-09-14
|
|
162
206
|
|
|
163
207
|
### Added
|
|
164
208
|
|
|
165
|
-
- Determine name for dependencies by splitting identifiers on any invalid local variable name characters (e.g. "/", "?", "!"), instead of splitting on dots only (raventid in
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
[Compare v0.4.3...v0.4.4](https://github.com/dry-rb/dry-auto_inject/compare/v0.4.3...v0.4.4)
|
|
209
|
+
- Determine name for dependencies by splitting identifiers on any invalid local variable name characters (e.g. "/", "?", "!"), instead of splitting on dots only. (@raventid in #39)
|
|
169
210
|
|
|
170
|
-
|
|
211
|
+
[0.4.4]: https://github.com/dry-rb/dry-auto_inject/compare/v0.4.3...v0.4.4
|
|
171
212
|
|
|
213
|
+
## [0.4.3] - 2017-05-27
|
|
172
214
|
|
|
173
215
|
### Added
|
|
174
216
|
|
|
175
|
-
- Push sequential arguments along with keywords in the kwargs strategy (hbda + vladra in
|
|
217
|
+
- Push sequential arguments along with keywords in the kwargs strategy. (@hbda + @vladra in #32)
|
|
176
218
|
|
|
219
|
+
[0.4.3]: https://github.com/dry-rb/dry-auto_inject/compare/v0.4.2...v0.4.3
|
|
177
220
|
|
|
178
|
-
[
|
|
179
|
-
|
|
180
|
-
## 0.4.2 2016-10-10
|
|
181
|
-
|
|
221
|
+
## [0.4.2] - 2016-10-10
|
|
182
222
|
|
|
183
223
|
### Fixed
|
|
184
224
|
|
|
185
|
-
- Fixed issue where injectors for different containers could not be used on different classes in an inheritance hierarchy (timriley in
|
|
186
|
-
|
|
225
|
+
- Fixed issue where injectors for different containers could not be used on different classes in an inheritance hierarchy. (@timriley in #31)
|
|
187
226
|
|
|
188
|
-
[
|
|
189
|
-
|
|
190
|
-
## 0.4.1 2016-08-14
|
|
227
|
+
[0.4.2]: https://github.com/dry-rb/dry-auto_inject/compare/v0.4.1...v0.4.2
|
|
191
228
|
|
|
229
|
+
## [0.4.1] - 2016-08-14
|
|
192
230
|
|
|
193
231
|
### Changed
|
|
194
232
|
|
|
195
|
-
- Loosened version dependency on dry-container (AMHOL)
|
|
196
|
-
|
|
197
|
-
[Compare v0.4.0...v0.4.1](https://github.com/dry-rb/dry-auto_inject/compare/v0.4.0...v0.4.1)
|
|
233
|
+
- Loosened version dependency on dry-container. (@AMHOL)
|
|
198
234
|
|
|
199
|
-
|
|
235
|
+
[0.4.1]: https://github.com/dry-rb/dry-auto_inject/compare/v0.4.0...v0.4.1
|
|
200
236
|
|
|
237
|
+
## [0.4.0] - 2016-07-26
|
|
201
238
|
|
|
202
239
|
### Added
|
|
203
240
|
|
|
204
|
-
- Support for strategy chaining, which is helpful in opting for alternatives to an application's normal strategy (timriley in
|
|
241
|
+
- Support for strategy chaining, which is helpful in opting for alternatives to an application's normal strategy. (@timriley in #25)
|
|
205
242
|
|
|
206
243
|
```ruby
|
|
207
244
|
# Define the application's injector with a non-default
|
|
@@ -220,16 +257,15 @@ as pass-through because they can forward arguments to another method (flash-gord
|
|
|
220
257
|
|
|
221
258
|
### Fixed
|
|
222
259
|
|
|
223
|
-
- Fixed issue with kwargs injectors used at multiple points in a class inheritance heirarchy (flash-gordon in
|
|
260
|
+
- Fixed issue with kwargs injectors used at multiple points in a class inheritance heirarchy. (@flash-gordon in #27)
|
|
224
261
|
|
|
225
262
|
### Changed
|
|
226
263
|
|
|
227
|
-
- Use a `BasicObject`-based environment for the injector builder API instead of the previous `define_singleton_method`-based approach, which had negative performance characteristics (timriley in
|
|
264
|
+
- Use a `BasicObject`-based environment for the injector builder API instead of the previous `define_singleton_method`-based approach, which had negative performance characteristics. (@timriley in #26)
|
|
228
265
|
|
|
229
|
-
[
|
|
230
|
-
|
|
231
|
-
## 0.3.0, 2016-06-02
|
|
266
|
+
[0.4.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.3.0...v0.4.0
|
|
232
267
|
|
|
268
|
+
## [0.3.0] - 2016-06-02
|
|
233
269
|
|
|
234
270
|
### Added
|
|
235
271
|
|
|
@@ -314,25 +350,22 @@ as pass-through because they can forward arguments to another method (flash-gord
|
|
|
314
350
|
- `kwargs` is the new default injection strategy
|
|
315
351
|
- Rubinius support is not available for the `kwargs` strategy (see [#18](https://github.com/dry-rb/dry-auto_inject/issues/18))
|
|
316
352
|
|
|
317
|
-
[
|
|
318
|
-
|
|
319
|
-
## 0.2.0 2016-02-09
|
|
353
|
+
[0.3.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.2.0...v0.3.0
|
|
320
354
|
|
|
355
|
+
## [0.2.0] - 2016-02-09
|
|
321
356
|
|
|
322
357
|
### Added
|
|
323
358
|
|
|
324
|
-
- Support for hashes as constructor arguments via `Import.hash` interface (solnic)
|
|
359
|
+
- Support for hashes as constructor arguments via `Import.hash` interface. (@solnic)
|
|
325
360
|
|
|
361
|
+
[0.2.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.1.0...v0.2.0
|
|
326
362
|
|
|
327
|
-
[
|
|
328
|
-
|
|
329
|
-
## 0.1.0 2015-11-12
|
|
363
|
+
## [0.1.0] - 2015-11-12
|
|
330
364
|
|
|
331
365
|
Changed interface from `Dry::AutoInject.new { container(some_container) }` to
|
|
332
366
|
|
|
367
|
+
[0.1.0]: https://github.com/dry-rb/dry-auto_inject/compare/v0.0.1...v0.1.0
|
|
333
368
|
|
|
334
|
-
[
|
|
335
|
-
|
|
336
|
-
## 0.0.1 2015-08-20
|
|
369
|
+
## [0.0.1] - 2015-08-20
|
|
337
370
|
|
|
338
371
|
First public release \o/
|
data/LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
<!---
|
|
1
|
+
<!--- This file is synced from hanakai-rb/repo-sync -->
|
|
2
2
|
|
|
3
|
-
[gem]: https://rubygems.org/gems/dry-auto_inject
|
|
4
3
|
[actions]: https://github.com/dry-rb/dry-auto_inject/actions
|
|
4
|
+
[chat]: https://discord.gg/naQApPAsZB
|
|
5
|
+
[forum]: https://discourse.hanamirb.org
|
|
6
|
+
[rubygem]: https://rubygems.org/gems/dry-auto_inject
|
|
5
7
|
|
|
6
|
-
# dry-auto_inject [][
|
|
8
|
+
# dry-auto_inject [][rubygem] [][actions]
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* [User documentation](https://dry-rb.org/gems/dry-auto_inject)
|
|
11
|
-
* [API documentation](http://rubydoc.info/gems/dry-auto_inject)
|
|
12
|
-
* [Forum](https://discourse.dry-rb.org)
|
|
13
|
-
|
|
14
|
-
## Supported Ruby versions
|
|
10
|
+
[][forum]
|
|
11
|
+
[][chat]
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
## Links
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
- [User documentation](https://dry-rb.org/gems/dry-auto_inject)
|
|
16
|
+
- [API documentation](http://rubydoc.info/gems/dry-auto_inject)
|
|
17
|
+
- [Forum](https://discourse.dry-rb.org)
|
|
20
18
|
|
|
21
19
|
## License
|
|
22
20
|
|
|
23
21
|
See `LICENSE` file.
|
|
22
|
+
|
data/config/default.yml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
DryAutoInject/DependencyOrder:
|
|
2
|
+
Description: 'Enforces a configurable order for dry-auto_inject `Import[...]` dependencies.'
|
|
3
|
+
Enabled: true
|
|
4
|
+
VersionAdded: '1.2'
|
|
5
|
+
InjectorModules:
|
|
6
|
+
- 'Import'
|
|
7
|
+
- '*::Import'
|
|
8
|
+
- 'Deps'
|
|
9
|
+
- '*::Deps'
|
|
10
|
+
Order:
|
|
11
|
+
- '*'
|
|
12
|
+
|
|
13
|
+
DryAutoInject/RedundantAlias:
|
|
14
|
+
Description: 'Flags dry-auto_inject imports whose hash key matches the last segment of the path.'
|
|
15
|
+
Enabled: true
|
|
16
|
+
VersionAdded: '1.2'
|
|
17
|
+
InjectorModules:
|
|
18
|
+
- 'Import'
|
|
19
|
+
- '*::Import'
|
|
20
|
+
- 'Deps'
|
|
21
|
+
- '*::Deps'
|
data/dry-auto_inject.gemspec
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
# This file is synced from hanakai-rb/repo-sync. To update it, edit repo-sync.yml.
|
|
4
4
|
|
|
5
5
|
lib = File.expand_path("lib", __dir__)
|
|
6
6
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
@@ -8,29 +8,33 @@ require "dry/auto_inject/version"
|
|
|
8
8
|
|
|
9
9
|
Gem::Specification.new do |spec|
|
|
10
10
|
spec.name = "dry-auto_inject"
|
|
11
|
-
spec.authors = ["
|
|
12
|
-
spec.email = ["
|
|
11
|
+
spec.authors = ["Hanakai team"]
|
|
12
|
+
spec.email = ["info@hanakai.org"]
|
|
13
13
|
spec.license = "MIT"
|
|
14
14
|
spec.version = Dry::AutoInject::VERSION.dup
|
|
15
15
|
|
|
16
16
|
spec.summary = "Container-agnostic automatic constructor injection"
|
|
17
17
|
spec.description = spec.summary
|
|
18
18
|
spec.homepage = "https://dry-rb.org/gems/dry-auto_inject"
|
|
19
|
-
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-auto_inject.gemspec",
|
|
20
|
-
|
|
21
|
-
spec.
|
|
22
|
-
spec.executables = []
|
|
19
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-auto_inject.gemspec", "lib/**/*", "config/**/*"]
|
|
20
|
+
spec.bindir = "exe"
|
|
21
|
+
spec.executables = Dir["exe/*"].map { |f| File.basename(f) }
|
|
23
22
|
spec.require_paths = ["lib"]
|
|
24
23
|
|
|
25
|
-
spec.
|
|
26
|
-
spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-auto_inject/blob/main/CHANGELOG.md"
|
|
27
|
-
spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-auto_inject"
|
|
28
|
-
spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-auto_inject/issues"
|
|
29
|
-
spec.metadata["rubygems_mfa_required"] = "true"
|
|
24
|
+
spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE"]
|
|
30
25
|
|
|
31
|
-
spec.
|
|
26
|
+
spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-auto_inject/blob/main/CHANGELOG.md"
|
|
27
|
+
spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-auto_inject"
|
|
28
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-auto_inject/issues"
|
|
29
|
+
spec.metadata["funding_uri"] = "https://github.com/sponsors/hanami"
|
|
30
|
+
spec.metadata["default_lint_roller_plugin"] = "RuboCop::DryAutoInject::Plugin"
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
spec.
|
|
32
|
+
spec.required_ruby_version = ">= 3.3"
|
|
33
|
+
|
|
34
|
+
spec.add_runtime_dependency "dry-core", "~> 1.1"
|
|
35
|
+
spec.add_runtime_dependency "zeitwerk", "~> 2.6"
|
|
36
|
+
spec.add_development_dependency "bundler"
|
|
37
|
+
spec.add_development_dependency "rake"
|
|
38
|
+
spec.add_development_dependency "rspec"
|
|
36
39
|
end
|
|
40
|
+
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "set"
|
|
4
|
-
|
|
5
3
|
module Dry
|
|
6
4
|
module AutoInject
|
|
7
5
|
# @api private
|
|
8
6
|
class MethodParameters
|
|
9
|
-
PASS_THROUGH = [
|
|
10
|
-
[%i[rest]],
|
|
11
|
-
[%i[rest], %i[keyrest]],
|
|
12
|
-
[%i[rest *]],
|
|
13
|
-
[%i[rest *], %i[keyrest **]]
|
|
14
|
-
].freeze
|
|
15
|
-
|
|
16
7
|
def self.of(obj, name)
|
|
17
8
|
::Enumerator.new do |y|
|
|
18
9
|
begin
|
|
@@ -61,7 +52,23 @@ module Dry
|
|
|
61
52
|
|
|
62
53
|
def length = parameters.length
|
|
63
54
|
|
|
64
|
-
def pass_through?
|
|
55
|
+
def pass_through?
|
|
56
|
+
return false if parameters.empty?
|
|
57
|
+
return true if parameters.any? { |param| param in [:keyrest, :__auto_inject_kwargs__] }
|
|
58
|
+
|
|
59
|
+
parameters.all? do |param|
|
|
60
|
+
case param
|
|
61
|
+
in [:rest, :*] | [:keyrest, :**]
|
|
62
|
+
true
|
|
63
|
+
in [:rest | :req | :opt | :keyrest | :keyreq | :key | :block, _]
|
|
64
|
+
false
|
|
65
|
+
in [:nokey]
|
|
66
|
+
false
|
|
67
|
+
else
|
|
68
|
+
true
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
65
72
|
|
|
66
73
|
EMPTY = new([])
|
|
67
74
|
end
|
|
@@ -23,8 +23,10 @@ module Dry
|
|
|
23
23
|
|
|
24
24
|
def define_initialize(klass)
|
|
25
25
|
super_parameters = MethodParameters.of(klass, :initialize).each do |ps|
|
|
26
|
-
# Look upwards past
|
|
27
|
-
#
|
|
26
|
+
# Look upwards past methods that only forward arguments, stopping at the
|
|
27
|
+
# first instance of explicit parameters. So `foo(**kwargs)` is
|
|
28
|
+
# skipped, but `foo(bar:, **kwargs)` is not. `foo(...)` is used by ROM as
|
|
29
|
+
# a delegation pattern, so it is not skipped.
|
|
28
30
|
break ps unless ps.pass_through?
|
|
29
31
|
end
|
|
30
32
|
|
|
@@ -37,15 +39,18 @@ module Dry
|
|
|
37
39
|
self
|
|
38
40
|
end
|
|
39
41
|
|
|
42
|
+
# rubocop:disable Lint/UnderscorePrefixedVariableName
|
|
40
43
|
def define_initialize_with_keywords(super_parameters)
|
|
41
44
|
assign_dependencies = method(:assign_dependencies)
|
|
42
45
|
slice_kwargs = method(:slice_kwargs)
|
|
43
46
|
|
|
44
47
|
instance_mod.class_exec do
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
# The choice of `__auto_inject_kwargs__` here is intentional, and used
|
|
49
|
+
# by MethodParameters#pass_through? to detect an injected initialize.
|
|
50
|
+
define_method :initialize do |**__auto_inject_kwargs__, &block|
|
|
51
|
+
assign_dependencies.(__auto_inject_kwargs__, self)
|
|
47
52
|
|
|
48
|
-
super_kwargs = slice_kwargs.(
|
|
53
|
+
super_kwargs = slice_kwargs.(__auto_inject_kwargs__, super_parameters)
|
|
49
54
|
|
|
50
55
|
if super_kwargs.any?
|
|
51
56
|
super(**super_kwargs, &block)
|
|
@@ -61,13 +66,13 @@ module Dry
|
|
|
61
66
|
slice_kwargs = method(:slice_kwargs)
|
|
62
67
|
|
|
63
68
|
instance_mod.class_exec do
|
|
64
|
-
define_method :initialize do |*args, **
|
|
65
|
-
assign_dependencies.(
|
|
69
|
+
define_method :initialize do |*args, **__auto_inject_kwargs__, &block|
|
|
70
|
+
assign_dependencies.(__auto_inject_kwargs__, self)
|
|
66
71
|
|
|
67
72
|
if super_parameters.splat?
|
|
68
|
-
super(*args, **
|
|
73
|
+
super(*args, **__auto_inject_kwargs__, &block)
|
|
69
74
|
else
|
|
70
|
-
super_kwargs = slice_kwargs.(
|
|
75
|
+
super_kwargs = slice_kwargs.(__auto_inject_kwargs__, super_parameters)
|
|
71
76
|
|
|
72
77
|
if super_kwargs.any?
|
|
73
78
|
super(*args, **super_kwargs, &block)
|
|
@@ -78,6 +83,7 @@ module Dry
|
|
|
78
83
|
end
|
|
79
84
|
end
|
|
80
85
|
end
|
|
86
|
+
# rubocop:enable Lint/UnderscorePrefixedVariableName
|
|
81
87
|
|
|
82
88
|
def assign_dependencies(kwargs, destination)
|
|
83
89
|
dependency_map.names.each do |name|
|
data/lib/dry/auto_inject.rb
CHANGED
data/lib/dry-auto_inject.rb
CHANGED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "mixin"
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Cop
|
|
7
|
+
module DryAutoInject
|
|
8
|
+
# Enforces a configurable order for dry-auto_inject `Import[...]` deps.
|
|
9
|
+
#
|
|
10
|
+
# Non-aliased deps are emitted first, then aliased deps. Within each
|
|
11
|
+
# section, deps are grouped by matching the configured `Order` patterns
|
|
12
|
+
# and sorted alphabetically inside a group. Each pattern can be:
|
|
13
|
+
#
|
|
14
|
+
# - `'*'` — catch-all (at most one; implicitly appended)
|
|
15
|
+
# - `'prefix.*'` — prefix wildcard (matches `prefix` and `prefix.*`)
|
|
16
|
+
# - `'/regex/flags'` — regex matched against the dep path
|
|
17
|
+
# - otherwise — exact path match
|
|
18
|
+
#
|
|
19
|
+
# If `Order` is empty or omits `'*'`, a catch-all `'*'` group is appended
|
|
20
|
+
# implicitly so unmatched deps still have a home.
|
|
21
|
+
#
|
|
22
|
+
# Specific patterns take priority over the `*` catch-all regardless of
|
|
23
|
+
# their position in `Order`.
|
|
24
|
+
#
|
|
25
|
+
# @example Order: ['web.*', '*', 'core.*']
|
|
26
|
+
# # bad
|
|
27
|
+
# include Import[
|
|
28
|
+
# 'core.db',
|
|
29
|
+
# 'web.router',
|
|
30
|
+
# ]
|
|
31
|
+
#
|
|
32
|
+
# # good
|
|
33
|
+
# include Import[
|
|
34
|
+
# 'web.router',
|
|
35
|
+
# 'core.db',
|
|
36
|
+
# ]
|
|
37
|
+
#
|
|
38
|
+
# @example Order: ['/\A[^.]+\z/', '*'] — group dotless deps first
|
|
39
|
+
# include Import[
|
|
40
|
+
# 'logger',
|
|
41
|
+
# 'core.db',
|
|
42
|
+
# ]
|
|
43
|
+
class DependencyOrder < Base
|
|
44
|
+
extend AutoCorrector
|
|
45
|
+
include Mixin
|
|
46
|
+
|
|
47
|
+
MSG = "Dependencies are not in the configured order."
|
|
48
|
+
|
|
49
|
+
def initialize(config = nil, options = nil)
|
|
50
|
+
super
|
|
51
|
+
@parsed_order = build_parsed_order
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def on_send(node)
|
|
55
|
+
return unless injector_call?(node)
|
|
56
|
+
|
|
57
|
+
deps = parse_injector_deps(node)
|
|
58
|
+
return if deps.nil?
|
|
59
|
+
|
|
60
|
+
order = parsed_order
|
|
61
|
+
current = deps[:non_aliased] + deps[:aliased]
|
|
62
|
+
sorted = [deps[:non_aliased], deps[:aliased]].flat_map { |group|
|
|
63
|
+
group_and_sort(group, order) { |d| d[:path] }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return if current == sorted
|
|
67
|
+
|
|
68
|
+
add_offense(node, message: MSG) do |corrector|
|
|
69
|
+
replace_injector_content(corrector, node, sorted)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
attr_reader :parsed_order
|
|
76
|
+
|
|
77
|
+
def build_parsed_order
|
|
78
|
+
raw = Array(cop_config["Order"]).dup
|
|
79
|
+
|
|
80
|
+
if raw.count("*") > 1
|
|
81
|
+
raise "#{self.class.badge}: `Order` may contain at most one '*' entry " \
|
|
82
|
+
"(got #{raw.inspect})"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
raw << "*" unless raw.include?("*")
|
|
86
|
+
raw.each { |pat| validate_regex_pattern!(pat) if pat.start_with?("/") }
|
|
87
|
+
raw
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def validate_regex_pattern!(pat)
|
|
91
|
+
return if parse_regex_entry(pat)
|
|
92
|
+
|
|
93
|
+
raise "#{self.class.badge}: invalid regex in `Order` entry #{pat.inspect}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def group_and_sort(deps, order, &)
|
|
97
|
+
groups = ::Hash.new { |h, k| h[k] = [] }
|
|
98
|
+
|
|
99
|
+
# Specific patterns take priority over the `*` catch-all regardless
|
|
100
|
+
# of their position in `Order`.
|
|
101
|
+
specific_patterns = order.reject { |p| p == "*" }
|
|
102
|
+
|
|
103
|
+
deps.each do |d|
|
|
104
|
+
pat = specific_patterns.find { |p| match_pattern?(d[:path], p) } || "*"
|
|
105
|
+
groups[pat] << d
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
order.flat_map { |p| groups[p].sort_by(&) }
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def match_pattern?(path, pattern)
|
|
112
|
+
return true if pattern == "*"
|
|
113
|
+
|
|
114
|
+
if pattern.start_with?("/")
|
|
115
|
+
parse_regex_entry(pattern)&.match?(path)
|
|
116
|
+
elsif pattern.end_with?(".*")
|
|
117
|
+
prefix = pattern[...-2]
|
|
118
|
+
path == prefix || path.start_with?("#{prefix}.")
|
|
119
|
+
else
|
|
120
|
+
path == pattern
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/core"
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Cop
|
|
7
|
+
module DryAutoInject
|
|
8
|
+
# Shared helpers for cops that inspect `Import[...]`-style calls produced
|
|
9
|
+
# by dry-auto_inject.
|
|
10
|
+
module Mixin
|
|
11
|
+
include ::Dry::Core::Constants
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def injector_call?(node)
|
|
16
|
+
return false unless node.send_type?
|
|
17
|
+
return false unless node.method?(:[])
|
|
18
|
+
|
|
19
|
+
receiver = node.receiver
|
|
20
|
+
return false unless receiver&.const_type?
|
|
21
|
+
|
|
22
|
+
match_injector_module?(receiver)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def match_injector_module?(const_node)
|
|
26
|
+
full = const_fullname(const_node)
|
|
27
|
+
clean = full.sub(/\A::/, "")
|
|
28
|
+
|
|
29
|
+
Array(cop_config["InjectorModules"]).any? do |entry|
|
|
30
|
+
match_injector_entry?(entry.to_s, full, clean)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Entry formats:
|
|
35
|
+
# - `/pattern/flags` — regex literal, matched against `clean`
|
|
36
|
+
# - `*::Name` — last segment match with any prefix (incl. empty)
|
|
37
|
+
# - otherwise — exact match on the full or leading-`::`-stripped path
|
|
38
|
+
def match_injector_entry?(entry, full, clean)
|
|
39
|
+
if entry.start_with?("/")
|
|
40
|
+
regex = parse_regex_entry(entry)
|
|
41
|
+
return false unless regex
|
|
42
|
+
|
|
43
|
+
regex.match?(clean)
|
|
44
|
+
elsif entry.start_with?("*::")
|
|
45
|
+
suffix = entry[3..]
|
|
46
|
+
clean == suffix || clean.end_with?("::#{suffix}")
|
|
47
|
+
else
|
|
48
|
+
entry == full || entry == clean
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns a Regexp for a `/pattern/flags` literal, or nil if the
|
|
53
|
+
# string is not a regex literal or the pattern is invalid.
|
|
54
|
+
def parse_regex_entry(str)
|
|
55
|
+
m = str.match(%r{\A/(.*)/([imx]*)\z}m)
|
|
56
|
+
return nil unless m
|
|
57
|
+
|
|
58
|
+
opts = 0
|
|
59
|
+
opts |= ::Regexp::IGNORECASE if m[2].include?("i")
|
|
60
|
+
opts |= ::Regexp::MULTILINE if m[2].include?("m")
|
|
61
|
+
opts |= ::Regexp::EXTENDED if m[2].include?("x")
|
|
62
|
+
::Regexp.new(m[1], opts)
|
|
63
|
+
rescue ::RegexpError
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def const_fullname(const_node)
|
|
68
|
+
parts = []
|
|
69
|
+
current = const_node
|
|
70
|
+
|
|
71
|
+
while current
|
|
72
|
+
if current.const_type?
|
|
73
|
+
parts.unshift(current.children[1].to_s)
|
|
74
|
+
current = current.children[0]
|
|
75
|
+
elsif current.cbase_type?
|
|
76
|
+
parts.unshift("")
|
|
77
|
+
current = nil
|
|
78
|
+
else
|
|
79
|
+
return ""
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
parts.join("::")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Parses the arguments of an `Import[...]` call into a structured form.
|
|
87
|
+
# Returns nil if any argument is not a plain string or symbol-keyed/string-valued pair.
|
|
88
|
+
def parse_injector_deps(node)
|
|
89
|
+
args = node.arguments
|
|
90
|
+
return nil if args.empty?
|
|
91
|
+
|
|
92
|
+
hash_arg = args.last if args.last.hash_type?
|
|
93
|
+
string_nodes = hash_arg ? args[...-1] : args
|
|
94
|
+
|
|
95
|
+
non_aliased = parse_non_aliased_deps(string_nodes)
|
|
96
|
+
aliased = parse_aliased_deps(hash_arg)
|
|
97
|
+
return nil if non_aliased.nil? || aliased.nil?
|
|
98
|
+
|
|
99
|
+
{non_aliased:, aliased:}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def parse_non_aliased_deps(nodes)
|
|
103
|
+
return nil unless nodes.all?(&:str_type?)
|
|
104
|
+
|
|
105
|
+
nodes.map { |arg| {node: arg, alias: nil, path: arg.value} }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def parse_aliased_deps(hash_arg)
|
|
109
|
+
return EMPTY_ARRAY unless hash_arg
|
|
110
|
+
return nil unless hash_arg.pairs.all? { |p| p.key.sym_type? && p.value.str_type? }
|
|
111
|
+
|
|
112
|
+
hash_arg.pairs.map { |p| {node: p, alias: p.key.value.to_s, path: p.value.value} }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def format_dep(dep)
|
|
116
|
+
node = dep[:node]
|
|
117
|
+
if dep[:alias]
|
|
118
|
+
"#{dep[:alias]}: #{node.value.source}"
|
|
119
|
+
else
|
|
120
|
+
node.source
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def line_indent_col(node)
|
|
125
|
+
line = node.source_range.source_line
|
|
126
|
+
line.index(/\S/) || node.source_range.column
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def item_indent_spaces(node)
|
|
130
|
+
args = node.arguments
|
|
131
|
+
|
|
132
|
+
if args.any? && args.first.source_range.line > node.source_range.line
|
|
133
|
+
indent(args.first.source_range.column)
|
|
134
|
+
else
|
|
135
|
+
indent(line_indent_col(node) + 2)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def indent(width)
|
|
140
|
+
" " * width
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def render_deps(node, deps)
|
|
144
|
+
if node.multiline?
|
|
145
|
+
inner_indent = item_indent_spaces(node)
|
|
146
|
+
close_indent = indent(line_indent_col(node))
|
|
147
|
+
lines = deps.map { |d| "#{inner_indent}#{format_dep(d)}," }
|
|
148
|
+
"\n#{lines.join("\n")}\n#{close_indent}"
|
|
149
|
+
else
|
|
150
|
+
deps.map { |d| format_dep(d) }.join(", ")
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def replace_injector_content(corrector, node, deps)
|
|
155
|
+
selector = node.loc.selector
|
|
156
|
+
return unless selector&.source&.start_with?("[")
|
|
157
|
+
|
|
158
|
+
corrector.replace(selector.adjust(begin_pos: 1, end_pos: -1), render_deps(node, deps))
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "mixin"
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Cop
|
|
7
|
+
module DryAutoInject
|
|
8
|
+
# Flags dry-auto_inject imports whose hash key matches the last segment
|
|
9
|
+
# of the path, since dry-auto_inject already derives the dependency name
|
|
10
|
+
# from that segment.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# # bad
|
|
14
|
+
# include Import[foo: 'some.path.foo']
|
|
15
|
+
#
|
|
16
|
+
# # good
|
|
17
|
+
# include Import['some.path.foo']
|
|
18
|
+
class RedundantAlias < Base
|
|
19
|
+
extend AutoCorrector
|
|
20
|
+
include Mixin
|
|
21
|
+
|
|
22
|
+
MSG =
|
|
23
|
+
"Redundant alias `%<alias_name>s:` — dependency key is derived from " \
|
|
24
|
+
"the last segment of `'%<path>s'`."
|
|
25
|
+
|
|
26
|
+
def on_send(node)
|
|
27
|
+
return unless injector_call?(node)
|
|
28
|
+
|
|
29
|
+
deps = parse_injector_deps(node)
|
|
30
|
+
return if deps.nil?
|
|
31
|
+
|
|
32
|
+
redundant = deps[:aliased].select { |d| d[:alias] == d[:path].split(".").last }
|
|
33
|
+
return if redundant.empty?
|
|
34
|
+
|
|
35
|
+
canonical = promote_redundant_aliases(deps)
|
|
36
|
+
|
|
37
|
+
redundant.each_with_index do |dep, i|
|
|
38
|
+
add_offense(
|
|
39
|
+
dep[:node],
|
|
40
|
+
message: format(MSG, alias_name: dep[:alias], path: dep[:path])
|
|
41
|
+
) do |corrector|
|
|
42
|
+
next unless i.zero?
|
|
43
|
+
|
|
44
|
+
replace_injector_content(corrector, node, canonical)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def promote_redundant_aliases(deps)
|
|
52
|
+
non_aliased = deps[:non_aliased].dup
|
|
53
|
+
aliased = []
|
|
54
|
+
|
|
55
|
+
deps[:aliased].each do |d|
|
|
56
|
+
if d[:alias] == d[:path].split(".").last
|
|
57
|
+
non_aliased << {node: d[:node].value, alias: nil, path: d[:path]}
|
|
58
|
+
else
|
|
59
|
+
aliased << d
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
non_aliased + aliased
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lint_roller"
|
|
4
|
+
|
|
5
|
+
require "dry/auto_inject/version"
|
|
6
|
+
require_relative "../cop/dry_auto_inject/dependency_order"
|
|
7
|
+
require_relative "../cop/dry_auto_inject/redundant_alias"
|
|
8
|
+
|
|
9
|
+
module RuboCop
|
|
10
|
+
module DryAutoInject
|
|
11
|
+
class Plugin < ::LintRoller::Plugin
|
|
12
|
+
def about
|
|
13
|
+
::LintRoller::About.new(
|
|
14
|
+
name: "dry-auto_inject",
|
|
15
|
+
version: ::Dry::AutoInject::VERSION,
|
|
16
|
+
homepage: "https://hanakai.org/learn/dry/dry-auto_inject",
|
|
17
|
+
description: "RuboCop cops for enforcing dry-auto_inject conventions."
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def supported?(context)
|
|
22
|
+
context.engine == :rubocop
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def rules(_context)
|
|
26
|
+
project_root = ::Pathname.new(__dir__).join("../../..")
|
|
27
|
+
|
|
28
|
+
::LintRoller::Rules.new(
|
|
29
|
+
type: :path,
|
|
30
|
+
config_format: :rubocop,
|
|
31
|
+
value: project_root.join("config", "default.yml")
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dry-auto_inject
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1
|
|
4
|
+
version: 1.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
bindir: bin
|
|
7
|
+
- Hanakai team
|
|
8
|
+
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: dry-core
|
|
@@ -38,16 +37,62 @@ dependencies:
|
|
|
38
37
|
- - "~>"
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
39
|
version: '2.6'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: bundler
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rake
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: rspec
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
41
82
|
description: Container-agnostic automatic constructor injection
|
|
42
83
|
email:
|
|
43
|
-
-
|
|
84
|
+
- info@hanakai.org
|
|
44
85
|
executables: []
|
|
45
86
|
extensions: []
|
|
46
|
-
extra_rdoc_files:
|
|
87
|
+
extra_rdoc_files:
|
|
88
|
+
- CHANGELOG.md
|
|
89
|
+
- LICENSE
|
|
90
|
+
- README.md
|
|
47
91
|
files:
|
|
48
92
|
- CHANGELOG.md
|
|
49
93
|
- LICENSE
|
|
50
94
|
- README.md
|
|
95
|
+
- config/default.yml
|
|
51
96
|
- dry-auto_inject.gemspec
|
|
52
97
|
- lib/dry-auto_inject.rb
|
|
53
98
|
- lib/dry/auto_inject.rb
|
|
@@ -61,16 +106,21 @@ files:
|
|
|
61
106
|
- lib/dry/auto_inject/strategies/hash.rb
|
|
62
107
|
- lib/dry/auto_inject/strategies/kwargs.rb
|
|
63
108
|
- lib/dry/auto_inject/version.rb
|
|
109
|
+
- lib/rubocop/cop/dry_auto_inject/dependency_order.rb
|
|
110
|
+
- lib/rubocop/cop/dry_auto_inject/mixin.rb
|
|
111
|
+
- lib/rubocop/cop/dry_auto_inject/redundant_alias.rb
|
|
112
|
+
- lib/rubocop/dry-auto_inject.rb
|
|
113
|
+
- lib/rubocop/dry_auto_inject.rb
|
|
114
|
+
- lib/rubocop/dry_auto_inject/plugin.rb
|
|
64
115
|
homepage: https://dry-rb.org/gems/dry-auto_inject
|
|
65
116
|
licenses:
|
|
66
117
|
- MIT
|
|
67
118
|
metadata:
|
|
68
|
-
allowed_push_host: https://rubygems.org
|
|
69
119
|
changelog_uri: https://github.com/dry-rb/dry-auto_inject/blob/main/CHANGELOG.md
|
|
70
120
|
source_code_uri: https://github.com/dry-rb/dry-auto_inject
|
|
71
121
|
bug_tracker_uri: https://github.com/dry-rb/dry-auto_inject/issues
|
|
72
|
-
|
|
73
|
-
|
|
122
|
+
funding_uri: https://github.com/sponsors/hanami
|
|
123
|
+
default_lint_roller_plugin: RuboCop::DryAutoInject::Plugin
|
|
74
124
|
rdoc_options: []
|
|
75
125
|
require_paths:
|
|
76
126
|
- lib
|
|
@@ -78,15 +128,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
78
128
|
requirements:
|
|
79
129
|
- - ">="
|
|
80
130
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: '3.
|
|
131
|
+
version: '3.3'
|
|
82
132
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
133
|
requirements:
|
|
84
134
|
- - ">="
|
|
85
135
|
- !ruby/object:Gem::Version
|
|
86
136
|
version: '0'
|
|
87
137
|
requirements: []
|
|
88
|
-
rubygems_version: 3.
|
|
89
|
-
signing_key:
|
|
138
|
+
rubygems_version: 3.6.9
|
|
90
139
|
specification_version: 4
|
|
91
140
|
summary: Container-agnostic automatic constructor injection
|
|
92
141
|
test_files: []
|