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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb5b1320e0c36ea11d3931c04aad10d03a3c909cf16added71b537bb540e9851
4
- data.tar.gz: c2e121be2bfa362e5e6b8f7acaae7378d82158fbecdcb0c6b562e9eb4f4f1b0b
3
+ metadata.gz: 635807053b2df421a854cdc73001545451f8a7017623c93c6d6eb89bf304e172
4
+ data.tar.gz: cacd6163f57b4ee053b3053a950240b71bc2665b8bd93d6a4dba916d02490683
5
5
  SHA512:
6
- metadata.gz: 45b61992be6ad19b714eaa67929b0782c0cfb6b237cfb0a9770aca073f5672b817586305b8588052d636556e73afcd54826112d19ec67cb3d13df9af554a6e2b
7
- data.tar.gz: 2983a3c4e99c5c58cb4361b2ac93b588230df3e318e79c1f4ec8b0b0f16d49ac69ff0e9f2fd443ecf5ac3ef8be3d673f3116f18854498590f129d23093079da8
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-05 21:07:30 UTC using RuboCop version 1.81.7.
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: 61
25
+ Max: 60
26
26
 
27
- # Offense count: 1
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: 11
48
+ # Offense count: 12
49
49
  # Configuration parameters: CountAsOne.
50
50
  RSpec/ExampleLength:
51
- Max: 26
51
+ Max: 37
52
52
 
53
53
  # Offense count: 2
54
54
  # This cop supports safe autocorrection (--autocorrect).
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubocop-sorted_methods_by_call (1.0.1)
4
+ rubocop-sorted_methods_by_call (1.1.0)
5
5
  lint_roller
6
6
  rubocop (>= 1.72.0)
7
7
 
data/LICENSE.txt CHANGED
@@ -1,11 +1,21 @@
1
- Copyright 2022 unurgunite
1
+ MIT License
2
2
 
3
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
3
+ Copyright (c) 2025 unurgunite
4
4
 
5
- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
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
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
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
- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
-
11
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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
  [![CI](https://github.com/unurgunite/rubocop-sorted_methods_by_call/actions/workflows/ci.yml/badge.svg)](https://github.com/unurgunite/rubocop-sorted_methods_by_call/actions)
5
5
  [![Gem Version](https://badge.fury.io/rb/rubocop-sorted_methods_by_call.svg)](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
- do_smth
92
+ foo
93
+ bar
89
94
  end
90
95
 
91
96
  private
92
97
 
93
- def do_smth
94
- well
98
+ def bar
99
+ method123
95
100
  end
96
101
 
97
- def well
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
- do_smth
118
+ foo
119
+ bar
109
120
  end
110
121
 
111
122
  private
112
123
 
113
- def well # ❌ Offense: Define #well after its caller #do_smth
124
+ def foo # ❌ Offense: Define #foo after its caller #method123
114
125
  123
115
126
  end
116
127
 
117
- def do_smth
118
- well
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 .rubocop.test.yml lib/ -A
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 is now stable and ready for production use! The "waterfall" ordering pattern helps create more
225
- > readable code by ensuring that methods are defined in the order they're conceptually needed.
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 waterfall ordering: define methods after the methods that call them."
2
+ Description: "Enforces method ordering based on call relationships."
4
3
  Enabled: false
5
- VersionAdded: "1.0.1"
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 foo
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 bar
34
+ # def foo
24
35
  # 123
25
36
  # end
26
37
  #
27
- # def foo
28
- # bar
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
- # Find a visibility section that contains both names
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 = target_section[:visibility]
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 (so we replace it)
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 = node.source_range
470
+ expr = node.source_range
474
471
 
475
472
  start_line = expr.line
476
473
  lineno = start_line - 1
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module SortedMethodsByCall
5
- VERSION = '1.0.1'
5
+ VERSION = '1.1.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-sorted_methods_by_call
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - unurgunite