rubocop-prefer_it_parameter 1.0.0 → 1.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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +42 -0
- data/config/default.yml +1 -0
- data/lib/rubocop/cop/style/prefer_it_parameter.rb +115 -16
- data/lib/rubocop/prefer_it_parameter/version.rb +1 -1
- data/sig/rubocop/cop/style/prefer_it_parameter.rbs +74 -9
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a654f707a32decb9fe04e213f80d731587b30ca23daa159fabcf6b34d7ce1b9c
|
|
4
|
+
data.tar.gz: d3e5ba34a8f33a1d1064d1f2f7c7d0d276b90e94b01fff3ef35bcd433f695c99
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b35242ffe25304f9790f90d9ad875529d07c0522ef9bf8d82ea3ff76d815eeb2cd864ab0e06a8bd0a8a821d255deb60b9df74e776b7b2342ba4b0be654306efa
|
|
7
|
+
data.tar.gz: 70af29593bdb22415d82812c08323d353e8c14d1447ea4c3d2c31f5715288e3dfd1c1eee72be7caccd8679fd7a3f2bcfe55cb144b48f70ad0dff10d41c71ab96
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.1.0] - 2026-09-07
|
|
4
|
+
|
|
5
|
+
- `Style/PreferItParameter`: recognize RSpec's custom matcher DSL (`RSpec::Matchers.define`)
|
|
6
|
+
as a built-in exception, alongside `lambda`/`proc`/`Proc.new`/`define_method`/
|
|
7
|
+
`define_singleton_method`; these are always checked and cannot be disabled.
|
|
8
|
+
- `Style/PreferItParameter`: add the `IgnoredBlockContexts` config option, so a project
|
|
9
|
+
can name its own such unsafe blocks on top of the built-ins above. As part of this,
|
|
10
|
+
the built-in `Proc.new` check now matches by exact receiver source text rather than
|
|
11
|
+
resolved constant name, so a `Proc` reached through another namespace is no longer
|
|
12
|
+
recognized.
|
|
13
|
+
|
|
3
14
|
## [1.0.0] - 2026-08-05
|
|
4
15
|
|
|
5
16
|
Initial release.
|
data/README.md
CHANGED
|
@@ -70,6 +70,47 @@ A block is left alone when it:
|
|
|
70
70
|
- references a local variable named `it` from an enclosing scope, or assigns to `it`
|
|
71
71
|
- already names its argument `it` — dropping it would revive an `it` from an enclosing scope (`Style/ItAssignment` forbids the name instead)
|
|
72
72
|
- defines a callable or a method — `->(x) { }`, `lambda`, `proc`, `Proc.new`, `define_method`, `define_singleton_method` — since the parameter list is part of its API and `it` drops the parameter name
|
|
73
|
+
- is nested inside RSpec's custom matcher DSL (`RSpec::Matchers.define`) as `match`, `match_when_negated`, `match_unless_raises`, `chain`, `failure_message`, `failure_message_when_negated` or `description` — these blocks are turned into actual methods internally, where `it`'s implicit binding does not reliably survive (see below)
|
|
74
|
+
- matches a project-specific entry in `IgnoredBlockContexts` (see below)
|
|
75
|
+
|
|
76
|
+
The `Proc.new`/`lambda`/etc. and RSpec cases above are built into the cop and always checked — they cannot be turned off. `IgnoredBlockContexts` is how a project adds its own such cases on top of them.
|
|
77
|
+
|
|
78
|
+
#### `IgnoredBlockContexts`
|
|
79
|
+
|
|
80
|
+
A block can be unsafe to convert for reasons specific to how it's used, not just because of what method it's passed to — this is exactly why RSpec's matcher DSL and `Proc.new` are already built-in exceptions above. `IgnoredBlockContexts` lets a project name its *own* such cases the same way, each scoped to the call it's nested inside (or, for `Proc.new`-like cases, matched wherever it's called), so a generic method name doesn't suppress the check on unrelated code.
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
# bad
|
|
84
|
+
RSpec::Matchers.define :be_valid_foo do
|
|
85
|
+
match { it.is_a?(Foo) && it.valid? }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# good
|
|
89
|
+
RSpec::Matchers.define :be_valid_foo do
|
|
90
|
+
match { |actual| actual.is_a?(Foo) && actual.valid? }
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`IgnoredBlockContexts` is empty by default. The built-in cases above are not stored in this config option at all — they're checked independently — so setting `IgnoredBlockContexts` in your `.rubocop.yml` only *adds* entries; it can never disable a built-in case:
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
Style/PreferItParameter:
|
|
98
|
+
IgnoredBlockContexts:
|
|
99
|
+
OurDsl.define_matcher:
|
|
100
|
+
- our_custom_dsl_method
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
A block named this way is only ignored when it's nested inside the matching enclosing call — so `our_custom_dsl_method { |x| x.foo }` written anywhere else is unaffected and still converted, even though the method name is the same. This is what keeps a generic name from silently suppressing the check on unrelated code.
|
|
104
|
+
|
|
105
|
+
An enclosing call written without a receiver (`define_matcher:` instead of `OurDsl.define_matcher:`) only matches a bare call with no receiver at all. Write `*.define_matcher:` to match regardless of receiver instead — the same way `lambda` or `define_method` are matched in the exceptions list above. A value of `nil` (an entry with nothing under it) means the call itself is unsafe wherever it appears, with no nesting required — this is how the built-in `Proc.new` case works internally:
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
Style/PreferItParameter:
|
|
109
|
+
IgnoredBlockContexts:
|
|
110
|
+
"*.our_dsl_method": # any receiver, no nesting required
|
|
111
|
+
OurDsl.define_matcher: # this exact receiver, blocks nested inside it
|
|
112
|
+
- our_custom_dsl_method
|
|
113
|
+
```
|
|
73
114
|
|
|
74
115
|
## Related cops
|
|
75
116
|
|
|
@@ -105,6 +146,7 @@ The autocorrection is marked unsafe (`SafeAutoCorrect: false`), so `rubocop -a`
|
|
|
105
146
|
- A local variable or parameter named `it` takes precedence over the block parameter. The cop skips a block that references such a variable, but it cannot detect one that the block never references — there the autocorrection silently changes what the block sees. Enabling `Style/ItAssignment` is therefore a prerequisite.
|
|
106
147
|
- `Proc#parameters` loses the argument name: `[[:opt, :x]]` becomes `[[:opt]]`. Blocks that define a callable or a method are excluded for this reason, but a block captured with `&block` and introspected elsewhere is still affected.
|
|
107
148
|
- `binding.local_variable_get(:x)` inside the block stops working.
|
|
149
|
+
- A block can be unsafe to convert for reasons specific to its own context — e.g. a library that turns it into an actual method internally may stop passing it an argument at all. RSpec's custom matcher DSL is built in for this reason (see [Exceptions](#exceptions)); [`IgnoredBlockContexts`](#ignoredblockcontexts) lets a project name the same kind of case for a library this cop doesn't know about.
|
|
108
150
|
|
|
109
151
|
## Requirements
|
|
110
152
|
|
data/config/default.yml
CHANGED
|
@@ -15,9 +15,19 @@ module RuboCop
|
|
|
15
15
|
# change what the block sees. Enabling `Style/ItAssignment` rules such names
|
|
16
16
|
# out. Additionally, `it` drops the argument name from `Proc#parameters`
|
|
17
17
|
# (`[[:opt, :x]]` becomes `[[:opt]]`) and breaks
|
|
18
|
-
# `binding.local_variable_get(:x)` inside the block.
|
|
19
|
-
#
|
|
20
|
-
#
|
|
18
|
+
# `binding.local_variable_get(:x)` inside the block. A block captured with
|
|
19
|
+
# `&block` and introspected elsewhere is still affected even when none of
|
|
20
|
+
# the below applies.
|
|
21
|
+
#
|
|
22
|
+
# Some blocks are unsafe to convert for reasons this cop cannot see from the
|
|
23
|
+
# AST alone — `->(x) { }`, `lambda`, `proc`, `Proc.new`, `define_method` and
|
|
24
|
+
# `define_singleton_method` all define a callable or a method, where the
|
|
25
|
+
# parameter list is part of its API and `it` drops the parameter name; RSpec's
|
|
26
|
+
# custom matcher DSL turns `match`, `chain` and similar blocks into actual
|
|
27
|
+
# methods internally, where `it`'s implicit binding does not reliably survive.
|
|
28
|
+
# These are all built in and cannot be turned off. `IgnoredBlockContexts` lets
|
|
29
|
+
# a project add its own cases the same way, scoped to where they're nested so
|
|
30
|
+
# a generic method name doesn't suppress the check on unrelated code.
|
|
21
31
|
#
|
|
22
32
|
# @example
|
|
23
33
|
# # bad
|
|
@@ -47,6 +57,11 @@ module RuboCop
|
|
|
47
57
|
# ->(x) { puts x }
|
|
48
58
|
# define_method(:m) { |x| x + 1 }
|
|
49
59
|
#
|
|
60
|
+
# # good - RSpec turns this block into a method internally, where `it` cannot be trusted
|
|
61
|
+
# RSpec::Matchers.define :be_valid_foo do
|
|
62
|
+
# match { |actual| actual.valid? }
|
|
63
|
+
# end
|
|
64
|
+
#
|
|
50
65
|
# # bad
|
|
51
66
|
# items.map { |item| {item:} }
|
|
52
67
|
#
|
|
@@ -64,7 +79,25 @@ module RuboCop
|
|
|
64
79
|
|
|
65
80
|
INNER_BLOCK_TYPES = %i[block numblock itblock].freeze #: Array[Symbol]
|
|
66
81
|
|
|
67
|
-
|
|
82
|
+
# Maps a call to the method names that are unsafe when nested inside it, in
|
|
83
|
+
# the same format as the `IgnoredBlockContexts` config option (see
|
|
84
|
+
# `matches_context?` for the exact matching rules). A `nil` value means the
|
|
85
|
+
# call itself is unsafe, wherever it appears, with no nesting required —
|
|
86
|
+
# `lambda`/`proc`/`define_method`/`define_singleton_method` match regardless
|
|
87
|
+
# of receiver (`*.`), `Proc.new` requires that exact receiver. These are core
|
|
88
|
+
# Ruby behavior and RSpec's widely-used matcher DSL, so unlike
|
|
89
|
+
# `IgnoredBlockContexts` they're built in and cannot be turned off.
|
|
90
|
+
BUILTIN_IGNORED_BLOCK_CONTEXTS = {
|
|
91
|
+
"*.lambda" => nil,
|
|
92
|
+
"*.proc" => nil,
|
|
93
|
+
"*.define_method" => nil,
|
|
94
|
+
"*.define_singleton_method" => nil,
|
|
95
|
+
"Proc.new" => nil,
|
|
96
|
+
"RSpec::Matchers.define" => %i[
|
|
97
|
+
match match_when_negated match_unless_raises chain
|
|
98
|
+
failure_message failure_message_when_negated description
|
|
99
|
+
]
|
|
100
|
+
}.freeze #: Hash[String, Array[Symbol]?]
|
|
68
101
|
|
|
69
102
|
# @rbs node: RuboCop::AST::BlockNode
|
|
70
103
|
def on_block(node) #: void
|
|
@@ -86,7 +119,7 @@ module RuboCop
|
|
|
86
119
|
# @rbs body: RuboCop::AST::Node
|
|
87
120
|
def convertible_argument_name(node, body) #: Symbol?
|
|
88
121
|
return unless node.single_line?
|
|
89
|
-
return if
|
|
122
|
+
return if ignored?(node)
|
|
90
123
|
|
|
91
124
|
name = sole_argument_name(node)
|
|
92
125
|
return unless name
|
|
@@ -105,24 +138,90 @@ module RuboCop
|
|
|
105
138
|
lvar_references(body, :it).any? || reassigned?(body, :it)
|
|
106
139
|
end
|
|
107
140
|
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
#
|
|
141
|
+
# A block can be unsafe to convert for reasons specific to how it's used, not
|
|
142
|
+
# just because of what method it's passed to — see `BUILTIN_IGNORED_BLOCK_CONTEXTS`
|
|
143
|
+
# for the built-in cases and `matches_context?` for what a context means.
|
|
144
|
+
# `IgnoredBlockContexts` lets a project add its own cases the same way; it is
|
|
145
|
+
# checked separately from, and in addition to, the built-in ones, so a project
|
|
146
|
+
# can never accidentally disable those by overriding this config option.
|
|
111
147
|
#
|
|
112
148
|
# @rbs node: RuboCop::AST::BlockNode
|
|
113
|
-
def
|
|
114
|
-
|
|
149
|
+
def ignored?(node) #: bool
|
|
150
|
+
ignored_in?(node, BUILTIN_IGNORED_BLOCK_CONTEXTS) || ignored_in?(node, ignored_block_contexts)
|
|
115
151
|
end
|
|
116
152
|
|
|
117
153
|
# @rbs node: RuboCop::AST::BlockNode
|
|
118
|
-
|
|
119
|
-
|
|
154
|
+
# @rbs contexts: Hash[String, Array[Symbol]?]
|
|
155
|
+
def ignored_in?(node, contexts) #: bool
|
|
156
|
+
contexts.any? { |context, method_names| matches_context?(node, context, method_names) }
|
|
157
|
+
end
|
|
120
158
|
|
|
121
|
-
|
|
122
|
-
return false unless receiver&.const_type?
|
|
159
|
+
# @rbs @ignored_block_contexts: Hash[String, Array[Symbol]?]
|
|
123
160
|
|
|
124
|
-
|
|
125
|
-
|
|
161
|
+
def ignored_block_contexts #: Hash[String, Array[Symbol]?]
|
|
162
|
+
default = {} #: Hash[String, Array[String]?]
|
|
163
|
+
@ignored_block_contexts ||= cop_config.fetch("IgnoredBlockContexts", default).transform_values do |names|
|
|
164
|
+
names&.map(&:to_sym)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# A `nil` (or empty) `method_names` means `context` describes the node's own
|
|
169
|
+
# call, checked with no nesting required — this is how `Proc.new` and the
|
|
170
|
+
# receiver-blind `*.lambda`-style entries work. Otherwise, `context` names an
|
|
171
|
+
# enclosing call the node must be nested inside, and `method_names` are the
|
|
172
|
+
# names that are unsafe within it — this is how RSpec's matcher DSL works.
|
|
173
|
+
#
|
|
174
|
+
# @rbs node: RuboCop::AST::BlockNode
|
|
175
|
+
# @rbs context: String
|
|
176
|
+
# @rbs method_names: Array[Symbol]?
|
|
177
|
+
def matches_context?(node, context, method_names) #: bool
|
|
178
|
+
if method_names.nil? || method_names.empty?
|
|
179
|
+
receiver_source, method_name = parse_context(context)
|
|
180
|
+
context_call?(node.send_node, receiver_source, method_name)
|
|
181
|
+
else
|
|
182
|
+
method_names.include?(node.method_name) && nested_in_context?(node, context)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# `numblock` and `itblock` (a `_1` or `it` block) are included since
|
|
187
|
+
# rubocop-ast maps both to `BlockNode`, so `#send_node` works the same as for
|
|
188
|
+
# a plain `block`.
|
|
189
|
+
#
|
|
190
|
+
# @rbs node: RuboCop::AST::BlockNode
|
|
191
|
+
# @rbs context: String
|
|
192
|
+
def nested_in_context?(node, context) #: bool
|
|
193
|
+
receiver_source, method_name = parse_context(context)
|
|
194
|
+
node.each_ancestor(*INNER_BLOCK_TYPES).any? do |ancestor|
|
|
195
|
+
block_ancestor = ancestor #: RuboCop::AST::BlockNode
|
|
196
|
+
context_call?(block_ancestor.send_node, receiver_source, method_name)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# @rbs context: String
|
|
201
|
+
def parse_context(context) #: [String, String]
|
|
202
|
+
receiver_source, _dot, method_name = context.rpartition(".")
|
|
203
|
+
[receiver_source, method_name]
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# `receiver_source` of `"*"` matches any receiver, or none. An empty
|
|
207
|
+
# `receiver_source` (`context` had no `.`) requires no receiver at all.
|
|
208
|
+
# Otherwise the receiver's source must match exactly, modulo a leading `::`
|
|
209
|
+
# on either side — `::Proc` is not receiver-less, its source is `"::Proc"`
|
|
210
|
+
# (a `cbase`-prefixed const), so this is what lets `Proc.new` also match
|
|
211
|
+
# `::Proc.new`.
|
|
212
|
+
#
|
|
213
|
+
# @rbs send_node: RuboCop::AST::SendNode
|
|
214
|
+
# @rbs receiver_source: String
|
|
215
|
+
# @rbs method_name: String
|
|
216
|
+
def context_call?(send_node, receiver_source, method_name) #: bool
|
|
217
|
+
return false unless send_node.method?(method_name.to_sym)
|
|
218
|
+
return true if receiver_source == "*"
|
|
219
|
+
return send_node.receiver.nil? if receiver_source.empty?
|
|
220
|
+
|
|
221
|
+
actual_receiver_source = send_node.receiver&.source
|
|
222
|
+
return false unless actual_receiver_source
|
|
223
|
+
|
|
224
|
+
actual_receiver_source.delete_prefix("::") == receiver_source.delete_prefix("::")
|
|
126
225
|
end
|
|
127
226
|
|
|
128
227
|
# @rbs node: RuboCop::AST::BlockNode
|
|
@@ -15,9 +15,19 @@ module RuboCop
|
|
|
15
15
|
# change what the block sees. Enabling `Style/ItAssignment` rules such names
|
|
16
16
|
# out. Additionally, `it` drops the argument name from `Proc#parameters`
|
|
17
17
|
# (`[[:opt, :x]]` becomes `[[:opt]]`) and breaks
|
|
18
|
-
# `binding.local_variable_get(:x)` inside the block.
|
|
19
|
-
#
|
|
20
|
-
#
|
|
18
|
+
# `binding.local_variable_get(:x)` inside the block. A block captured with
|
|
19
|
+
# `&block` and introspected elsewhere is still affected even when none of
|
|
20
|
+
# the below applies.
|
|
21
|
+
#
|
|
22
|
+
# Some blocks are unsafe to convert for reasons this cop cannot see from the
|
|
23
|
+
# AST alone — `->(x) { }`, `lambda`, `proc`, `Proc.new`, `define_method` and
|
|
24
|
+
# `define_singleton_method` all define a callable or a method, where the
|
|
25
|
+
# parameter list is part of its API and `it` drops the parameter name; RSpec's
|
|
26
|
+
# custom matcher DSL turns `match`, `chain` and similar blocks into actual
|
|
27
|
+
# methods internally, where `it`'s implicit binding does not reliably survive.
|
|
28
|
+
# These are all built in and cannot be turned off. `IgnoredBlockContexts` lets
|
|
29
|
+
# a project add its own cases the same way, scoped to where they're nested so
|
|
30
|
+
# a generic method name doesn't suppress the check on unrelated code.
|
|
21
31
|
#
|
|
22
32
|
# @example
|
|
23
33
|
# # bad
|
|
@@ -47,6 +57,11 @@ module RuboCop
|
|
|
47
57
|
# ->(x) { puts x }
|
|
48
58
|
# define_method(:m) { |x| x + 1 }
|
|
49
59
|
#
|
|
60
|
+
# # good - RSpec turns this block into a method internally, where `it` cannot be trusted
|
|
61
|
+
# RSpec::Matchers.define :be_valid_foo do
|
|
62
|
+
# match { |actual| actual.valid? }
|
|
63
|
+
# end
|
|
64
|
+
#
|
|
50
65
|
# # bad
|
|
51
66
|
# items.map { |item| {item:} }
|
|
52
67
|
#
|
|
@@ -63,7 +78,15 @@ module RuboCop
|
|
|
63
78
|
|
|
64
79
|
INNER_BLOCK_TYPES: Array[Symbol]
|
|
65
80
|
|
|
66
|
-
|
|
81
|
+
# Maps a call to the method names that are unsafe when nested inside it, in
|
|
82
|
+
# the same format as the `IgnoredBlockContexts` config option (see
|
|
83
|
+
# `matches_context?` for the exact matching rules). A `nil` value means the
|
|
84
|
+
# call itself is unsafe, wherever it appears, with no nesting required —
|
|
85
|
+
# `lambda`/`proc`/`define_method`/`define_singleton_method` match regardless
|
|
86
|
+
# of receiver (`*.`), `Proc.new` requires that exact receiver. These are core
|
|
87
|
+
# Ruby behavior and RSpec's widely-used matcher DSL, so unlike
|
|
88
|
+
# `IgnoredBlockContexts` they're built in and cannot be turned off.
|
|
89
|
+
BUILTIN_IGNORED_BLOCK_CONTEXTS: Hash[String, Array[Symbol]?]
|
|
67
90
|
|
|
68
91
|
# @rbs node: RuboCop::AST::BlockNode
|
|
69
92
|
def on_block: (RuboCop::AST::BlockNode node) -> void
|
|
@@ -81,15 +104,57 @@ module RuboCop
|
|
|
81
104
|
# @rbs body: RuboCop::AST::Node
|
|
82
105
|
def shadows_it?: (RuboCop::AST::Node body) -> bool
|
|
83
106
|
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
107
|
+
# A block can be unsafe to convert for reasons specific to how it's used, not
|
|
108
|
+
# just because of what method it's passed to — see `BUILTIN_IGNORED_BLOCK_CONTEXTS`
|
|
109
|
+
# for the built-in cases and `matches_context?` for what a context means.
|
|
110
|
+
# `IgnoredBlockContexts` lets a project add its own cases the same way; it is
|
|
111
|
+
# checked separately from, and in addition to, the built-in ones, so a project
|
|
112
|
+
# can never accidentally disable those by overriding this config option.
|
|
113
|
+
#
|
|
114
|
+
# @rbs node: RuboCop::AST::BlockNode
|
|
115
|
+
def ignored?: (RuboCop::AST::BlockNode node) -> bool
|
|
116
|
+
|
|
117
|
+
# @rbs node: RuboCop::AST::BlockNode
|
|
118
|
+
# @rbs contexts: Hash[String, Array[Symbol]?]
|
|
119
|
+
def ignored_in?: (RuboCop::AST::BlockNode node, Hash[String, Array[Symbol]?] contexts) -> bool
|
|
120
|
+
|
|
121
|
+
@ignored_block_contexts: Hash[String, Array[Symbol]?]
|
|
122
|
+
|
|
123
|
+
def ignored_block_contexts: () -> Hash[String, Array[Symbol]?]
|
|
124
|
+
|
|
125
|
+
# A `nil` (or empty) `method_names` means `context` describes the node's own
|
|
126
|
+
# call, checked with no nesting required — this is how `Proc.new` and the
|
|
127
|
+
# receiver-blind `*.lambda`-style entries work. Otherwise, `context` names an
|
|
128
|
+
# enclosing call the node must be nested inside, and `method_names` are the
|
|
129
|
+
# names that are unsafe within it — this is how RSpec's matcher DSL works.
|
|
87
130
|
#
|
|
88
131
|
# @rbs node: RuboCop::AST::BlockNode
|
|
89
|
-
|
|
132
|
+
# @rbs context: String
|
|
133
|
+
# @rbs method_names: Array[Symbol]?
|
|
134
|
+
def matches_context?: (RuboCop::AST::BlockNode node, String context, Array[Symbol]? method_names) -> bool
|
|
90
135
|
|
|
136
|
+
# `numblock` and `itblock` (a `_1` or `it` block) are included since
|
|
137
|
+
# rubocop-ast maps both to `BlockNode`, so `#send_node` works the same as for
|
|
138
|
+
# a plain `block`.
|
|
139
|
+
#
|
|
91
140
|
# @rbs node: RuboCop::AST::BlockNode
|
|
92
|
-
|
|
141
|
+
# @rbs context: String
|
|
142
|
+
def nested_in_context?: (RuboCop::AST::BlockNode node, String context) -> bool
|
|
143
|
+
|
|
144
|
+
# @rbs context: String
|
|
145
|
+
def parse_context: (String context) -> [ String, String ]
|
|
146
|
+
|
|
147
|
+
# `receiver_source` of `"*"` matches any receiver, or none. An empty
|
|
148
|
+
# `receiver_source` (`context` had no `.`) requires no receiver at all.
|
|
149
|
+
# Otherwise the receiver's source must match exactly, modulo a leading `::`
|
|
150
|
+
# on either side — `::Proc` is not receiver-less, its source is `"::Proc"`
|
|
151
|
+
# (a `cbase`-prefixed const), so this is what lets `Proc.new` also match
|
|
152
|
+
# `::Proc.new`.
|
|
153
|
+
#
|
|
154
|
+
# @rbs send_node: RuboCop::AST::SendNode
|
|
155
|
+
# @rbs receiver_source: String
|
|
156
|
+
# @rbs method_name: String
|
|
157
|
+
def context_call?: (RuboCop::AST::SendNode send_node, String receiver_source, String method_name) -> bool
|
|
93
158
|
|
|
94
159
|
# @rbs node: RuboCop::AST::BlockNode
|
|
95
160
|
def sole_argument_name: (RuboCop::AST::BlockNode node) -> Symbol?
|