/
else_layout.rb
94 lines (80 loc) · 2.58 KB
/
else_layout.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
# frozen_string_literal: true
module RuboCop
module Cop
module Lint
# This cop checks for odd `else` block layout - like
# having an expression on the same line as the `else` keyword,
# which is usually a mistake.
#
# Its auto-correction tweaks layout to keep the syntax. So, this auto-correction
# is compatible correction for bad case syntax, but if your code makes a mistake
# with `elsif` and `else`, you will have to correct it manually.
#
# @example
#
# # bad
#
# if something
# # ...
# else do_this
# do_that
# end
#
# @example
#
# # good
#
# # This code is compatible with the bad case. It will be auto-corrected like this.
# if something
# # ...
# else
# do_this
# do_that
# end
#
# # This code is incompatible with the bad case.
# # If `do_this` is a condition, `elsif` should be used instead of `else`.
# if something
# # ...
# elsif do_this
# do_that
# end
class ElseLayout < Base
include RangeHelp
extend AutoCorrector
MSG = 'Odd `else` layout detected. Did you mean to use `elsif`?'
def on_if(node)
return if node.ternary?
# If the if is on a single line, it'll be handled by `Style/OneLineConditional`
return if node.single_line?
check(node)
end
private
def check(node)
return unless node.else_branch
if node.else? && node.loc.else.is?('else')
check_else(node)
elsif node.if?
check(node.else_branch)
end
end
def check_else(node)
else_branch = node.else_branch
first_else = else_branch.begin_type? ? else_branch.children.first : else_branch
return unless first_else
return unless first_else.source_range.line == node.loc.else.line
add_offense(first_else) { |corrector| autocorrect(corrector, node, first_else) }
end
def autocorrect(corrector, node, first_else)
corrector.insert_after(node.loc.else, "\n")
blank_range = range_between(node.loc.else.end_pos, first_else.loc.expression.begin_pos)
indentation = indent(node, offset: indentation_width)
corrector.replace(blank_range, indentation)
end
def indentation_width
@config.for_cop('Layout/IndentationWidth')['Width'] || 2
end
end
end
end
end