/
empty_line_after_guard_clause.rb
172 lines (139 loc) · 4.66 KB
/
empty_line_after_guard_clause.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# frozen_string_literal: true
module RuboCop
module Cop
module Layout
# This cop enforces empty line after guard clause
#
# @example
#
# # bad
# def foo
# return if need_return?
# bar
# end
#
# # good
# def foo
# return if need_return?
#
# bar
# end
#
# # good
# def foo
# return if something?
# return if something_different?
#
# bar
# end
#
# # also good
# def foo
# if something?
# do_something
# return if need_return?
# end
# end
class EmptyLineAfterGuardClause < Base
include RangeHelp
extend AutoCorrector
MSG = 'Add empty line after guard clause.'
END_OF_HEREDOC_LINE = 1
def on_if(node)
return if correct_style?(node)
if node.modifier_form? && (heredoc_node = last_heredoc_argument(node))
return if next_line_empty_or_enable_directive_comment?(heredoc_line(node, heredoc_node))
add_offense(heredoc_node.loc.heredoc_end) do |corrector|
autocorrect(corrector, heredoc_node)
end
else
return if next_line_empty_or_enable_directive_comment?(node.last_line)
add_offense(offense_location(node)) { |corrector| autocorrect(corrector, node) }
end
end
private
def autocorrect(corrector, node)
node_range = if heredoc?(node)
range_by_whole_lines(node.loc.heredoc_body)
else
range_by_whole_lines(node.source_range)
end
next_line = node_range.last_line + 1
if next_line_enable_directive_comment?(next_line)
node_range = processed_source.comment_at_line(next_line)
end
corrector.insert_after(node_range, "\n")
end
def correct_style?(node)
!contains_guard_clause?(node) ||
next_line_rescue_or_ensure?(node) ||
next_sibling_parent_empty_or_else?(node) ||
next_sibling_empty_or_guard_clause?(node)
end
def contains_guard_clause?(node)
node.if_branch&.guard_clause?
end
def next_line_empty_or_enable_directive_comment?(line)
return true if next_line_empty?(line)
next_line = line + 1
next_line_enable_directive_comment?(next_line) && next_line_empty?(next_line)
end
def next_line_empty?(line)
processed_source[line].blank?
end
def next_line_enable_directive_comment?(line)
return false unless (comment = processed_source.comment_at_line(line))
DirectiveComment.new(comment).enabled?
end
def next_line_rescue_or_ensure?(node)
parent = node.parent
parent.nil? || parent.rescue_type? || parent.ensure_type?
end
def next_sibling_parent_empty_or_else?(node)
next_sibling = node.right_sibling
return true if next_sibling.nil?
parent = next_sibling.parent
parent&.if_type? && parent&.else?
end
def next_sibling_empty_or_guard_clause?(node)
next_sibling = node.right_sibling
return true if next_sibling.nil?
next_sibling.if_type? && contains_guard_clause?(next_sibling)
end
def last_heredoc_argument(node)
n = last_heredoc_argument_node(node)
return n if heredoc?(n)
return unless n.respond_to?(:arguments)
n.arguments.each do |argument|
node = last_heredoc_argument(argument)
return node if node
end
return last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
end
def last_heredoc_argument_node(node)
return node unless node.respond_to?(:if_branch)
if node.if_branch.and_type?
node.if_branch.children.first
else
node.if_branch.children.last
end
end
def heredoc_line(node, heredoc_node)
heredoc_body = heredoc_node.loc.heredoc_body
num_of_heredoc_lines = heredoc_body.last_line - heredoc_body.first_line
node.last_line + num_of_heredoc_lines + END_OF_HEREDOC_LINE
end
def heredoc?(node)
node.respond_to?(:heredoc?) && node.heredoc?
end
def offense_location(node)
if node.loc.respond_to?(:end) && node.loc.end
node.loc.end
else
node
end
end
end
end
end
end