rubocop-fourshark 0.8.1 → 0.8.2

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: 31d77a73abb724b68a4c2d187cc780899067d2ef82564e50bcce0d6b09dbffeb
4
- data.tar.gz: fd2eda214bf001b848e18be1f68df32463d70272be3f7ce999ac7cb3b1be8f8f
3
+ metadata.gz: 9358c7dd0bcd6717781203b1f4ccdd6e282851da1e52838db50acf058ce39414
4
+ data.tar.gz: f219f75c7fdaea1dff73f43ed9a1c16478e97b44f45f5242d9f21044e57cd19c
5
5
  SHA512:
6
- metadata.gz: 61aabc197c8224de85d39c9f150cb0fb1b73916a8882fd35cb3241b4b5ca330eb44f4098a12eff4fc934b918ea2ccf75a81bd150c1eac96193678ef620ae734c
7
- data.tar.gz: b0b7426b78afa3a99f028eb84b4dd78479c153d219997d55611e7e1ab3544ddfe99ead0b323306c24220c9806715ddf413b1ace76bdb19df8ccad9bb43391562
6
+ metadata.gz: edd536903d83b3516f576bdcf318847c5914a9b747d52203f2153a2dc2eaf5af783a7fc9d16d1f730674d51a8bde815b576a29f64619655824a227551a2979b1
7
+ data.tar.gz: c063cd068bace0cdccf5e0948e94c40088b0160fc023f14ee315f4177374134bea62eedc49d42655a505579afc0d43a9248d1f2d4a6231344d624154e5b95afe
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [0.8.2] - 2026-08-06
2
+
3
+ ### Fixed
4
+
5
+ - `Style/DisallowDelegate` — `each` in a class including `Enumerable` is no longer flagged
6
+ - `Style/DisallowDelegate` — a method composing its own state into the call is no longer flagged
7
+
1
8
  ## [0.8.1] - 2026-08-06
2
9
 
3
10
  ### Fixed
@@ -22,6 +22,21 @@ module RuboCop
22
22
  # method answers for a domain it owns, so it is not delegation and is not
23
23
  # flagged.
24
24
  #
25
+ # `each` in a class that includes `Enumerable` is the module's required
26
+ # contract, not delegation. The class has no interface without it — every
27
+ # method `Enumerable` provides is built on `each` — so the class is
28
+ # implementing its own interface rather than answering for a collaborator.
29
+ # It is not flagged. Any other method in such a class still is.
30
+ #
31
+ # A body that passes the object's own state as an argument is not a
32
+ # pass-through. Middle Man is a method that republishes a collaborator's
33
+ # answer verbatim, which the caller could reach by navigating; a method
34
+ # that supplies its own attributes contributes something the caller would
35
+ # otherwise have to reach in and take, and the result is a simpler API on
36
+ # the object that owns the data. Own state is an instance variable or a
37
+ # receiverless call — a method parameter forwarded through is not, so a
38
+ # setter passing its argument along stays flagged.
39
+ #
25
40
  # @example
26
41
  # # bad
27
42
  # delegate :name, to: :commission
@@ -39,6 +54,20 @@ module RuboCop
39
54
  # self.class.lock_key(company_id: company_id)
40
55
  # end
41
56
  #
57
+ # # good — `each` is the Enumerable contract this class implements
58
+ # class SearchResult
59
+ # include Enumerable
60
+ #
61
+ # def each(&)
62
+ # results.each(&)
63
+ # end
64
+ # end
65
+ #
66
+ # # good — composes its own attribute, so the caller cannot just navigate
67
+ # def output
68
+ # variable.output(value)
69
+ # end
70
+ #
42
71
  class DisallowDelegate < ::RuboCop::Cop::Base
43
72
  MACRO_MSG = 'Do not use automatic delegation. Delete the forwarder and let the caller navigate.'
44
73
  FORWARDER_MSG = 'Do not forward a collaborator\'s message. Delete the forwarder and let the caller navigate.'
@@ -51,8 +80,15 @@ module RuboCop
51
80
  add_offense(node, message: MACRO_MSG)
52
81
  end
53
82
 
83
+ # @!method includes_enumerable?(node)
84
+ def_node_matcher :includes_enumerable?, <<~PATTERN
85
+ (send nil? :include (const {nil? cbase} :Enumerable))
86
+ PATTERN
87
+
54
88
  def on_def(node)
55
89
  return unless forwards_own_message?(node.body, node.method_name)
90
+ return if enumerable_contract?(node)
91
+ return if composes_own_state?(node.body)
56
92
 
57
93
  add_offense(node.loc.name, message: FORWARDER_MSG)
58
94
  end
@@ -75,6 +111,36 @@ module RuboCop
75
111
 
76
112
  receiver.receiver.self_type?
77
113
  end
114
+
115
+ def enumerable_contract?(node)
116
+ return false unless node.method?(:each)
117
+
118
+ enclosing = node.each_ancestor(:class, :module).first
119
+ return false if enclosing.nil?
120
+
121
+ enumerable_body?(enclosing.body)
122
+ end
123
+
124
+ def enumerable_body?(body)
125
+ return false if body.nil?
126
+ return body.children.any? { |child| includes_enumerable?(child) } if body.begin_type?
127
+
128
+ includes_enumerable?(body)
129
+ end
130
+
131
+ def composes_own_state?(body)
132
+ body.arguments.any? { |argument| own_state?(argument) }
133
+ end
134
+
135
+ # A method parameter reaches the body as an `lvar`, so only an instance
136
+ # variable or a receiverless call counts as the object's own state.
137
+ def own_state?(argument)
138
+ return true if argument.ivar_type?
139
+ return true if argument.send_type? && argument.receiver.nil?
140
+ return argument.values.any? { |value| own_state?(value) } if argument.hash_type?
141
+
142
+ false
143
+ end
78
144
  end
79
145
  end
80
146
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Fourshark
5
- VERSION = '0.8.1'
5
+ VERSION = '0.8.2'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-fourshark
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paulo Ribeiro