-
Notifications
You must be signed in to change notification settings - Fork 26
/
erb_to_haml.rb
158 lines (135 loc) · 4.72 KB
/
erb_to_haml.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
require 'cgi'
module Rails
class TemplateRunner
def get_indent(line)
line = line.to_s
space_areas = line.scan(/^\s+/)
space_areas.empty? ? 0 : (space_areas.first.size / 2)
end
def block_start?(line)
block_starters = [/\s+do/, /^-\s+while/, /^-\s+module/, /^-\s+begin/,
/^-\s+case/, /^-\s+class/, /^-\s+unless/, /^-\s+for/,
/^-\s+until/, /^-\s*if/]
line = line.to_s
line.strip =~ /^-/ && block_starters.any?{|bs| line.strip =~ bs}
end
def block_end?(line)
line = line.to_s
line.strip =~ /^-\send$/
end
def ie_block_start?(line)
line = line.to_s
line =~ /\[if/i && line =~ /IE/ && line.strip =~ /\]>$/
end
def ie_block_end?(line)
line = line.to_s
line =~ /<!\[endif\]/i
end
def comment_line?(line)
line = line.to_s
line.strip =~ /^\//
end
def indent(line, steps = 0)
line = line.to_s
exceptions = [/\s+else\W/, /^-\s+elsif/, /^-\s+when/, /^-\s+ensure/, /^-\s+rescue/]
return if exceptions.any?{|ex| line.strip =~ ex}
steps ||= 0
line = line.to_s
(" " * steps) + line
end
def alter_lines(lines, altered_lines)
altered_lines.each do |pair|
line_number, text = pair
lines[line_number] = text
end
lines
end
def indent_lines(lines, indented_lines)
indented_lines.each do |pair|
line_number, indent_by = pair
lines[line_number] = indent(lines[line_number], indent_by)
end
lines
end
def remove_lines(lines, goner_lines)
goner_lines.each do |i|
lines[i] = nil
end
lines.compact
end
def erb_to_haml(folder)
in_root do
Dir[File.join(folder, "**/*.erb")].each do |origin|
destination = origin.gsub(/\.erb$/, '.haml')
run "html2haml -rx #{origin} #{destination}"
# Auto-fix for haml indentation. Likely not very reliable.
stack = []
lines = File.readlines(destination)
line_number = lines.size
goner_lines = []
indented_lines = []
altered_lines = []
inside_ie_block = false
just_passed_ie_block = false
lines.reverse_each do |line|
line_number -= 1
if just_passed_ie_block
altered_lines << [line_number, line.sub('/', "/" + just_passed_ie_block)]
just_passed_ie_block = false
elsif ie_block_start?(line)
goner_lines << line_number
inside_ie_block = false
stack.pop
just_passed_ie_block = line.strip.chop
elsif ie_block_end?(line)
goner_lines << line_number
inside_ie_block = true
stack << get_indent(line)
elsif inside_ie_block
match = line.match(/<haml[^>]*>([^<]+)<\/haml/)
string = match && match[1]
string = string ? "= #{CGI::unescapeHTML(CGI::unescapeHTML(string.strip))}\n" : "#{line.strip}\n"
altered_lines << [line_number, string]
indented_lines << [line_number, stack.last]
elsif block_end?(line)
stack << 1
goner_lines << line_number
elsif block_start?(line)
stack.pop
else
indented_lines << [line_number, stack.last]
end
end
lines = alter_lines(lines, altered_lines)
lines = indent_lines(lines, indented_lines)
lines = remove_lines(lines, goner_lines)
altered_lines = []
indented_lines = []
goner_lines = []
line_number = -1
lines.each_cons(3) do |three_lines|
line_number += 1
line2_number = line_number + 1
middle_indented_by_one = (get_indent(three_lines[1]) - get_indent(three_lines[0]) == 1)
top_indented_more = (get_indent(three_lines[0]) >= get_indent(three_lines[2]))
commented = (three_lines[0].to_s.strip =~ /^\//)
if(top_indented_more && middle_indented_by_one && !commented)
if (three_lines[1].strip =~ /^=/)
altered_lines << [line_number, (three_lines[0].rstrip + three_lines[1].lstrip)]
else
altered_lines << [line_number, (three_lines[0].rstrip + " " + three_lines[1].lstrip)]
end
goner_lines << line2_number
end
end
lines = alter_lines(lines, altered_lines)
lines = remove_lines(lines, goner_lines)
File.open(destination, "w") do |f|
f.write(lines.join)
end
File.delete(origin)
end
end
end
end
end