forked from rubocop/rubocop
-
Notifications
You must be signed in to change notification settings - Fork 1
/
multiline_literal_brace_layout.rb
140 lines (114 loc) · 3.88 KB
/
multiline_literal_brace_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
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
# frozen_string_literal: true
module RuboCop
module Cop
# Common functionality for checking the closing brace of a literal is
# either on the same line as the last contained elements or a new line.
module MultilineLiteralBraceLayout
include ConfigurableEnforcedStyle
private
def check_brace_layout(node)
return if ignored_literal?(node)
# If the last node is or contains a conflicting HEREDOC, we don't want
# to adjust the brace layout because this will result in invalid code.
return if last_line_heredoc?(node.children.last)
check(node)
end
# Returns true for the case
# [a,
# b # comment
# ].some_method
def new_line_needed_before_closing_brace?(node)
last_element_line =
last_element_range_with_trailing_comma(node).last_line
last_element_commented = processed_source.comment_at_line(last_element_line)
last_element_commented && (node.chained? || node.argument?)
end
def check(node)
case style
when :symmetrical then check_symmetrical(node)
when :new_line then check_new_line(node)
when :same_line then check_same_line(node)
end
end
def check_new_line(node)
return unless closing_brace_on_same_line?(node)
add_offense(node,
location: :end,
message: self.class::ALWAYS_NEW_LINE_MESSAGE)
end
def check_same_line(node)
return if closing_brace_on_same_line?(node)
add_offense(node,
location: :end,
message: self.class::ALWAYS_SAME_LINE_MESSAGE)
end
def check_symmetrical(node)
if opening_brace_on_same_line?(node)
return if closing_brace_on_same_line?(node)
add_offense(node, location: :end,
message: self.class::SAME_LINE_MESSAGE)
else
return unless closing_brace_on_same_line?(node)
add_offense(node, location: :end,
message: self.class::NEW_LINE_MESSAGE)
end
end
def empty_literal?(node)
children(node).empty?
end
def implicit_literal?(node)
!node.loc.begin
end
def ignored_literal?(node)
implicit_literal?(node) || empty_literal?(node) || node.single_line?
end
def children(node)
node.children
end
# This method depends on the fact that we have guarded
# against implicit and empty literals.
def opening_brace_on_same_line?(node)
node.loc.begin.line == children(node).first.first_line
end
# This method depends on the fact that we have guarded
# against implicit and empty literals.
def closing_brace_on_same_line?(node)
node.loc.end.line == children(node).last.last_line
end
# Starting with the parent node and recursively for the parent node's
# children, check if the node is a HEREDOC and if the HEREDOC ends below
# or on the last line of the parent node.
#
# Example:
#
# # node is `b: ...` parameter
# # last_line_heredoc?(node) => false
# foo(a,
# b: {
# a: 1,
# c: <<-EOM
# baz
# EOM
# }
# )
#
# # node is `b: ...` parameter
# # last_line_heredoc?(node) => true
# foo(a,
# b: <<-EOM
# baz
# EOM
# )
def last_line_heredoc?(node, parent = nil)
parent ||= node
if node.respond_to?(:loc) &&
node.loc.respond_to?(:heredoc_end) &&
node.loc.heredoc_end.last_line >= parent.last_line
return true
end
return false unless node.respond_to?(:children)
node.children.any? { |child| last_line_heredoc?(child, parent) }
end
end
end
end