rubocop-sorted_methods_by_call 1.0.1 → 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/.rubocop_todo.yml +5 -5
- data/Gemfile.lock +1 -1
- data/LICENSE.txt +17 -7
- data/README.md +37 -40
- data/config/default.yml +2 -3
- data/lib/rubocop/cop/sorted_methods_by_call/waterfall.rb +21 -24
- data/lib/rubocop/sorted_methods_by_call/version.rb +1 -1
- 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: 635807053b2df421a854cdc73001545451f8a7017623c93c6d6eb89bf304e172
|
|
4
|
+
data.tar.gz: cacd6163f57b4ee053b3053a950240b71bc2665b8bd93d6a4dba916d02490683
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4bedcb4e198e0d75209bb286a15d55ba16ec3ea026cbc52769f7acb13bc8c8f118cac590d4ca7fd16bdfd82730e380c3d02782e6dbf24001fc4815f316928d2a
|
|
7
|
+
data.tar.gz: 05d4815fcce53e4c90e8b66ac1933363ec3a4940f551d6f0464a993b63b2b3af36ba8795be3bea7a34cb462ad9aa6f39da011a87f055ac5154e8e4174319ffab
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2025-11-
|
|
3
|
+
# on 2025-11-06 15:18:01 UTC using RuboCop version 1.81.7.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -22,9 +22,9 @@ Gemspec/RequiredRubyVersion:
|
|
|
22
22
|
# Offense count: 4
|
|
23
23
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
|
24
24
|
Metrics/AbcSize:
|
|
25
|
-
Max:
|
|
25
|
+
Max: 60
|
|
26
26
|
|
|
27
|
-
# Offense count:
|
|
27
|
+
# Offense count: 2
|
|
28
28
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
|
|
29
29
|
# AllowedMethods: refine
|
|
30
30
|
Metrics/BlockLength:
|
|
@@ -45,10 +45,10 @@ Metrics/MethodLength:
|
|
|
45
45
|
Metrics/PerceivedComplexity:
|
|
46
46
|
Max: 22
|
|
47
47
|
|
|
48
|
-
# Offense count:
|
|
48
|
+
# Offense count: 12
|
|
49
49
|
# Configuration parameters: CountAsOne.
|
|
50
50
|
RSpec/ExampleLength:
|
|
51
|
-
Max:
|
|
51
|
+
Max: 37
|
|
52
52
|
|
|
53
53
|
# Offense count: 2
|
|
54
54
|
# This cop supports safe autocorrection (--autocorrect).
|
data/Gemfile.lock
CHANGED
data/LICENSE.txt
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
MIT License
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Copyright (c) 2025 unurgunite
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
[](https://github.com/unurgunite/rubocop-sorted_methods_by_call/actions)
|
|
5
5
|
[](https://rubygems.org/gems/rubocop-sorted_methods_by_call)
|
|
6
6
|
|
|
7
|
+
**Enforces "waterfall" method ordering**: define methods *after* any method that calls them within the same scope.
|
|
8
|
+
|
|
7
9
|
* [RuboCop::SortedMethodsByCall](#rubocopsortedmethodsbycall)
|
|
8
10
|
* [Features](#features)
|
|
9
11
|
* [Installation](#installation)
|
|
@@ -24,16 +26,14 @@
|
|
|
24
26
|
* [License](#license)
|
|
25
27
|
* [Code of Conduct](#code-of-conduct)
|
|
26
28
|
|
|
27
|
-
**Enforces "waterfall" method ordering**: define methods *after* any method that calls them within the same scope.
|
|
28
|
-
|
|
29
29
|
## Features
|
|
30
30
|
|
|
31
|
-
- **Waterfall ordering enforcement**: Caller methods must be defined before their callees
|
|
32
|
-
- **Smart visibility handling**: Respects `private`/`protected`/`public` sections
|
|
33
|
-
- **Safe mutual recursion**: Handles recursive method calls gracefully
|
|
34
|
-
- **Autocorrection support**: Automatically reorders methods (opt-in with `-A`)
|
|
35
|
-
- **Full RuboCop integration**: Works seamlessly with modern RuboCop plugin system
|
|
36
|
-
- **Comprehensive scope support**: Classes, modules, singleton classes, and top-level
|
|
31
|
+
- **Waterfall ordering enforcement**: Caller methods must be defined before their callees;
|
|
32
|
+
- **Smart visibility handling**: Respects `private`/`protected`/`public` sections;
|
|
33
|
+
- **Safe mutual recursion**: Handles recursive method calls gracefully;
|
|
34
|
+
- **Autocorrection support**: Automatically reorders methods (opt-in with `-A`);
|
|
35
|
+
- **Full RuboCop integration**: Works seamlessly with modern RuboCop plugin system;
|
|
36
|
+
- **Comprehensive scope support**: Classes, modules, singleton classes, and top-level;
|
|
37
37
|
|
|
38
38
|
## Installation
|
|
39
39
|
|
|
@@ -82,19 +82,28 @@ SortedMethodsByCall/Waterfall:
|
|
|
82
82
|
|
|
83
83
|
### Good Code (waterfall order)
|
|
84
84
|
|
|
85
|
+
In waterfall ordering, **callers come before callees**. This creates a top-down reading flow where main logic appears
|
|
86
|
+
before implementation details.
|
|
87
|
+
|
|
85
88
|
```ruby
|
|
89
|
+
|
|
86
90
|
class Service
|
|
87
91
|
def call
|
|
88
|
-
|
|
92
|
+
foo
|
|
93
|
+
bar
|
|
89
94
|
end
|
|
90
95
|
|
|
91
96
|
private
|
|
92
97
|
|
|
93
|
-
def
|
|
94
|
-
|
|
98
|
+
def bar
|
|
99
|
+
method123
|
|
95
100
|
end
|
|
96
101
|
|
|
97
|
-
def
|
|
102
|
+
def method123
|
|
103
|
+
foo
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def foo
|
|
98
107
|
123
|
|
99
108
|
end
|
|
100
109
|
end
|
|
@@ -103,19 +112,25 @@ end
|
|
|
103
112
|
### Bad Code (violates waterfall order)
|
|
104
113
|
|
|
105
114
|
```ruby
|
|
115
|
+
|
|
106
116
|
class Service
|
|
107
117
|
def call
|
|
108
|
-
|
|
118
|
+
foo
|
|
119
|
+
bar
|
|
109
120
|
end
|
|
110
121
|
|
|
111
122
|
private
|
|
112
123
|
|
|
113
|
-
def
|
|
124
|
+
def foo # ❌ Offense: Define #foo after its caller #method123
|
|
114
125
|
123
|
|
115
126
|
end
|
|
116
127
|
|
|
117
|
-
def
|
|
118
|
-
|
|
128
|
+
def bar
|
|
129
|
+
method123
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def method123
|
|
133
|
+
foo
|
|
119
134
|
end
|
|
120
135
|
end
|
|
121
136
|
```
|
|
@@ -128,25 +143,7 @@ Run with unsafe autocorrection to automatically fix violations:
|
|
|
128
143
|
bundle exec rubocop -A
|
|
129
144
|
```
|
|
130
145
|
|
|
131
|
-
This will reorder the methods while preserving comments and visibility modifiers
|
|
132
|
-
|
|
133
|
-
```ruby
|
|
134
|
-
class Service
|
|
135
|
-
def call
|
|
136
|
-
do_smth
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
private
|
|
140
|
-
|
|
141
|
-
def do_smth
|
|
142
|
-
well
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def well
|
|
146
|
-
123
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
```
|
|
146
|
+
This will reorder the methods while preserving comments and visibility modifiers.
|
|
150
147
|
|
|
151
148
|
## Testing
|
|
152
149
|
|
|
@@ -160,7 +157,7 @@ Run RuboCop on the gem itself:
|
|
|
160
157
|
|
|
161
158
|
```bash
|
|
162
159
|
bundle exec rubocop
|
|
163
|
-
bundle exec rubocop --config
|
|
160
|
+
bundle exec rubocop --config test_project/.rubocop.test.yml lib/ -A
|
|
164
161
|
```
|
|
165
162
|
|
|
166
163
|
## Development
|
|
@@ -212,8 +209,7 @@ at https://unurgunite.github.io/rubocop-sorted_methods_by_call_docs/
|
|
|
212
209
|
|
|
213
210
|
## License
|
|
214
211
|
|
|
215
|
-
The gem is available as open source under the terms of
|
|
216
|
-
the [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause).
|
|
212
|
+
The gem is available as open source under the terms of MIT License.
|
|
217
213
|
|
|
218
214
|
## Code of Conduct
|
|
219
215
|
|
|
@@ -221,5 +217,6 @@ Everyone interacting with this project is expected to follow the [Code of Conduc
|
|
|
221
217
|
|
|
222
218
|
---
|
|
223
219
|
|
|
224
|
-
> **Note**: This gem
|
|
225
|
-
>
|
|
220
|
+
> **Note**: This gem implements **true waterfall ordering** that considers the complete call graph across all methods in
|
|
221
|
+
> a scope. Methods are ordered so that every callee appears after all of its callers, creating a natural top-down
|
|
222
|
+
> reading flow.
|
data/config/default.yml
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
# Default configuration for rubocop-sorted_methods_by_call
|
|
2
1
|
SortedMethodsByCall/Waterfall:
|
|
3
|
-
Description: "Enforces
|
|
2
|
+
Description: "Enforces method ordering based on call relationships."
|
|
4
3
|
Enabled: false
|
|
5
|
-
VersionAdded: "1.0
|
|
4
|
+
VersionAdded: "1.1.0"
|
|
6
5
|
SafeAutoCorrect: false
|
|
7
6
|
AllowedRecursion: true
|
|
@@ -11,21 +11,32 @@ module RuboCop
|
|
|
11
11
|
# - Autocorrect: UNSAFE; reorders methods within a contiguous visibility section
|
|
12
12
|
#
|
|
13
13
|
# Example (good):
|
|
14
|
-
# def
|
|
14
|
+
# def call
|
|
15
|
+
# foo
|
|
15
16
|
# bar
|
|
16
17
|
# end
|
|
17
18
|
#
|
|
19
|
+
# private
|
|
20
|
+
#
|
|
18
21
|
# def bar
|
|
22
|
+
# method123
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# def method123
|
|
26
|
+
# foo
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# def foo
|
|
19
30
|
# 123
|
|
20
31
|
# end
|
|
21
32
|
#
|
|
22
33
|
# Example (bad):
|
|
23
|
-
# def
|
|
34
|
+
# def foo
|
|
24
35
|
# 123
|
|
25
36
|
# end
|
|
26
37
|
#
|
|
27
|
-
# def
|
|
28
|
-
#
|
|
38
|
+
# def call
|
|
39
|
+
# foo
|
|
29
40
|
# end
|
|
30
41
|
#
|
|
31
42
|
# Autocorrect (unsafe, opt-in via SafeAutoCorrect: false): topologically sorts the contiguous
|
|
@@ -102,6 +113,7 @@ module RuboCop
|
|
|
102
113
|
names_set = names.to_set
|
|
103
114
|
index_of = names.each_with_index.to_h
|
|
104
115
|
|
|
116
|
+
# Build complete call graph - find ALL method calls in ALL methods
|
|
105
117
|
edges = []
|
|
106
118
|
def_nodes.each do |def_node|
|
|
107
119
|
local_calls(def_node, names_set).each do |callee|
|
|
@@ -172,20 +184,6 @@ module RuboCop
|
|
|
172
184
|
res.uniq
|
|
173
185
|
end
|
|
174
186
|
|
|
175
|
-
# +RuboCop::Cop::SortedMethodsByCall::Waterfall#find_violation+ -> [Symbol, Symbol], nil
|
|
176
|
-
#
|
|
177
|
-
# Finds the first backward edge (caller->callee where callee is defined above caller)
|
|
178
|
-
# using the provided index map.
|
|
179
|
-
#
|
|
180
|
-
# @param [Array<Array(Symbol, Symbol)>] edges
|
|
181
|
-
# @param [Hash{Symbol=>Integer}] index_of
|
|
182
|
-
# @return [[Symbol, Symbol], nil] tuple [caller, callee] or nil if none found
|
|
183
|
-
def find_violation(edges, index_of)
|
|
184
|
-
edges.find do |caller, callee|
|
|
185
|
-
index_of.key?(caller) && index_of.key?(callee) && index_of[callee] < index_of[caller]
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
187
|
# +RuboCop::Cop::SortedMethodsByCall::Waterfall#try_autocorrect+ -> void
|
|
190
188
|
#
|
|
191
189
|
# UNSAFE: Reorders method definitions inside the target visibility section only
|
|
@@ -215,7 +213,7 @@ module RuboCop
|
|
|
215
213
|
# No violation -> nothing to do
|
|
216
214
|
return unless caller_name && callee_name
|
|
217
215
|
|
|
218
|
-
#
|
|
216
|
+
# Find a visibility section that contains both names
|
|
219
217
|
target_section = sections.find do |section|
|
|
220
218
|
names_in_section = section[:defs].to_set(&:method_name)
|
|
221
219
|
names_in_section.include?(caller_name) && names_in_section.include?(callee_name)
|
|
@@ -228,11 +226,9 @@ module RuboCop
|
|
|
228
226
|
return unless defs.size > 1
|
|
229
227
|
|
|
230
228
|
# Apply topological sort only within this visibility section
|
|
231
|
-
defs = target_section[:defs]
|
|
232
229
|
names = defs.map(&:method_name)
|
|
233
230
|
idx_of = names.each_with_index.to_h
|
|
234
231
|
|
|
235
|
-
# Filter edges to only those within this section
|
|
236
232
|
# Filter edges to only those within this section
|
|
237
233
|
section_names = names.to_set
|
|
238
234
|
section_edges = edges.select { |u, v| section_names.include?(u) && section_names.include?(v) }
|
|
@@ -245,7 +241,7 @@ module RuboCop
|
|
|
245
241
|
sorted_def_sources = sorted_names.map { |name| ranges_by_name[name].source }
|
|
246
242
|
|
|
247
243
|
# Reconstruct the section: keep the visibility modifier (if any) above the first def
|
|
248
|
-
visibility_node
|
|
244
|
+
visibility_node = target_section[:visibility]
|
|
249
245
|
visibility_source = visibility_node&.source.to_s
|
|
250
246
|
|
|
251
247
|
new_content = if visibility_source.empty?
|
|
@@ -255,7 +251,7 @@ module RuboCop
|
|
|
255
251
|
end
|
|
256
252
|
|
|
257
253
|
# Expand the replaced region:
|
|
258
|
-
# - if a visibility node exists, start from its begin_pos
|
|
254
|
+
# - if a visibility node exists, start from its begin_pos
|
|
259
255
|
# - otherwise, start from the earliest leading doc-comment of the defs
|
|
260
256
|
section_begin =
|
|
261
257
|
if visibility_node
|
|
@@ -306,6 +302,7 @@ module RuboCop
|
|
|
306
302
|
# If mutual recursion allowed and there is a path callee -> caller, skip
|
|
307
303
|
next if allow_recursion && path_exists?(callee, caller, adj)
|
|
308
304
|
|
|
305
|
+
# Violation: callee is defined BEFORE caller (waterfall order)
|
|
309
306
|
index_of[callee] < index_of[caller]
|
|
310
307
|
end
|
|
311
308
|
end
|
|
@@ -470,7 +467,7 @@ module RuboCop
|
|
|
470
467
|
# @return [Parser::Source::Range] Range covering leading comments + method body.
|
|
471
468
|
def range_with_leading_comments(node)
|
|
472
469
|
buffer = processed_source.buffer
|
|
473
|
-
expr
|
|
470
|
+
expr = node.source_range
|
|
474
471
|
|
|
475
472
|
start_line = expr.line
|
|
476
473
|
lineno = start_line - 1
|