/
percent_literal_corrector.rb
117 lines (99 loc) · 3.63 KB
/
percent_literal_corrector.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
# frozen_string_literal: true
module RuboCop
module Cop
# This auto-corrects percent literals
class PercentLiteralCorrector
include Util
attr_reader :config, :preferred_delimiters
def initialize(config, preferred_delimiters)
@config = config
@preferred_delimiters = preferred_delimiters
end
def correct(node, char)
escape = escape_words?(node)
char = char.upcase if escape
delimiters = delimiters_for("%#{char}")
contents = new_contents(node, escape, delimiters)
wrap_contents(node, contents, char, delimiters)
end
private
def wrap_contents(node, contents, char, delimiters)
lambda do |corrector|
corrector.replace(
node,
"%#{char}#{delimiters[0]}#{contents}#{delimiters[1]}"
)
end
end
def escape_words?(node)
node.children.any? { |w| needs_escaping?(w.children[0]) }
end
def delimiters_for(type)
PreferredDelimiters
.new(type, config, preferred_delimiters)
.delimiters
end
def new_contents(node, escape, delimiters)
if node.multiline?
autocorrect_multiline_words(node, escape, delimiters)
else
autocorrect_words(node, escape, delimiters)
end
end
def autocorrect_multiline_words(node, escape, delimiters)
contents = process_multiline_words(node, escape, delimiters)
contents << end_content(node.source)
contents.join('')
end
def autocorrect_words(node, escape, delimiters)
node.children.map do |word_node|
fix_escaped_content(word_node, escape, delimiters)
end.join(' ')
end
def process_multiline_words(node, escape, delimiters)
base_line_num = node.first_line
prev_line_num = base_line_num
node.children.map.with_index do |word_node, index|
line_breaks = line_breaks(word_node,
node.source,
prev_line_num,
base_line_num,
index)
prev_line_num = word_node.first_line
content = fix_escaped_content(word_node, escape, delimiters)
line_breaks + content
end
end
def line_breaks(node, source, previous_line_num, base_line_num, node_indx)
source_in_lines = source.split("\n")
if first_line?(node, previous_line_num)
node_indx.zero? && node.first_line == base_line_num ? '' : ' '
else
process_lines(node, previous_line_num, base_line_num, source_in_lines)
end
end
def first_line?(node, previous_line_num)
node.first_line == previous_line_num
end
def process_lines(node, previous_line_num, base_line_num, source_in_lines)
begin_line_num = previous_line_num - base_line_num + 1
end_line_num = node.first_line - base_line_num + 1
lines = source_in_lines[begin_line_num...end_line_num]
"\n#{(lines.join("\n").split(node.source).first || '')}"
end
def fix_escaped_content(word_node, escape, delimiters)
content = +word_node.children.first.to_s
content = escape_string(content) if escape
substitute_escaped_delimiters(content, delimiters)
content
end
def substitute_escaped_delimiters(content, delimiters)
delimiters.each { |delim| content.gsub!(delim, "\\#{delim}") }
end
def end_content(source)
result = /\A(\s*)\]/.match(source.split("\n").last)
("\n" + result[1]) if result
end
end
end
end