rubocop-fourshark 0.8.3 → 0.8.4
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4cdbe5b265ec54b100ac589171adad9038c99fee37dac3008cb56bba16e1a002
|
|
4
|
+
data.tar.gz: 8dfc81f74e7af24ad5518bf67ab735e9d75557cf2db03d4401ee46ba1c471f61
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 684f7b5b0f1064064eb545240a7f2f290207c9d0e7f759363e26d2607b2fe0d48fda173e8e48827769fa625f3eefb5ed6591ffdbdc770bf29f63bebbe156c50f
|
|
7
|
+
data.tar.gz: 19a91ad805511e8a3f19d903d18eeb007c5a2c1d4e2329733336e12d6b041cad998466f0fe080556830fbf8a90be6736f568b33eaf1d803b3e2e4c94b0dd8555
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## [0.8.4] - 2026-08-07
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
|
|
5
|
+
- `Style/DisallowDelegate` — own state reached through a call on it is no longer flagged
|
|
6
|
+
- `Style/DisallowDelegate` — an argument rooted at the collaborator being forwarded to is flagged again
|
|
7
|
+
- `Style/DisallowDelegate` — own state read through an explicit `self` is no longer flagged
|
|
8
|
+
- `Style/DisallowDelegate` — a call reached through safe navigation counts as the call it is, on both the receiver and the argument side
|
|
9
|
+
|
|
1
10
|
## [0.8.3] - 2026-08-06
|
|
2
11
|
|
|
3
12
|
### Fixed
|
|
@@ -127,7 +127,7 @@ module RuboCop
|
|
|
127
127
|
match && match[1]
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
-
# "UserAccount" → "user_account"; "
|
|
130
|
+
# "UserAccount" → "user_account"; "Order::LineItem" → "order/line_item"
|
|
131
131
|
def camel_to_snake(name)
|
|
132
132
|
name.gsub('::', '/')
|
|
133
133
|
.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
|
@@ -37,34 +37,46 @@ module RuboCop
|
|
|
37
37
|
# contributes something the caller would otherwise have to reach in and
|
|
38
38
|
# take, and the result is a simpler API on the object that owns the data.
|
|
39
39
|
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
40
|
+
# Own state is an instance variable, `self`, or a receiverless call,
|
|
41
|
+
# reached directly, through a wrapper, or through a call on it — `record`,
|
|
42
|
+
# `record.owner_id` and `[record.owner_id]` all carry the object's own
|
|
43
|
+
# data. A method PARAMETER does not: it arrives as an `lvar`, so a setter
|
|
44
|
+
# handing its argument to a collaborator stays flagged.
|
|
45
|
+
#
|
|
46
|
+
# Two limits keep the exemption from swallowing the rule.
|
|
47
|
+
#
|
|
48
|
+
# The receiver must not itself be a chain. Remove Middle Man on a message
|
|
49
|
+
# chain IS the caller navigating, so composing own state does not excuse
|
|
50
|
+
# it.
|
|
51
|
+
#
|
|
52
|
+
# An argument rooted at the collaborator being forwarded to does not earn
|
|
53
|
+
# the exemption. `author.name(author.locale)` hands the collaborator back
|
|
54
|
+
# its own data, which is the echo this rule forbids, not composition, so
|
|
55
|
+
# with no other argument to carry it the forward stays flagged. Rooted at
|
|
56
|
+
# the object's OWN state the argument may be a chain of any depth — the
|
|
57
|
+
# object still supplied what the collaborator needed, and how far it
|
|
58
|
+
# reached inside itself to build the value is its own business.
|
|
59
|
+
#
|
|
60
|
+
# A forward to a collaborator that passes NO argument is the one that
|
|
61
|
+
# republishes, and it is always flagged. That is the line — supplying data
|
|
62
|
+
# the collaborator needs is composition, echoing back what the collaborator
|
|
63
|
+
# already knows is delegation.
|
|
52
64
|
#
|
|
53
65
|
# @example
|
|
54
66
|
# # bad
|
|
55
|
-
# delegate :name, to: :
|
|
67
|
+
# delegate :name, to: :author
|
|
56
68
|
#
|
|
57
69
|
# # bad — same promise, written by hand
|
|
58
70
|
# def name
|
|
59
|
-
#
|
|
71
|
+
# author.name
|
|
60
72
|
# end
|
|
61
73
|
#
|
|
62
74
|
# # good — the caller navigates
|
|
63
|
-
#
|
|
75
|
+
# post.author.name
|
|
64
76
|
#
|
|
65
77
|
# # good — the object answers about itself, not for a collaborator
|
|
66
78
|
# def lock_key
|
|
67
|
-
# self.class.lock_key(
|
|
79
|
+
# self.class.lock_key(owner_id: owner_id)
|
|
68
80
|
# end
|
|
69
81
|
#
|
|
70
82
|
# # good — `each` is the Enumerable contract this class implements
|
|
@@ -78,12 +90,22 @@ module RuboCop
|
|
|
78
90
|
#
|
|
79
91
|
# # good — composes its own attribute, so the caller cannot just navigate
|
|
80
92
|
# def output
|
|
81
|
-
#
|
|
93
|
+
# formatter.output(value)
|
|
94
|
+
# end
|
|
95
|
+
#
|
|
96
|
+
# # good — names an expression built from its own record; not a forward
|
|
97
|
+
# def lock_key
|
|
98
|
+
# Registry.lock_key(owner_id: record.owner_id)
|
|
82
99
|
# end
|
|
83
100
|
#
|
|
84
101
|
# # bad — a chain does not stop being a chain because an argument rode along
|
|
85
102
|
# def starts_at
|
|
86
|
-
#
|
|
103
|
+
# schedule.window.period.starts_at(calendar)
|
|
104
|
+
# end
|
|
105
|
+
#
|
|
106
|
+
# # bad — the argument is the collaborator's own data handed back to it
|
|
107
|
+
# def name
|
|
108
|
+
# author.name(author.locale)
|
|
87
109
|
# end
|
|
88
110
|
#
|
|
89
111
|
class DisallowDelegate < ::RuboCop::Cop::Base
|
|
@@ -154,32 +176,43 @@ module RuboCop
|
|
|
154
176
|
mixes_in_enumerable?(body)
|
|
155
177
|
end
|
|
156
178
|
|
|
157
|
-
def composes_own_state?(body)
|
|
158
|
-
return false if chained_receiver?(body.receiver)
|
|
159
|
-
|
|
160
|
-
body.arguments.any? { |argument| own_state?(argument) }
|
|
161
|
-
end
|
|
162
|
-
|
|
163
179
|
# Remove Middle Man on a message chain IS the caller navigating, so an
|
|
164
180
|
# argument riding along does not earn the exemption.
|
|
165
|
-
def
|
|
166
|
-
return false
|
|
181
|
+
def composes_own_state?(body)
|
|
182
|
+
return false if call_with_receiver?(body.receiver)
|
|
167
183
|
|
|
168
|
-
|
|
184
|
+
body.arguments.any? { |argument| own_state?(argument, body.receiver) }
|
|
169
185
|
end
|
|
170
186
|
|
|
171
187
|
# A method parameter reaches the body as an `lvar`, so only an instance
|
|
172
|
-
# variable or a receiverless call counts as the object's own
|
|
173
|
-
#
|
|
174
|
-
|
|
175
|
-
|
|
188
|
+
# variable, `self`, or a receiverless call counts as the object's own
|
|
189
|
+
# state — read directly, through a wrapper, or through a call on it.
|
|
190
|
+
# Anything rooted at the collaborator is that collaborator's own data
|
|
191
|
+
# coming back, which is the echo the rule forbids. The first guard
|
|
192
|
+
# refuses anything that is not a node, which covers both the nil child
|
|
193
|
+
# an anonymous block pass carries and a wrapper whose children are raw
|
|
194
|
+
# Ruby values rather than nodes.
|
|
195
|
+
def own_state?(argument, collaborator)
|
|
196
|
+
return false unless argument.is_a?(::RuboCop::AST::Node)
|
|
197
|
+
return false if argument == collaborator
|
|
176
198
|
return true if argument.ivar_type?
|
|
177
|
-
return true if argument.
|
|
178
|
-
return argument.
|
|
199
|
+
return true if argument.self_type?
|
|
200
|
+
return own_state?(argument.receiver, collaborator) if call_with_receiver?(argument)
|
|
201
|
+
return true if argument.send_type?
|
|
202
|
+
return argument.children.any? { |child| own_state?(child, collaborator) } if wrapper?(argument)
|
|
179
203
|
|
|
180
204
|
false
|
|
181
205
|
end
|
|
182
206
|
|
|
207
|
+
# `call_type?` is the `send`/`csend` union, so safe navigation counts as
|
|
208
|
+
# the call it is — a `&.` link neither escapes the chain limit nor stops
|
|
209
|
+
# own state from being recognized.
|
|
210
|
+
def call_with_receiver?(node)
|
|
211
|
+
return false unless node.call_type?
|
|
212
|
+
|
|
213
|
+
!node.receiver.nil?
|
|
214
|
+
end
|
|
215
|
+
|
|
183
216
|
def wrapper?(argument)
|
|
184
217
|
ARGUMENT_WRAPPERS.include?(argument.type)
|
|
185
218
|
end
|