/
statement_modifier.rb
91 lines (73 loc) · 2.86 KB
/
statement_modifier.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
# frozen_string_literal: true
module RuboCop
module Cop
# Common functionality for modifier cops.
module StatementModifier
include LineLengthHelp
private
def single_line_as_modifier?(node)
return false if non_eligible_node?(node) ||
non_eligible_body?(node.body) ||
non_eligible_condition?(node.condition)
modifier_fits_on_single_line?(node)
end
def non_eligible_node?(node)
node.modifier_form? ||
node.nonempty_line_count > 3 ||
processed_source.line_with_comment?(node.loc.last_line)
end
def non_eligible_body?(body)
body.nil? ||
body.empty_source? ||
body.begin_type? ||
processed_source.contains_comment?(body.source_range)
end
def non_eligible_condition?(condition)
condition.each_node.any?(&:lvasgn_type?)
end
def modifier_fits_on_single_line?(node)
return true unless max_line_length
length_in_modifier_form(node) <= max_line_length
end
def length_in_modifier_form(node)
keyword_element = node.loc.keyword
end_element = node.loc.end
code_before = keyword_element.source_line[0...keyword_element.column]
code_after = end_element.source_line[end_element.last_column..-1]
expression = to_modifier_form(node)
line_length("#{code_before}#{expression}#{code_after}")
end
def to_modifier_form(node)
expression = [node.body.source,
node.keyword,
node.condition.source].compact.join(' ')
parenthesized = parenthesize?(node) ? "(#{expression})" : expression
[parenthesized, first_line_comment(node)].compact.join(' ')
end
def first_line_comment(node)
comment = processed_source.find_comment { |c| c.loc.line == node.loc.line }
return unless comment
comment_source = comment.loc.expression.source
comment_source unless comment_disables_cop?(comment_source)
end
def parenthesize?(node)
# Parenthesize corrected expression if changing to modifier-if form
# would change the meaning of the parent expression
# (due to the low operator precedence of modifier-if)
parent = node.parent
return false if parent.nil?
return true if parent.assignment? || parent.operator_keyword?
return true if %i[array pair].include?(parent.type)
node.parent.send_type?
end
def max_line_length
return unless config.for_cop('Layout/LineLength')['Enabled']
config.for_cop('Layout/LineLength')['Max']
end
def comment_disables_cop?(comment)
regexp_pattern = "# rubocop : (disable|todo) ([^,],)* (all|#{cop_name})"
Regexp.new(regexp_pattern.gsub(' ', '\s*')).match?(comment)
end
end
end
end