rubocop-vibe 0.3.0 → 0.4.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: e14c979862da1db7feb6dc28697248359d9320450a1bbfca24db50101d9f4c43
4
- data.tar.gz: e13a6d3fe34d9a24edc775dba8800e901a2a5a59ca5b3f35f516838e4ca79853
3
+ metadata.gz: cdbef6b6693f735e021fc40b2ff54c091942cacc146e6d7314b93597d92d5f0a
4
+ data.tar.gz: 1d612390dcb873c62803cfce7357dc6e73f2dd76cc63adff21478f62d513743f
5
5
  SHA512:
6
- metadata.gz: 1d89ddcdf3d94bb0aeca2ce767157e305a75990b540f2bd91d1e9255e26e29915da0eb7b3188d293a96b0d4bf2ce4ac25c700f4601238705e82f7c62dbdaaeac
7
- data.tar.gz: 064b6dfe86613f8af93718a277db85d6bd705d7580fa27fe69469c41579aa0e4653c14dd4bcc48b56dd1d808c752921b2f69336816fe0ef3fcbb1098dd0d22f2
6
+ metadata.gz: 4b57b54a638c0cd84c19e2096d5792c145964bfab9c96f5f47f6a19d44f17bf8830260b536f6913cacb1f154da30dd26226ac688b3c5fa074fbcd90346cfbfb9
7
+ data.tar.gz: dfec2e07080d666343b0ebd686042299eaa129884fa47c35cab9b0f5ccdd54747d7227edecc970bff1e0e3a1279c4ac8c6eedc7a29e0da54df9fbd3edbed7a8e
data/config/default.yml CHANGED
@@ -98,6 +98,12 @@ Vibe/ConsecutiveIndexedAssignmentAlignment:
98
98
  SafeAutoCorrect: true
99
99
  VersionAdded: "0.3.0"
100
100
 
101
+ Vibe/ConsecutiveInstanceVariableAssignmentAlignment:
102
+ Description: "Enforces alignment of consecutive instance variable assignments at the = operator."
103
+ Enabled: true
104
+ SafeAutoCorrect: true
105
+ VersionAdded: "0.4.0"
106
+
101
107
  Vibe/ConsecutiveLetAlignment:
102
108
  Description: "Enforces alignment of consecutive let declarations at the { brace."
103
109
  Enabled: true
@@ -122,6 +128,12 @@ Vibe/IsExpectedOneLiner:
122
128
  SafeAutoCorrect: true
123
129
  VersionAdded: "0.1.0"
124
130
 
131
+ Vibe/LetOrder:
132
+ Description: "Enforces alphabetical ordering of consecutive let declarations."
133
+ Enabled: true
134
+ SafeAutoCorrect: true
135
+ VersionAdded: "0.4.0"
136
+
125
137
  Vibe/MultilineHashArgumentStyle:
126
138
  Description: "Enforces one-per-line and alphabetical ordering for hash arguments in multiline method calls."
127
139
  Enabled: true
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Vibe
6
+ # Enforces alignment of consecutive instance variable assignments at the `=` operator.
7
+ #
8
+ # Consecutive assignments (with no blank lines between) should align their
9
+ # `=` operators for better readability. Groups are broken by blank lines.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # @user = create(:user)
14
+ # @character = create(:character)
15
+ # @input = "test"
16
+ #
17
+ # # good
18
+ # @user = create(:user)
19
+ # @character = create(:character)
20
+ # @input = "test"
21
+ #
22
+ # # good - blank line breaks the group
23
+ # @user = create(:user)
24
+ # @character = create(:character)
25
+ #
26
+ # @service = Users::Activate.new
27
+ # @activation = service.call
28
+ class ConsecutiveInstanceVariableAssignmentAlignment < Base
29
+ extend AutoCorrector
30
+ include AlignmentHelpers
31
+
32
+ MSG = "Align consecutive instance variable assignments at the = operator."
33
+
34
+ # Check block nodes for assignment alignment.
35
+ #
36
+ # @param [RuboCop::AST::Node] node The block node.
37
+ # @return [void]
38
+ def on_block(node)
39
+ if node.body
40
+ check_assignments_in_body(node.body)
41
+ end
42
+ end
43
+ alias on_numblock on_block
44
+
45
+ # Check method definitions for assignment alignment.
46
+ #
47
+ # @param [RuboCop::AST::Node] node The def node.
48
+ # @return [void]
49
+ def on_def(node)
50
+ if node.body
51
+ check_assignments_in_body(node.body)
52
+ end
53
+ end
54
+ alias on_defs on_def
55
+
56
+ private
57
+
58
+ # Check assignments in a body node.
59
+ #
60
+ # @param [RuboCop::AST::Node] body The body node.
61
+ # @return [void]
62
+ def check_assignments_in_body(body)
63
+ statements = extract_statements(body)
64
+
65
+ return if statements.size < 2
66
+
67
+ groups = group_consecutive_statements(statements, &:ivasgn_type?)
68
+
69
+ groups.each { |group| check_group_alignment(group) }
70
+ end
71
+
72
+ # Check alignment for a group of assignments.
73
+ #
74
+ # @param [Array<RuboCop::AST::Node>] group The assignment group.
75
+ # @return [void]
76
+ def check_group_alignment(group)
77
+ columns = group.map { |asgn| asgn.loc.operator.column }
78
+ target_column = columns.max
79
+
80
+ group.each do |asgn|
81
+ current_column = asgn.loc.operator.column
82
+
83
+ next if current_column == target_column
84
+
85
+ add_offense(asgn.loc.name) do |corrector|
86
+ autocorrect_alignment(corrector, asgn, target_column)
87
+ end
88
+ end
89
+ end
90
+
91
+ # Auto-correct the alignment of an assignment.
92
+ #
93
+ # @param [RuboCop::AST::Corrector] corrector The corrector.
94
+ # @param [RuboCop::AST::Node] asgn The assignment node.
95
+ # @param [Integer] target_column The target column for alignment.
96
+ # @return [void]
97
+ def autocorrect_alignment(corrector, asgn, target_column)
98
+ variable_name_end = asgn.loc.name.end_pos
99
+ operator_start = asgn.loc.operator.begin_pos
100
+ total_spaces = calculate_total_spaces(asgn, target_column)
101
+
102
+ corrector.replace(
103
+ range_between(variable_name_end, operator_start),
104
+ " " * total_spaces
105
+ )
106
+ end
107
+
108
+ # Calculate total spaces needed for alignment.
109
+ #
110
+ # @param [RuboCop::AST::Node] asgn The assignment node.
111
+ # @param [Integer] target_column The target column for alignment.
112
+ # @return [Integer] The number of spaces (minimum 1).
113
+ def calculate_total_spaces(asgn, target_column)
114
+ current_column = asgn.loc.operator.column
115
+ current_spaces = asgn.loc.operator.begin_pos - asgn.loc.name.end_pos
116
+ spaces_needed = target_column - current_column
117
+
118
+ [1, current_spaces + spaces_needed].max
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Vibe
6
+ # Enforces alphabetical ordering of consecutive `let` declarations.
7
+ #
8
+ # Consecutive `let` declarations (with no blank lines between) should be
9
+ # alphabetically ordered by their symbol name for better readability and
10
+ # easier scanning. Groups are broken by blank lines or non-let statements.
11
+ #
12
+ # @example
13
+ # # bad
14
+ # let(:subcategory) { create(:category, :subcategory) }
15
+ # let(:budget) { subcategory.budget }
16
+ # let(:category) { subcategory.parent }
17
+ #
18
+ # # good
19
+ # let(:budget) { subcategory.budget }
20
+ # let(:category) { subcategory.parent }
21
+ # let(:subcategory) { create(:category, :subcategory) }
22
+ #
23
+ # # good - blank line breaks the group
24
+ # let(:zebra) { create(:zebra) }
25
+ #
26
+ # let(:apple) { create(:apple) }
27
+ class LetOrder < Base
28
+ extend AutoCorrector
29
+ include SpecFileHelper
30
+ include AlignmentHelpers
31
+
32
+ MSG = "Order consecutive `let` declarations alphabetically."
33
+
34
+ # @!method let_declaration?(node)
35
+ # Check if node is a let/let! declaration.
36
+ def_node_matcher :let_declaration?, <<~PATTERN
37
+ (block (send nil? {:let :let!} (sym _)) ...)
38
+ PATTERN
39
+
40
+ # Check describe/context blocks for let ordering.
41
+ #
42
+ # @param [RuboCop::AST::Node] node The block node.
43
+ # @return [void]
44
+ def on_block(node)
45
+ return unless spec_file?
46
+ return unless describe_or_context?(node)
47
+ return unless node.body
48
+
49
+ check_lets_in_body(node.body)
50
+ end
51
+ alias on_numblock on_block
52
+
53
+ private
54
+
55
+ # Check if block is a describe or context block.
56
+ #
57
+ # @param [RuboCop::AST::Node] node The block node.
58
+ # @return [Boolean]
59
+ def describe_or_context?(node)
60
+ node.send_node && %i(describe context).include?(node.method_name)
61
+ end
62
+
63
+ # Check let declarations in a body node.
64
+ #
65
+ # @param [RuboCop::AST::Node] body The body node.
66
+ # @return [void]
67
+ def check_lets_in_body(body)
68
+ statements = extract_statements(body)
69
+
70
+ return if statements.size < 2
71
+
72
+ groups = group_consecutive_statements(statements) { |s| let_declaration?(s) }
73
+
74
+ groups.each { |group| check_group_order(group) }
75
+ end
76
+
77
+ # Check ordering for a group of let declarations.
78
+ #
79
+ # @param [Array<RuboCop::AST::Node>] group The let group.
80
+ # @return [void]
81
+ def check_group_order(group)
82
+ return if alphabetically_ordered?(group)
83
+
84
+ violations = find_ordering_violations(group)
85
+
86
+ violations.each do |let|
87
+ add_offense(let.send_node) do |corrector|
88
+ autocorrect(corrector, group)
89
+ end
90
+ end
91
+ end
92
+
93
+ # Check if let declarations are alphabetically ordered.
94
+ #
95
+ # @param [Array<RuboCop::AST::Node>] group The let group.
96
+ # @return [Boolean]
97
+ def alphabetically_ordered?(group)
98
+ names = group.map { |let| extract_let_name(let) }
99
+
100
+ names == names.sort
101
+ end
102
+
103
+ # Extract the symbol name from a let declaration.
104
+ #
105
+ # @param [RuboCop::AST::Node] let The let block node.
106
+ # @return [String]
107
+ def extract_let_name(let)
108
+ let.send_node.first_argument.value.to_s
109
+ end
110
+
111
+ # Find let declarations that violate ordering.
112
+ #
113
+ # @param [Array<RuboCop::AST::Node>] group The let group.
114
+ # @return [Array<RuboCop::AST::Node>] Lets that violate ordering.
115
+ def find_ordering_violations(group)
116
+ violations = []
117
+
118
+ group.each_cons(2) do |current, following|
119
+ current_name = extract_let_name(current)
120
+ following_name = extract_let_name(following)
121
+
122
+ violations << following if current_name > following_name
123
+ end
124
+
125
+ violations.uniq
126
+ end
127
+
128
+ # Auto-correct by reordering let declarations.
129
+ #
130
+ # @param [RuboCop::AST::Corrector] corrector The corrector.
131
+ # @param [Array<RuboCop::AST::Node>] group The let group.
132
+ # @return [void]
133
+ def autocorrect(corrector, group)
134
+ sorted = group.sort_by { |let| extract_let_name(let) }
135
+
136
+ group.each_with_index do |let, index|
137
+ sorted_let = sorted[index]
138
+
139
+ next if let == sorted_let
140
+
141
+ corrector.replace(let, sorted_let.source)
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -9,10 +9,12 @@ require_relative "vibe/class_organization"
9
9
  require_relative "vibe/consecutive_assignment_alignment"
10
10
  require_relative "vibe/consecutive_constant_alignment"
11
11
  require_relative "vibe/consecutive_indexed_assignment_alignment"
12
+ require_relative "vibe/consecutive_instance_variable_assignment_alignment"
12
13
  require_relative "vibe/consecutive_let_alignment"
13
14
  require_relative "vibe/describe_block_order"
14
15
  require_relative "vibe/explicit_return_conditional"
15
16
  require_relative "vibe/is_expected_one_liner"
17
+ require_relative "vibe/let_order"
16
18
  require_relative "vibe/multiline_hash_argument_style"
17
19
  require_relative "vibe/no_assigns_attribute_testing"
18
20
  require_relative "vibe/no_compound_conditions"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Vibe
5
- VERSION = "0.3.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-vibe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tristan Dunn
@@ -93,10 +93,12 @@ files:
93
93
  - lib/rubocop/cop/vibe/consecutive_assignment_alignment.rb
94
94
  - lib/rubocop/cop/vibe/consecutive_constant_alignment.rb
95
95
  - lib/rubocop/cop/vibe/consecutive_indexed_assignment_alignment.rb
96
+ - lib/rubocop/cop/vibe/consecutive_instance_variable_assignment_alignment.rb
96
97
  - lib/rubocop/cop/vibe/consecutive_let_alignment.rb
97
98
  - lib/rubocop/cop/vibe/describe_block_order.rb
98
99
  - lib/rubocop/cop/vibe/explicit_return_conditional.rb
99
100
  - lib/rubocop/cop/vibe/is_expected_one_liner.rb
101
+ - lib/rubocop/cop/vibe/let_order.rb
100
102
  - lib/rubocop/cop/vibe/mixin/alignment_helpers.rb
101
103
  - lib/rubocop/cop/vibe/mixin/spec_file_helper.rb
102
104
  - lib/rubocop/cop/vibe/multiline_hash_argument_style.rb