rubocop-vibe 0.4.0 → 0.6.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +38 -0
  3. data/lib/rubocop/cop/vibe/attr_order.rb +87 -0
  4. data/lib/rubocop/cop/vibe/blank_line_after_assignment.rb +56 -55
  5. data/lib/rubocop/cop/vibe/blank_line_before_expectation.rb +40 -39
  6. data/lib/rubocop/cop/vibe/class_organization.rb +262 -361
  7. data/lib/rubocop/cop/vibe/consecutive_assignment_alignment.rb +31 -30
  8. data/lib/rubocop/cop/vibe/consecutive_constant_alignment.rb +30 -30
  9. data/lib/rubocop/cop/vibe/consecutive_indexed_assignment_alignment.rb +46 -45
  10. data/lib/rubocop/cop/vibe/consecutive_instance_variable_assignment_alignment.rb +31 -30
  11. data/lib/rubocop/cop/vibe/consecutive_let_alignment.rb +39 -38
  12. data/lib/rubocop/cop/vibe/consecutive_scope_alignment.rb +132 -0
  13. data/lib/rubocop/cop/vibe/constant_alpha_order.rb +144 -0
  14. data/lib/rubocop/cop/vibe/describe_block_order.rb +76 -68
  15. data/lib/rubocop/cop/vibe/explicit_return_conditional.rb +70 -69
  16. data/lib/rubocop/cop/vibe/is_expected_one_liner.rb +16 -16
  17. data/lib/rubocop/cop/vibe/keyword_argument_order.rb +190 -0
  18. data/lib/rubocop/cop/vibe/let_order.rb +35 -34
  19. data/lib/rubocop/cop/vibe/multiline_hash_argument_style.rb +63 -63
  20. data/lib/rubocop/cop/vibe/no_compound_conditions.rb +30 -30
  21. data/lib/rubocop/cop/vibe/no_rubocop_disable.rb +23 -24
  22. data/lib/rubocop/cop/vibe/no_skipped_tests.rb +10 -10
  23. data/lib/rubocop/cop/vibe/no_unless_guard_clause.rb +96 -96
  24. data/lib/rubocop/cop/vibe/prefer_one_liner_expectation.rb +36 -35
  25. data/lib/rubocop/cop/vibe/raise_unless_block.rb +22 -19
  26. data/lib/rubocop/cop/vibe/rspec_before_block_style.rb +19 -18
  27. data/lib/rubocop/cop/vibe/rspec_stub_chain_style.rb +100 -100
  28. data/lib/rubocop/cop/vibe/validate_after_validates.rb +155 -0
  29. data/lib/rubocop/cop/vibe/validates_alpha_order.rb +166 -0
  30. data/lib/rubocop/cop/vibe_cops.rb +6 -0
  31. data/lib/rubocop/vibe/version.rb +1 -1
  32. metadata +12 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cdbef6b6693f735e021fc40b2ff54c091942cacc146e6d7314b93597d92d5f0a
4
- data.tar.gz: 1d612390dcb873c62803cfce7357dc6e73f2dd76cc63adff21478f62d513743f
3
+ metadata.gz: 32efe500f7fb50e4005a4ef34081405eee947bc058b96c684e60d3edb1095976
4
+ data.tar.gz: 79b4d44786594d509536e369756ead61b0cd34cd54cf288f857b4fa04e90f0a5
5
5
  SHA512:
6
- metadata.gz: 4b57b54a638c0cd84c19e2096d5792c145964bfab9c96f5f47f6a19d44f17bf8830260b536f6913cacb1f154da30dd26226ac688b3c5fa074fbcd90346cfbfb9
7
- data.tar.gz: dfec2e07080d666343b0ebd686042299eaa129884fa47c35cab9b0f5ccdd54747d7227edecc970bff1e0e3a1279c4ac8c6eedc7a29e0da54df9fbd3edbed7a8e
6
+ metadata.gz: 62fb11ebb915d21241f1c0da9b6684564e457aeaa0469ce2fc5ec708bfaf1754f8b4f85dfc7167b7ea68b9e498424d6feb3e6afb57673f28a2921e88fba56f3d
7
+ data.tar.gz: 10bdf89f1dcfd15dbdfe06d293d3a6633193ecf953d50133be333d50b70b3ed7f84f081f6d40c4cbafd3fa68ae50839958ad1fe92eafddd44151b3f1c068e090
data/config/default.yml CHANGED
@@ -62,6 +62,12 @@ Style/StringLiterals:
62
62
  Style/StringLiteralsInInterpolation:
63
63
  EnforcedStyle: double_quotes
64
64
 
65
+ Vibe/AttrOrder:
66
+ Description: "Enforces alphabetical ordering of attr_reader, attr_writer, and attr_accessor arguments."
67
+ Enabled: true
68
+ SafeAutoCorrect: true
69
+ VersionAdded: "0.5.0"
70
+
65
71
  Vibe/BlankLineAfterAssignment:
66
72
  Description: "Enforces a blank line after variable assignments when followed by other code."
67
73
  Enabled: true
@@ -79,6 +85,7 @@ Vibe/ClassOrganization:
79
85
  Enabled: true
80
86
  SafeAutoCorrect: false
81
87
  VersionAdded: "0.1.0"
88
+ VersionChanged: "0.6.0"
82
89
 
83
90
  Vibe/ConsecutiveAssignmentAlignment:
84
91
  Description: "Enforces alignment of consecutive variable assignments at the = operator."
@@ -110,11 +117,24 @@ Vibe/ConsecutiveLetAlignment:
110
117
  SafeAutoCorrect: true
111
118
  VersionAdded: "0.2.0"
112
119
 
120
+ Vibe/ConsecutiveScopeAlignment:
121
+ Description: "Enforces alignment of consecutive scope declarations at the -> arrow."
122
+ Enabled: true
123
+ SafeAutoCorrect: true
124
+ VersionAdded: "0.5.0"
125
+
126
+ Vibe/ConstantAlphaOrder:
127
+ Description: "Enforces alphabetical ordering of consecutive constant declarations by name."
128
+ Enabled: true
129
+ SafeAutoCorrect: false
130
+ VersionAdded: "0.5.0"
131
+
113
132
  Vibe/DescribeBlockOrder:
114
133
  Description: "Enforces consistent ordering of describe blocks in RSpec files."
115
134
  Enabled: true
116
135
  SafeAutoCorrect: false
117
136
  VersionAdded: "0.1.0"
137
+ VersionChanged: "0.6.0"
118
138
 
119
139
  Vibe/ExplicitReturnConditional:
120
140
  Description: "Enforces explicit if/else/end blocks instead of ternary or trailing conditionals for return values."
@@ -128,6 +148,12 @@ Vibe/IsExpectedOneLiner:
128
148
  SafeAutoCorrect: true
129
149
  VersionAdded: "0.1.0"
130
150
 
151
+ Vibe/KeywordArgumentOrder:
152
+ Description: "Enforces alphabetical ordering of keyword arguments and their YARD documentation."
153
+ Enabled: true
154
+ SafeAutoCorrect: true
155
+ VersionAdded: "0.5.0"
156
+
131
157
  Vibe/LetOrder:
132
158
  Description: "Enforces alphabetical ordering of consecutive let declarations."
133
159
  Enabled: true
@@ -196,3 +222,15 @@ Vibe/ServiceCallMethod:
196
222
  Description: "Service objects should define `self.call` and `call` methods."
197
223
  Enabled: true
198
224
  VersionAdded: "0.1.0"
225
+
226
+ Vibe/ValidateAfterValidates:
227
+ Description: "Enforces that validate calls appear after validates declarations in Rails models."
228
+ Enabled: true
229
+ SafeAutoCorrect: true
230
+ VersionAdded: "0.5.0"
231
+
232
+ Vibe/ValidatesAlphaOrder:
233
+ Description: "Enforces alphabetical ordering of consecutive validates declarations by attribute name."
234
+ Enabled: true
235
+ SafeAutoCorrect: true
236
+ VersionAdded: "0.5.0"
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Vibe
6
+ # Enforces alphabetical ordering of arguments to `attr_reader`,
7
+ # `attr_writer`, and `attr_accessor` declarations.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # attr_reader :id, :content, :timestamp, :raw
12
+ #
13
+ # # good
14
+ # attr_reader :content, :id, :raw, :timestamp
15
+ #
16
+ # # bad
17
+ # attr_accessor :zebra, :apple
18
+ #
19
+ # # good
20
+ # attr_accessor :apple, :zebra
21
+ class AttrOrder < Base
22
+ extend AutoCorrector
23
+
24
+ MSG = "Order `%<method>s` arguments alphabetically."
25
+
26
+ ATTR_METHODS = %i(attr_reader attr_writer attr_accessor).freeze
27
+
28
+ # Check attr_* method calls for alphabetical ordering.
29
+ #
30
+ # @param [RuboCop::AST::Node] node The send node.
31
+ # @return [void]
32
+ def on_send(node)
33
+ return unless attr_method?(node)
34
+ return unless node.arguments.size > 1
35
+ return if all_symbols?(node.arguments) && alphabetically_ordered?(node.arguments)
36
+
37
+ add_offense(node, message: format(MSG, method: node.method_name)) do |corrector|
38
+ autocorrect(corrector, node)
39
+ end
40
+ end
41
+ alias on_csend on_send
42
+
43
+ private
44
+
45
+ # Check if all arguments are symbols.
46
+ #
47
+ # @param [Array<RuboCop::AST::Node>] arguments The arguments.
48
+ # @return [Boolean]
49
+ def all_symbols?(arguments)
50
+ arguments.all?(&:sym_type?)
51
+ end
52
+
53
+ # Check if arguments are alphabetically ordered.
54
+ #
55
+ # @param [Array<RuboCop::AST::Node>] arguments The arguments.
56
+ # @return [Boolean]
57
+ def alphabetically_ordered?(arguments)
58
+ names = arguments.map { |arg| arg.value.to_s }
59
+
60
+ names == names.sort
61
+ end
62
+
63
+ # Check if the node is an attr_* method call.
64
+ #
65
+ # @param [RuboCop::AST::Node] node The send node.
66
+ # @return [Boolean]
67
+ def attr_method?(node)
68
+ node.receiver.nil? && ATTR_METHODS.include?(node.method_name)
69
+ end
70
+
71
+ # Auto-correct by reordering arguments alphabetically.
72
+ #
73
+ # @param [RuboCop::AST::Corrector] corrector The corrector.
74
+ # @param [RuboCop::AST::Node] node The send node.
75
+ # @return [void]
76
+ def autocorrect(corrector, node)
77
+ sorted_args = node.arguments.sort_by { |arg| arg.value.to_s }
78
+ sorted_source = sorted_args.map(&:source).join(", ")
79
+
80
+ args_range = node.first_argument.source_range.join(node.last_argument.source_range)
81
+
82
+ corrector.replace(args_range, sorted_source)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -53,6 +53,7 @@ module RuboCop
53
53
  end
54
54
  end
55
55
  alias on_numblock on_block
56
+ alias on_itblock on_block
56
57
 
57
58
  # Check method definitions for assignment statements.
58
59
  #
@@ -67,6 +68,45 @@ module RuboCop
67
68
 
68
69
  private
69
70
 
71
+ # Get the variable name from an assignment node.
72
+ #
73
+ # @param [RuboCop::AST::Node] node The assignment node.
74
+ # @return [Symbol, nil]
75
+ def assigned_variable_name(node)
76
+ return node.children.first if node.lvasgn_type?
77
+
78
+ target = node.children.first
79
+
80
+ if target.lvasgn_type?
81
+ target.children.first
82
+ end
83
+ end
84
+
85
+ # Check if a node is a variable assignment.
86
+ #
87
+ # @param [RuboCop::AST::Node] node The node to check.
88
+ # @return [Boolean]
89
+ def assignment?(node)
90
+ node.type?(:lvasgn, :op_asgn, :or_asgn, :and_asgn)
91
+ end
92
+
93
+ # Get the value being assigned.
94
+ #
95
+ # @param [RuboCop::AST::Node] node The assignment node.
96
+ # @return [RuboCop::AST::Node, nil]
97
+ def assignment_value(node)
98
+ node.children.last
99
+ end
100
+
101
+ # Check if there's a blank line between two statements.
102
+ #
103
+ # @param [RuboCop::AST::Node] previous_node The previous statement.
104
+ # @param [RuboCop::AST::Node] current_node The current statement.
105
+ # @return [Boolean]
106
+ def blank_line_between?(previous_node, current_node)
107
+ current_node.loc.line - previous_node.loc.last_line > 1
108
+ end
109
+
70
110
  # Check the body for missing blank lines after assignments.
71
111
  #
72
112
  # @param [RuboCop::AST::Node] body The body node.
@@ -81,18 +121,6 @@ module RuboCop
81
121
  end
82
122
  end
83
123
 
84
- # Extract statements from a body node.
85
- #
86
- # @param [RuboCop::AST::Node] body The body node.
87
- # @return [Array<RuboCop::AST::Node>]
88
- def extract_statements(body)
89
- if body.begin_type?
90
- body.children
91
- else
92
- [body]
93
- end
94
- end
95
-
96
124
  # Check a pair of statements for missing blank line after assignment.
97
125
  #
98
126
  # @param [RuboCop::AST::Node] current The current statement.
@@ -113,17 +141,6 @@ module RuboCop
113
141
  end
114
142
  end
115
143
 
116
- # Get the inner statement from a modifier node.
117
- #
118
- # @param [RuboCop::AST::Node] node The node to unwrap.
119
- # @return [RuboCop::AST::Node]
120
- def inner_statement(node)
121
- return node.if_branch if node.type?(:if) && node.modifier_form?
122
- return node.body if node.type?(:while, :until) && node.modifier_form?
123
-
124
- node
125
- end
126
-
127
144
  # Check if both statements are FactoryBot calls.
128
145
  #
129
146
  # @param [RuboCop::AST::Node] assignment The assignment node.
@@ -133,12 +150,16 @@ module RuboCop
133
150
  factory_bot_call?(assignment_value(assignment)) && factory_bot_call?(following)
134
151
  end
135
152
 
136
- # Get the value being assigned.
153
+ # Extract statements from a body node.
137
154
  #
138
- # @param [RuboCop::AST::Node] node The assignment node.
139
- # @return [RuboCop::AST::Node, nil]
140
- def assignment_value(node)
141
- node.children.last
155
+ # @param [RuboCop::AST::Node] body The body node.
156
+ # @return [Array<RuboCop::AST::Node>]
157
+ def extract_statements(body)
158
+ if body.begin_type?
159
+ body.children
160
+ else
161
+ [body]
162
+ end
142
163
  end
143
164
 
144
165
  # Check if a node is a FactoryBot method call.
@@ -166,18 +187,15 @@ module RuboCop
166
187
  receiver.lvar_type? && receiver.children.first == var_name
167
188
  end
168
189
 
169
- # Get the variable name from an assignment node.
190
+ # Get the inner statement from a modifier node.
170
191
  #
171
- # @param [RuboCop::AST::Node] node The assignment node.
172
- # @return [Symbol, nil]
173
- def assigned_variable_name(node)
174
- return node.children.first if node.lvasgn_type?
175
-
176
- target = node.children.first
192
+ # @param [RuboCop::AST::Node] node The node to unwrap.
193
+ # @return [RuboCop::AST::Node]
194
+ def inner_statement(node)
195
+ return node.if_branch if node.type?(:if) && node.modifier_form?
196
+ return node.body if node.type?(:while, :until) && node.modifier_form?
177
197
 
178
- if target.lvasgn_type?
179
- target.children.first
180
- end
198
+ node
181
199
  end
182
200
 
183
201
  # Get the leftmost receiver in a method chain.
@@ -194,23 +212,6 @@ module RuboCop
194
212
 
195
213
  current
196
214
  end
197
-
198
- # Check if a node is a variable assignment.
199
- #
200
- # @param [RuboCop::AST::Node] node The node to check.
201
- # @return [Boolean]
202
- def assignment?(node)
203
- node.type?(:lvasgn, :op_asgn, :or_asgn, :and_asgn)
204
- end
205
-
206
- # Check if there's a blank line between two statements.
207
- #
208
- # @param [RuboCop::AST::Node] previous_node The previous statement.
209
- # @param [RuboCop::AST::Node] current_node The current statement.
210
- # @return [Boolean]
211
- def blank_line_between?(previous_node, current_node)
212
- current_node.loc.line - previous_node.loc.last_line > 1
213
- end
214
215
  end
215
216
  end
216
217
  end
@@ -51,39 +51,17 @@ module RuboCop
51
51
  end
52
52
  end
53
53
  alias on_numblock on_block
54
+ alias on_itblock on_block
54
55
 
55
56
  private
56
57
 
57
- # Check if the block should be processed.
58
+ # Check if there's a blank line between two statements.
58
59
  #
59
- # @param [RuboCop::AST::Node] node The block node.
60
+ # @param [RuboCop::AST::Node] previous_node The previous statement.
61
+ # @param [RuboCop::AST::Node] current_node The current statement.
60
62
  # @return [Boolean]
61
- def processable_block?(node)
62
- spec_file? && example_block?(node) && node.body
63
- end
64
-
65
- # Extract statements from the block body.
66
- #
67
- # @param [RuboCop::AST::Node] body The block body.
68
- # @return [Array<RuboCop::AST::Node>]
69
- def extract_statements(body)
70
- if body.begin_type?
71
- body.children
72
- else
73
- [body]
74
- end
75
- end
76
-
77
- # Check statements for missing blank lines before expectations.
78
- #
79
- # @param [Array<RuboCop::AST::Node>] statements The statements to check.
80
- # @return [void]
81
- def check_statements(statements)
82
- statements.each_with_index do |statement, index|
83
- next if index.zero?
84
-
85
- check_statement_pair(statements[index - 1], statement)
86
- end
63
+ def blank_line_between?(previous_node, current_node)
64
+ current_node.loc.line - previous_node.loc.last_line > 1
87
65
  end
88
66
 
89
67
  # Check a pair of statements for missing blank line.
@@ -101,14 +79,27 @@ module RuboCop
101
79
  register_offense(expect_node, previous_statement)
102
80
  end
103
81
 
104
- # Register an offense for missing blank line.
82
+ # Check statements for missing blank lines before expectations.
105
83
  #
106
- # @param [RuboCop::AST::Node] expect_node The expect node.
107
- # @param [RuboCop::AST::Node] previous_statement The previous statement.
84
+ # @param [Array<RuboCop::AST::Node>] statements The statements to check.
108
85
  # @return [void]
109
- def register_offense(expect_node, previous_statement)
110
- add_offense(expect_node.loc.selector) do |corrector|
111
- corrector.insert_after(previous_statement, "\n")
86
+ def check_statements(statements)
87
+ statements.each_with_index do |statement, index|
88
+ next if index.zero?
89
+
90
+ check_statement_pair(statements[index - 1], statement)
91
+ end
92
+ end
93
+
94
+ # Extract statements from the block body.
95
+ #
96
+ # @param [RuboCop::AST::Node] body The block body.
97
+ # @return [Array<RuboCop::AST::Node>]
98
+ def extract_statements(body)
99
+ if body.begin_type?
100
+ body.children
101
+ else
102
+ [body]
112
103
  end
113
104
  end
114
105
 
@@ -132,13 +123,23 @@ module RuboCop
132
123
  node.each_descendant(:send).find { |send_node| expect_call?(send_node) }
133
124
  end
134
125
 
135
- # Check if there's a blank line between two statements.
126
+ # Check if the block should be processed.
136
127
  #
137
- # @param [RuboCop::AST::Node] previous_node The previous statement.
138
- # @param [RuboCop::AST::Node] current_node The current statement.
128
+ # @param [RuboCop::AST::Node] node The block node.
139
129
  # @return [Boolean]
140
- def blank_line_between?(previous_node, current_node)
141
- current_node.loc.line - previous_node.loc.last_line > 1
130
+ def processable_block?(node)
131
+ spec_file? && example_block?(node) && node.body
132
+ end
133
+
134
+ # Register an offense for missing blank line.
135
+ #
136
+ # @param [RuboCop::AST::Node] expect_node The expect node.
137
+ # @param [RuboCop::AST::Node] previous_statement The previous statement.
138
+ # @return [void]
139
+ def register_offense(expect_node, previous_statement)
140
+ add_offense(expect_node.loc.selector) do |corrector|
141
+ corrector.insert_after(previous_statement, "\n")
142
+ end
142
143
  end
143
144
  end
144
145
  end