rubocop-canon 0.5.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.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 899e2d0ddeff784568a001baef67ad0d3e42cf79178a89be152a3daaea76211d
|
|
4
|
+
data.tar.gz: a2e3f4f4e9cb206feb78327e911762bcbd42a9f082454da51251cfbfc20dd21d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1b5e6bd6c16a23b28e8ab256dadad94566e0e3ed7780273072d09736758ed804bc42cc15928e60898a06e64199fa0af166c9f9d86e875aa2fad9cbd74b84352
|
|
7
|
+
data.tar.gz: 29236733c6b92470a145bb9ca1d1fd4182c365f5bbdd14aba418bd9d57898314c6721bba2c64da8c0089270f4f33f02ed3c725c476053c6a22d097397fc67d74
|
|
@@ -7,17 +7,23 @@ module RuboCop
|
|
|
7
7
|
#
|
|
8
8
|
# A cop mixing this in supplies the decision — how many blank lines a
|
|
9
9
|
# pair of statements takes — and leaves the counting, the comment guard,
|
|
10
|
-
# the source ranges and the corrections here.
|
|
10
|
+
# the source ranges and the corrections here. A statement ends where its
|
|
11
|
+
# last heredoc ends, so a heredoc is part of the statement, not blank
|
|
12
|
+
# lines after it.
|
|
11
13
|
module BlankLineHelp
|
|
12
14
|
include RangeHelp
|
|
13
15
|
|
|
14
16
|
BLOCK_TYPES = %i[block numblock].freeze
|
|
17
|
+
HEREDOC_TYPES = %i[str dstr xstr].freeze
|
|
15
18
|
MSG_MULTILINE = 'Add a blank line around the multiline statement.'
|
|
16
19
|
|
|
17
20
|
private
|
|
18
21
|
|
|
19
22
|
def body_statements(node)
|
|
20
|
-
|
|
23
|
+
statements(node.body)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def statements(body)
|
|
21
27
|
return [] if body.nil?
|
|
22
28
|
return body.children if body.begin_type?
|
|
23
29
|
|
|
@@ -25,11 +31,11 @@ module RuboCop
|
|
|
25
31
|
end
|
|
26
32
|
|
|
27
33
|
def blank_lines_between(previous, following)
|
|
28
|
-
following.first_line - previous
|
|
34
|
+
following.first_line - end_line(previous) - 1
|
|
29
35
|
end
|
|
30
36
|
|
|
31
37
|
def multiline?(node)
|
|
32
|
-
node.first_line != node
|
|
38
|
+
node.first_line != end_line(node)
|
|
33
39
|
end
|
|
34
40
|
|
|
35
41
|
def multiline_pair?(previous, following)
|
|
@@ -38,6 +44,14 @@ module RuboCop
|
|
|
38
44
|
multiline?(following)
|
|
39
45
|
end
|
|
40
46
|
|
|
47
|
+
def end_line(node)
|
|
48
|
+
[node.last_line, *heredoc_end_lines(node)].max
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def heredoc_end_lines(node)
|
|
52
|
+
node.each_node(*HEREDOC_TYPES).select(&:heredoc?).map { |heredoc| heredoc.loc.heredoc_end.line }
|
|
53
|
+
end
|
|
54
|
+
|
|
41
55
|
def require_blank_line(previous, following, message)
|
|
42
56
|
return if comments_between?(previous, following)
|
|
43
57
|
return unless blank_lines_between(previous, following).zero?
|
|
@@ -54,7 +68,7 @@ module RuboCop
|
|
|
54
68
|
|
|
55
69
|
def comments_between?(previous, following)
|
|
56
70
|
processed_source.comments.any? do |comment|
|
|
57
|
-
comment.loc.line >= previous
|
|
71
|
+
comment.loc.line >= end_line(previous) && comment.loc.line < following.first_line
|
|
58
72
|
end
|
|
59
73
|
end
|
|
60
74
|
|
|
@@ -66,7 +80,7 @@ module RuboCop
|
|
|
66
80
|
|
|
67
81
|
def register_missing_blank_line(previous, following, message)
|
|
68
82
|
add_offense(first_line_range(following), message:) do |corrector|
|
|
69
|
-
corrector.insert_after(line_range(previous
|
|
83
|
+
corrector.insert_after(line_range(end_line(previous)), "\n")
|
|
70
84
|
end
|
|
71
85
|
end
|
|
72
86
|
|
|
@@ -94,11 +108,11 @@ module RuboCop
|
|
|
94
108
|
end
|
|
95
109
|
|
|
96
110
|
def blank_line_range(previous)
|
|
97
|
-
line_range(previous
|
|
111
|
+
line_range(end_line(previous) + 1)
|
|
98
112
|
end
|
|
99
113
|
|
|
100
114
|
def newline_range(previous)
|
|
101
|
-
range_between(line_range(previous
|
|
115
|
+
range_between(line_range(end_line(previous)).end_pos, line_range(end_line(previous) + 1).end_pos)
|
|
102
116
|
end
|
|
103
117
|
|
|
104
118
|
def first_line_range(node)
|
|
@@ -3,19 +3,30 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Canon
|
|
6
|
-
# Enforces blank lines between declaration groups in a class, module
|
|
7
|
-
# DSL block body.
|
|
6
|
+
# Enforces blank lines between declaration groups in a class, module,
|
|
7
|
+
# singleton class or DSL block body.
|
|
8
8
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
9
|
+
# Every method name is its own group: two declarations calling the same
|
|
10
|
+
# method take no blank line between them, and two calling different
|
|
11
|
+
# methods take exactly one. `GroupedMethods` merges names into one
|
|
12
|
+
# group — `belongs_to` with `has_many`, `validate` with `validates`.
|
|
13
|
+
# Constants are a group of their own, and so are the two Ruby families
|
|
14
|
+
# RuboCop's layout cops already treat as one: `attr`, `attr_accessor`,
|
|
15
|
+
# `attr_reader` and `attr_writer`; `extend`, `include` and `prepend`.
|
|
14
16
|
#
|
|
15
|
-
# A declaration
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
17
|
+
# A declaration is a call without a receiver or on `self`, or a constant
|
|
18
|
+
# assignment. A declaration spanning several lines, a block and a method
|
|
19
|
+
# definition are each a group of one whatever they call, so they always
|
|
20
|
+
# stand apart from their neighbours. Two definitions in a row belong to
|
|
21
|
+
# `Layout/EmptyLineBetweenDefs` and the lines around an access modifier
|
|
22
|
+
# to `Layout/EmptyLinesAroundAccessModifier`, so this cop leaves those
|
|
23
|
+
# alone. Anything else — an assignment, a conditional — it has no
|
|
24
|
+
# opinion about.
|
|
25
|
+
#
|
|
26
|
+
# A DSL block counts when it has no receiver and is a statement of a
|
|
27
|
+
# class, module or singleton class body, or of such a block: `included
|
|
28
|
+
# do`, `with_options ... do`, `action :index do`. A block passed as an
|
|
29
|
+
# argument — the lambda given to `scope` — is left alone.
|
|
19
30
|
#
|
|
20
31
|
# @example GroupedMethods: [[belongs_to, has_many], [validate, validates]]
|
|
21
32
|
# # bad
|
|
@@ -24,6 +35,9 @@ module RuboCop
|
|
|
24
35
|
#
|
|
25
36
|
# has_many :shift_assignments, dependent: :destroy
|
|
26
37
|
# validates :starts_at, presence: true
|
|
38
|
+
# scope :upcoming, -> { where(starts_at: Time.current..) }
|
|
39
|
+
#
|
|
40
|
+
# scope :past, -> { where(starts_at: ...Time.current) }
|
|
27
41
|
# end
|
|
28
42
|
#
|
|
29
43
|
# # good
|
|
@@ -32,12 +46,9 @@ module RuboCop
|
|
|
32
46
|
# has_many :shift_assignments, dependent: :destroy
|
|
33
47
|
#
|
|
34
48
|
# validates :starts_at, presence: true
|
|
35
|
-
# end
|
|
36
49
|
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
# request_transformer RequestTransformer
|
|
40
|
-
# api_builder APIBuilder
|
|
50
|
+
# scope :upcoming, -> { where(starts_at: Time.current..) }
|
|
51
|
+
# scope :past, -> { where(starts_at: ...Time.current) }
|
|
41
52
|
# end
|
|
42
53
|
class DeclarationGroups < Base
|
|
43
54
|
extend AutoCorrector
|
|
@@ -46,9 +57,9 @@ module RuboCop
|
|
|
46
57
|
MSG_EXTRA = 'Remove the blank line between declarations of the same group.'
|
|
47
58
|
MSG_MISSING = 'Add a blank line between declaration groups.'
|
|
48
59
|
ACCESS_MODIFIERS = %i[private protected public module_function private_class_method].freeze
|
|
60
|
+
BODY_TYPES = %i[class module sclass].freeze
|
|
61
|
+
BUILT_IN_GROUPS = [%w[attr attr_accessor attr_reader attr_writer], %w[extend include prepend]].freeze
|
|
49
62
|
DEFINITION_TYPES = %i[def defs].freeze
|
|
50
|
-
BLOCK_TYPES = %i[block numblock].freeze
|
|
51
|
-
STANDALONE_TYPES = %i[block numblock def defs].freeze
|
|
52
63
|
|
|
53
64
|
def on_class(node)
|
|
54
65
|
check_declarations(node)
|
|
@@ -58,8 +69,12 @@ module RuboCop
|
|
|
58
69
|
check_declarations(node)
|
|
59
70
|
end
|
|
60
71
|
|
|
72
|
+
def on_sclass(node)
|
|
73
|
+
check_declarations(node)
|
|
74
|
+
end
|
|
75
|
+
|
|
61
76
|
def on_block(node)
|
|
62
|
-
return unless
|
|
77
|
+
return unless declaration_block?(node)
|
|
63
78
|
|
|
64
79
|
check_declarations(node)
|
|
65
80
|
end
|
|
@@ -71,7 +86,6 @@ module RuboCop
|
|
|
71
86
|
def check_declarations(node)
|
|
72
87
|
statements = body_statements(node)
|
|
73
88
|
return if statements.size < 2
|
|
74
|
-
return unless statements.all? { |statement| declaration?(statement) }
|
|
75
89
|
|
|
76
90
|
statements.each_cons(2) do |previous, following|
|
|
77
91
|
next if definitions?(previous, following)
|
|
@@ -112,35 +126,54 @@ module RuboCop
|
|
|
112
126
|
end
|
|
113
127
|
|
|
114
128
|
def standalone?(node)
|
|
115
|
-
return true if
|
|
129
|
+
return true if BLOCK_TYPES.include?(node.type)
|
|
130
|
+
return true if definition?(node)
|
|
116
131
|
|
|
117
132
|
multiline?(node)
|
|
118
133
|
end
|
|
119
134
|
|
|
120
135
|
def group_key(node)
|
|
121
|
-
return
|
|
136
|
+
return :constant if node.casgn_type?
|
|
137
|
+
return unless declaration_call?(node)
|
|
122
138
|
|
|
123
|
-
|
|
139
|
+
name = node.method_name.to_s
|
|
140
|
+
group = groups.find { |members| members.include?(name) }
|
|
141
|
+
group.nil? ? name : group.first
|
|
124
142
|
end
|
|
125
143
|
|
|
126
|
-
def
|
|
127
|
-
|
|
128
|
-
return
|
|
129
|
-
return true if enclosing.class_type?
|
|
144
|
+
def declaration_call?(node)
|
|
145
|
+
return false unless node.send_type?
|
|
146
|
+
return true if node.receiver.nil?
|
|
130
147
|
|
|
131
|
-
|
|
148
|
+
node.receiver.self_type?
|
|
132
149
|
end
|
|
133
150
|
|
|
134
|
-
def
|
|
135
|
-
return
|
|
151
|
+
def declaration_block?(node)
|
|
152
|
+
return false unless node.send_node.receiver.nil?
|
|
153
|
+
|
|
154
|
+
declaration_body?(node.parent)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def declaration_body?(node)
|
|
158
|
+
return false if node.nil?
|
|
159
|
+
return declaration_body?(node.parent) if node.begin_type?
|
|
160
|
+
return true if BODY_TYPES.include?(node.type)
|
|
161
|
+
return false unless BLOCK_TYPES.include?(node.type)
|
|
162
|
+
|
|
163
|
+
declaration_block?(node)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def definition?(node)
|
|
136
167
|
return true if DEFINITION_TYPES.include?(node.type)
|
|
137
|
-
return
|
|
168
|
+
return false unless node.send_type?
|
|
138
169
|
|
|
139
|
-
node.
|
|
170
|
+
node.arguments.any? { |argument| DEFINITION_TYPES.include?(argument.type) }
|
|
140
171
|
end
|
|
141
172
|
|
|
142
173
|
def definitions?(previous, following)
|
|
143
|
-
|
|
174
|
+
return false unless definition?(previous)
|
|
175
|
+
|
|
176
|
+
definition?(following)
|
|
144
177
|
end
|
|
145
178
|
|
|
146
179
|
def access_modifier?(node)
|
|
@@ -150,8 +183,8 @@ module RuboCop
|
|
|
150
183
|
ACCESS_MODIFIERS.include?(node.method_name)
|
|
151
184
|
end
|
|
152
185
|
|
|
153
|
-
def
|
|
154
|
-
@
|
|
186
|
+
def groups
|
|
187
|
+
@groups ||= BUILT_IN_GROUPS + Array(cop_config['GroupedMethods']).map { |group| Array(group).map(&:to_s) }
|
|
155
188
|
end
|
|
156
189
|
end
|
|
157
190
|
end
|
|
@@ -15,15 +15,22 @@ module RuboCop
|
|
|
15
15
|
# The list is empty by default, so the cop only removes until it is
|
|
16
16
|
# configured.
|
|
17
17
|
#
|
|
18
|
-
# Guard clauses group
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
18
|
+
# Guard clauses group by what they do: the guards that return sit
|
|
19
|
+
# together, the guards that raise sit together, and one blank line
|
|
20
|
+
# separates the two groups. The position after the last guard belongs
|
|
21
|
+
# to `Layout/EmptyLineAfterGuardClause`, so this cop leaves it alone —
|
|
22
|
+
# and recognises a guard by that cop's own definition: an `if` whose
|
|
23
|
+
# branch is a single-line `return`, `break`, `next`, `raise` or `fail`.
|
|
24
|
+
# A bare `raise` on its own line is a statement, not a guard. A guard
|
|
25
|
+
# whose branch spans several lines is a multiline statement to both
|
|
26
|
+
# cops, so this cop sets it apart.
|
|
24
27
|
#
|
|
25
|
-
# A statement spanning several lines
|
|
26
|
-
# line on each side, guards included.
|
|
28
|
+
# A statement spanning several lines — a heredoc counts — is always set
|
|
29
|
+
# apart by a blank line on each side, guards included.
|
|
30
|
+
#
|
|
31
|
+
# A method that rescues has several bodies: the statements it protects,
|
|
32
|
+
# each `rescue` clause, the `else` and the `ensure`. The rules apply
|
|
33
|
+
# inside each of them.
|
|
27
34
|
#
|
|
28
35
|
# An entry matches a method name anywhere in the call chain. Write it
|
|
29
36
|
# dotted — `errors.add` — to match a receiver and method together, so
|
|
@@ -61,12 +68,24 @@ module RuboCop
|
|
|
61
68
|
#
|
|
62
69
|
# order.items.sum(&:amount)
|
|
63
70
|
# end
|
|
71
|
+
#
|
|
72
|
+
# # good — the guards that return and the guard that raises are two groups
|
|
73
|
+
# def resolve(name)
|
|
74
|
+
# return nil if name.nil?
|
|
75
|
+
# return name if name.is_a?(Array)
|
|
76
|
+
#
|
|
77
|
+
# raise ArgumentError, "#{name} not found" unless enums.key?(name)
|
|
78
|
+
#
|
|
79
|
+
# enums.fetch(name)
|
|
80
|
+
# end
|
|
64
81
|
class MethodBodyBlankLines < Base
|
|
65
82
|
extend AutoCorrector
|
|
66
83
|
include BlankLineHelp
|
|
67
84
|
|
|
68
85
|
MSG_EXTRA = 'Remove the blank line inside the method body.'
|
|
69
86
|
MSG_MISSING = 'Add a blank line around the standalone call.'
|
|
87
|
+
MSG_MIXED_GUARDS = 'Add a blank line between a guard that returns and a guard that raises.'
|
|
88
|
+
CLAUSE_TYPES = %i[ensure rescue resbody].freeze
|
|
70
89
|
JUMP_METHODS = %i[raise fail].freeze
|
|
71
90
|
|
|
72
91
|
def on_def(node)
|
|
@@ -80,9 +99,24 @@ module RuboCop
|
|
|
80
99
|
private
|
|
81
100
|
|
|
82
101
|
def check_method_body(node)
|
|
83
|
-
statements
|
|
84
|
-
|
|
102
|
+
statement_lists(node.body).each { |statements| check_statements(statements) }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def statement_lists(node)
|
|
106
|
+
return [] if node.nil?
|
|
107
|
+
return [statements(node)] unless CLAUSE_TYPES.include?(node.type)
|
|
85
108
|
|
|
109
|
+
clause_bodies(node).flat_map { |body| statement_lists(body) }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def clause_bodies(node)
|
|
113
|
+
return [node.children.first, node.branch] if node.ensure_type?
|
|
114
|
+
return [node.body] if node.resbody_type?
|
|
115
|
+
|
|
116
|
+
[node.body, *node.resbody_branches, node.else_branch]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def check_statements(statements)
|
|
86
120
|
statements.each_cons(2) do |previous, following|
|
|
87
121
|
next if guard_boundary?(previous, following)
|
|
88
122
|
|
|
@@ -93,12 +127,14 @@ module RuboCop
|
|
|
93
127
|
def guard_boundary?(previous, following)
|
|
94
128
|
return false unless guard?(previous)
|
|
95
129
|
|
|
96
|
-
!
|
|
130
|
+
!contains_guard?(following)
|
|
97
131
|
end
|
|
98
132
|
|
|
99
133
|
def check_gap(previous, following)
|
|
100
134
|
if multiline_pair?(previous, following)
|
|
101
135
|
require_blank_line(previous, following, MSG_MULTILINE)
|
|
136
|
+
elsif mixed_guards?(previous, following)
|
|
137
|
+
require_blank_line(previous, following, MSG_MIXED_GUARDS)
|
|
102
138
|
elsif separated_pair?(previous, following)
|
|
103
139
|
require_blank_line(previous, following, MSG_MISSING)
|
|
104
140
|
else
|
|
@@ -125,9 +161,25 @@ module RuboCop
|
|
|
125
161
|
chain.each_cons(2).any? { |pair| pair.join('.') == name }
|
|
126
162
|
end
|
|
127
163
|
|
|
164
|
+
def mixed_guards?(previous, following)
|
|
165
|
+
return false unless guard?(previous)
|
|
166
|
+
return false unless guard?(following)
|
|
167
|
+
|
|
168
|
+
raising_guard?(previous) != raising_guard?(following)
|
|
169
|
+
end
|
|
170
|
+
|
|
128
171
|
def guard?(node)
|
|
129
172
|
return false unless node.if_type?
|
|
130
173
|
|
|
174
|
+
branch = node.if_branch
|
|
175
|
+
return false if branch.nil?
|
|
176
|
+
|
|
177
|
+
branch.guard_clause?
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def contains_guard?(node)
|
|
181
|
+
return false unless node.if_type?
|
|
182
|
+
|
|
131
183
|
branch = node.if_branch
|
|
132
184
|
return false if branch.nil?
|
|
133
185
|
return true if branch.guard_clause?
|
|
@@ -145,6 +197,13 @@ module RuboCop
|
|
|
145
197
|
JUMP_METHODS.include?(node.method_name)
|
|
146
198
|
end
|
|
147
199
|
|
|
200
|
+
def raising_guard?(node)
|
|
201
|
+
jump = node.if_branch
|
|
202
|
+
jump = jump.rhs if jump.operator_keyword?
|
|
203
|
+
|
|
204
|
+
jump.send_type?
|
|
205
|
+
end
|
|
206
|
+
|
|
148
207
|
def separated_methods
|
|
149
208
|
@separated_methods ||= Array(cop_config['SeparatedMethods']).map(&:to_s)
|
|
150
209
|
end
|