rubocop-asjer 0.4.0 → 0.4.1

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: 772cbb0491de18ffeb19b27e41336474005b2c9295f5f2c152c842883e250654
4
- data.tar.gz: f2b5e866ba2bccd3fee26d59868f80b8f12de62e57b161e203e932f8aa70533f
3
+ metadata.gz: 6401e9b5d10c63a9c3ff7f3292aac36e8368a54fdd4df3062efda177ee331c11
4
+ data.tar.gz: a7e90b0a705e59b161b575fdedb087d82b54dd8af3cfec7509bc54553012c5f5
5
5
  SHA512:
6
- metadata.gz: 891112aad96477909e4a2de0a24660655b5573b6ef8f837cd70fe84927502390a3544f47994a9644b4d5b12b826aba74c8ab09f73dde3d49b044bb5fa6cc62cf
7
- data.tar.gz: f6c1dd35c8a2fe82392a38576b5c26af9b4958ad732d35493d4ae8e35cd0f423610b4263ff80909ce31c99f28d044a979eb8c0d124a5d4738777f984dc753fb6
6
+ metadata.gz: a0f223e4e32b83736f21750b9ebb06ab49eacd9e2ccb45d37f047b231d763cb4f4dd1effa7bb87e0376f04db89287b48a7727c544b84b96585b657a02d2fa092
7
+ data.tar.gz: '0810af3f8f3b56e7ae3b4ee4295805a9a01ee0cb34911da8d6197db60ff1d0f8ad3a37d596d8411ced98e2eae0fb13c60f904903bebea26b2302b52cdc66d3de'
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.4.0"
2
+ ".": "0.4.1"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.1](https://github.com/asjer/rubocop-asjer/compare/v0.4.0...v0.4.1) (2026-01-28)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * improve autocorrect functionality for `RailsClassOrder` cop and add Ruby 4.0 to ci ([#23](https://github.com/asjer/rubocop-asjer/issues/23)) ([16fc637](https://github.com/asjer/rubocop-asjer/commit/16fc63770f05f74e2bc005becd136af7d8ccb0d1))
9
+
3
10
  ## [0.4.0](https://github.com/asjer/rubocop-asjer/compare/v0.3.1...v0.4.0) (2026-01-23)
4
11
 
5
12
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Asjer
5
- VERSION = '0.4.0'
5
+ VERSION = '0.4.1'
6
6
  end
7
7
  end
@@ -56,34 +56,96 @@ module RuboCop
56
56
  OTHERS = %w[attr_readonly serialize].freeze
57
57
  end
58
58
 
59
+ # Autocorrect helpers for RailsClassOrder cop
60
+ module RailsClassOrderCorrector
61
+ def autocorrect(corrector, body, original, sorted)
62
+ first_target = original.min_by { |m| body.children.index(m) }
63
+ new_source = build_sorted_source(sorted, original)
64
+ corrector.replace(range_with_comments(first_target), new_source.rstrip)
65
+
66
+ (original - [first_target]).each do |method|
67
+ corrector.remove(full_method_range(method))
68
+ end
69
+ end
70
+
71
+ def range_with_comments(node)
72
+ comments = preceding_comments(node)
73
+ start_pos = comments.empty? ? node.loc.expression.begin_pos : comments.first.loc.expression.begin_pos
74
+ range_between(start_pos, node.loc.expression.end_pos)
75
+ end
76
+
77
+ def preceding_comments(node)
78
+ collect_adjacent_comments(node.loc.expression)
79
+ end
80
+
81
+ def collect_adjacent_comments(node_pos)
82
+ expected_line = node_pos.first_line - 1
83
+ comments_before_node(node_pos).take_while do |comment|
84
+ pos = comment.loc.expression
85
+ (pos.last_line == expected_line).tap { expected_line = pos.first_line - 1 }
86
+ end.reverse
87
+ end
88
+
89
+ def comments_before_node(node_pos)
90
+ processed_source.comments.select { |c| c.loc.expression.end_pos < node_pos.begin_pos }.reverse
91
+ end
92
+
93
+ def full_method_range(node)
94
+ range = range_with_comments(node)
95
+ source = processed_source.buffer.source
96
+ line_start = source.rindex("\n", range.begin_pos - 1)&.+(1) || 0
97
+ end_pos = source[range.end_pos] == "\n" ? range.end_pos + 1 : range.end_pos
98
+ range_between(line_start, end_pos)
99
+ end
100
+
101
+ def build_sorted_source(sorted, original)
102
+ indent = ' ' * original.first.loc.column
103
+ grouped = sorted.group_by { |m| method_type(m) }
104
+
105
+ %i[association callback other].filter_map do |type|
106
+ next unless grouped[type]&.any?
107
+
108
+ grouped[type].map { |m| source_with_comments(m) }.join("\n#{indent}")
109
+ end.join("\n\n#{indent}")
110
+ end
111
+
112
+ def source_with_comments(node)
113
+ range = range_with_comments(node)
114
+ processed_source.buffer.source[range.begin_pos...range.end_pos].lstrip
115
+ end
116
+ end
117
+
59
118
  # Enforces consistent ordering of declarative methods in Rails models.
60
119
  #
61
120
  # @see RailsClassOrderDefaults for default method lists
62
121
  class RailsClassOrder < Base
63
122
  extend AutoCorrector
64
123
  include RangeHelp
124
+ include RailsClassOrderCorrector
65
125
 
66
126
  MSG = 'Declarative methods should be sorted by type: associations, callbacks, then others.'
67
-
68
127
  TYPE_ORDER = { association: 0, callback: 1, other: 2 }.freeze
69
128
 
70
129
  def on_class(node)
71
130
  _name, _superclass, body = *node
72
131
  return unless body&.begin_type?
73
132
 
133
+ check_order(body)
134
+ end
135
+
136
+ private
137
+
138
+ def check_order(body)
74
139
  targets = target_methods(body)
75
140
  return if targets.empty?
76
141
 
77
142
  sorted = sort_methods(targets)
78
143
  return if targets == sorted
79
144
 
80
- add_offense(body) do |corrector|
81
- autocorrect(corrector, body, targets, sorted) if contiguous?(body, targets)
82
- end
145
+ first_misplaced = targets.zip(sorted).find { |a, e| a != e }&.first
146
+ add_offense(first_misplaced) { |corrector| autocorrect(corrector, body, targets, sorted) }
83
147
  end
84
148
 
85
- private
86
-
87
149
  def associations
88
150
  @associations ||= cop_config.fetch('Associations', RailsClassOrderDefaults::ASSOCIATIONS).map(&:to_sym)
89
151
  end
@@ -101,20 +163,11 @@ module RuboCop
101
163
  end
102
164
 
103
165
  def target_methods(body)
104
- body.children.select do |child|
105
- child.send_type? && all_target_methods.include?(child.method_name)
106
- end
166
+ body.children.select { |child| child.send_type? && all_target_methods.include?(child.method_name) }
107
167
  end
108
168
 
109
169
  def sort_methods(methods)
110
- # Use sort_by with index to make stable sort (preserve original order for equal elements)
111
- methods.each_with_index.sort_by do |method, index|
112
- [
113
- method_type_order(method),
114
- method_position_in_type(method),
115
- index
116
- ]
117
- end.map(&:first)
170
+ methods.each_with_index.sort_by { |m, i| [method_type_order(m), method_position_in_type(m), i] }.map(&:first)
118
171
  end
119
172
 
120
173
  def method_type(method)
@@ -130,51 +183,12 @@ module RuboCop
130
183
  end
131
184
 
132
185
  def method_position_in_type(method)
133
- name = method.method_name
134
- list = method_list_for_type(method_type(method))
135
- list.index(name) || list.size
186
+ method_list_for_type(method_type(method)).index(method.method_name) || 999
136
187
  end
137
188
 
138
189
  def method_list_for_type(type)
139
190
  { association: associations, callback: callbacks, other: others }[type]
140
191
  end
141
-
142
- def contiguous?(body, targets)
143
- indices = targets.map { |t| body.children.index(t) }
144
- indices.max - indices.min + 1 == indices.size
145
- end
146
-
147
- def autocorrect(corrector, _body, original, sorted)
148
- grouped = group_by_type(sorted)
149
- new_source = build_grouped_source(grouped, original)
150
- range = methods_range(original)
151
- corrector.replace(range, new_source)
152
- end
153
-
154
- def group_by_type(methods)
155
- methods.group_by { |m| method_type(m) }
156
- end
157
-
158
- def build_grouped_source(grouped, original)
159
- indent = ' ' * original.first.loc.column
160
-
161
- groups = []
162
- %i[association callback other].each do |type|
163
- next unless grouped[type]&.any?
164
-
165
- group_lines = grouped[type].map(&:source)
166
- groups << group_lines.join("\n#{indent}")
167
- end
168
-
169
- groups.join("\n\n#{indent}")
170
- end
171
-
172
- def methods_range(methods)
173
- first = methods.min_by { |m| m.loc.expression.begin_pos }
174
- last = methods.max_by { |m| m.loc.expression.end_pos }
175
-
176
- range_between(first.loc.expression.begin_pos, last.loc.expression.end_pos)
177
- end
178
192
  end
179
193
  end
180
194
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-asjer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asjer Querido