haml 3.1.0.alpha.26 → 3.1.0.alpha.27
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- data/EDGE_GEM_VERSION +1 -1
- data/REVISION +1 -0
- data/VERSION +1 -1
- data/lib/haml/buffer.rb +3 -3
- data/lib/haml/compiler.rb +432 -0
- data/lib/haml/engine.rb +5 -3
- data/lib/haml/filters.rb +20 -18
- data/lib/haml/helpers.rb +5 -5
- data/lib/haml/parser.rb +706 -0
- data/lib/haml/template.rb +1 -1
- data/lib/haml/template/plugin.rb +10 -9
- data/test/haml/engine_test.rb +34 -1
- data/vendor/sass/lib/sass/version.rb +1 -0
- metadata +5 -3
- data/lib/haml/precompiler.rb +0 -1113
data/EDGE_GEM_VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.0.alpha.
|
1
|
+
3.1.0.alpha.27
|
data/REVISION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
(release)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.0.alpha.
|
1
|
+
3.1.0.alpha.27
|
data/lib/haml/buffer.rb
CHANGED
@@ -209,7 +209,7 @@ RUBY
|
|
209
209
|
end) ? "" : "\n")
|
210
210
|
end
|
211
211
|
|
212
|
-
attributes =
|
212
|
+
attributes = Compiler.build_attributes(
|
213
213
|
html?, @options[:attr_wrapper], @options[:escape_attrs], attributes)
|
214
214
|
@buffer << "#{nuke_outer_whitespace || @options[:ugly] ? '' : tabs(tabulation)}<#{name}#{attributes}#{str}"
|
215
215
|
|
@@ -246,14 +246,14 @@ RUBY
|
|
246
246
|
# @param from [{String => #to_s}] The attribute hash to merge from
|
247
247
|
# @return [{String => String}] `to`, after being merged
|
248
248
|
def self.merge_attrs(to, from)
|
249
|
-
from['id'] =
|
249
|
+
from['id'] = Compiler.filter_and_join(from['id'], '_') if from['id']
|
250
250
|
if to['id'] && from['id']
|
251
251
|
to['id'] << '_' << from.delete('id').to_s
|
252
252
|
elsif to['id'] || from['id']
|
253
253
|
from['id'] ||= to['id']
|
254
254
|
end
|
255
255
|
|
256
|
-
from['class'] =
|
256
|
+
from['class'] = Compiler.filter_and_join(from['class'], ' ') if from['class']
|
257
257
|
if to['class'] && from['class']
|
258
258
|
# Make sure we don't duplicate class names
|
259
259
|
from['class'] = (from['class'].to_s.split(' ') | to['class'].split(' ')).sort.join(' ')
|
@@ -0,0 +1,432 @@
|
|
1
|
+
module Haml
|
2
|
+
module Compiler
|
3
|
+
include Haml::Util
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
# Returns the precompiled string with the preamble and postamble
|
8
|
+
def precompiled_with_ambles(local_names)
|
9
|
+
preamble = <<END.gsub("\n", ";")
|
10
|
+
begin
|
11
|
+
extend Haml::Helpers
|
12
|
+
_hamlout = @haml_buffer = Haml::Buffer.new(@haml_buffer, #{options_for_buffer.inspect})
|
13
|
+
_erbout = _hamlout.buffer
|
14
|
+
__in_erb_template = true
|
15
|
+
END
|
16
|
+
postamble = <<END.gsub("\n", ";")
|
17
|
+
#{precompiled_method_return_value}
|
18
|
+
ensure
|
19
|
+
@haml_buffer = @haml_buffer.upper
|
20
|
+
end
|
21
|
+
END
|
22
|
+
preamble + locals_code(local_names) + precompiled + postamble
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the string used as the return value of the precompiled method.
|
26
|
+
# This method exists so it can be monkeypatched to return modified values.
|
27
|
+
def precompiled_method_return_value
|
28
|
+
"_erbout"
|
29
|
+
end
|
30
|
+
|
31
|
+
def locals_code(names)
|
32
|
+
names = names.keys if Hash == names
|
33
|
+
|
34
|
+
names.map do |name|
|
35
|
+
# Can't use || because someone might explicitly pass in false with a symbol
|
36
|
+
sym_local = "_haml_locals[#{inspect_obj(name.to_sym)}]"
|
37
|
+
str_local = "_haml_locals[#{inspect_obj(name.to_s)}]"
|
38
|
+
"#{name} = #{sym_local}.nil? ? #{str_local} : #{sym_local}"
|
39
|
+
end.join(';') + ';'
|
40
|
+
end
|
41
|
+
|
42
|
+
def compile_root
|
43
|
+
@dont_indent_next_line = @dont_tab_up_next_text = false
|
44
|
+
@output_line = 1
|
45
|
+
@indentation = nil
|
46
|
+
yield
|
47
|
+
flush_merged_text
|
48
|
+
end
|
49
|
+
|
50
|
+
def compile_plain
|
51
|
+
push_text @node.value[:text]
|
52
|
+
end
|
53
|
+
|
54
|
+
def compile_script(&block)
|
55
|
+
push_script(@node.value[:text],
|
56
|
+
:preserve_script => @node.value[:preserve],
|
57
|
+
:escape_html => @node.value[:escape_html], &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
def compile_silent_script
|
61
|
+
return if @options[:suppress_eval]
|
62
|
+
push_silent(@node.value[:text])
|
63
|
+
keyword = @node.value[:keyword]
|
64
|
+
ruby_block = block_given? && !keyword
|
65
|
+
|
66
|
+
if block_given?
|
67
|
+
# Store these values because for conditional statements,
|
68
|
+
# we want to restore them for each branch
|
69
|
+
@node.value[:dont_indent_next_line] = @dont_indent_next_line
|
70
|
+
@node.value[:dont_tab_up_next_text] = @dont_tab_up_next_text
|
71
|
+
yield
|
72
|
+
push_silent("end", :can_suppress) unless @node.value[:dont_push_end]
|
73
|
+
elsif keyword == "end"
|
74
|
+
if @node.parent.children.last.equal?(@node)
|
75
|
+
# Since this "end" is ending the block,
|
76
|
+
# we don't need to generate an additional one
|
77
|
+
@node.parent.value[:dont_push_end] = true
|
78
|
+
end
|
79
|
+
# Don't restore dont_* for end because it isn't a conditional branch.
|
80
|
+
elsif Parser::MID_BLOCK_KEYWORDS.include?(keyword)
|
81
|
+
# Restore dont_* for this conditional branch
|
82
|
+
@dont_indent_next_line = @node.parent.value[:dont_indent_next_line]
|
83
|
+
@dont_tab_up_next_text = @node.parent.value[:dont_tab_up_next_text]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def compile_haml_comment; end
|
88
|
+
|
89
|
+
def compile_tag
|
90
|
+
t = @node.value
|
91
|
+
|
92
|
+
# Get rid of whitespace outside of the tag if we need to
|
93
|
+
rstrip_buffer! if t[:nuke_outer_whitespace]
|
94
|
+
|
95
|
+
dont_indent_next_line =
|
96
|
+
(t[:nuke_outer_whitespace] && !block_given?) ||
|
97
|
+
(t[:nuke_inner_whitespace] && block_given?)
|
98
|
+
|
99
|
+
if @options[:suppress_eval]
|
100
|
+
object_ref = "nil"
|
101
|
+
parse = false
|
102
|
+
value = t[:parse] ? nil : t[:value]
|
103
|
+
attributes_hashes = {}
|
104
|
+
preserve_script = false
|
105
|
+
else
|
106
|
+
object_ref = t[:object_ref]
|
107
|
+
parse = t[:parse]
|
108
|
+
value = t[:value]
|
109
|
+
attributes_hashes = t[:attributes_hashes]
|
110
|
+
preserve_script = t[:preserve_script]
|
111
|
+
end
|
112
|
+
|
113
|
+
# Check if we can render the tag directly to text and not process it in the buffer
|
114
|
+
if object_ref == "nil" && attributes_hashes.empty? && !preserve_script
|
115
|
+
tag_closed = !block_given? && !t[:self_closing] && !parse
|
116
|
+
|
117
|
+
open_tag = prerender_tag(t[:name], t[:self_closing], t[:attributes])
|
118
|
+
if tag_closed
|
119
|
+
open_tag << "#{value}</#{t[:name]}>"
|
120
|
+
open_tag << "\n" unless t[:nuke_outer_whitespace]
|
121
|
+
elsif !(parse || t[:nuke_inner_whitespace] ||
|
122
|
+
(t[:self_closing] && t[:nuke_outer_whitespace]))
|
123
|
+
open_tag << "\n"
|
124
|
+
end
|
125
|
+
|
126
|
+
push_merged_text(open_tag,
|
127
|
+
tag_closed || t[:self_closing] || t[:nuke_inner_whitespace] ? 0 : 1,
|
128
|
+
!t[:nuke_outer_whitespace])
|
129
|
+
|
130
|
+
@dont_indent_next_line = dont_indent_next_line
|
131
|
+
return if tag_closed
|
132
|
+
else
|
133
|
+
content = parse ? 'nil' : inspect_obj(value)
|
134
|
+
if attributes_hashes.empty?
|
135
|
+
attributes_hashes = ''
|
136
|
+
elsif attributes_hashes.size == 1
|
137
|
+
attributes_hashes = ", #{attributes_hashes.first}"
|
138
|
+
else
|
139
|
+
attributes_hashes = ", (#{attributes_hashes.join(").merge(")})"
|
140
|
+
end
|
141
|
+
|
142
|
+
args = [t[:name], t[:self_closing], !block_given?, t[:preserve_tag],
|
143
|
+
t[:escape_html], t[:attributes], t[:nuke_outer_whitespace],
|
144
|
+
t[:nuke_inner_whitespace]].map {|v| inspect_obj(v)}.join(', ')
|
145
|
+
push_silent "_hamlout.open_tag(#{args}, #{object_ref}, #{content}#{attributes_hashes})"
|
146
|
+
@dont_tab_up_next_text = @dont_indent_next_line = dont_indent_next_line
|
147
|
+
end
|
148
|
+
|
149
|
+
return if t[:self_closing]
|
150
|
+
|
151
|
+
if value.nil?
|
152
|
+
@output_tabs += 1 unless t[:nuke_inner_whitespace]
|
153
|
+
yield if block_given?
|
154
|
+
@output_tabs -= 1 unless t[:nuke_inner_whitespace]
|
155
|
+
rstrip_buffer! if t[:nuke_inner_whitespace]
|
156
|
+
push_merged_text("</#{t[:name]}>" + (t[:nuke_outer_whitespace] ? "" : "\n"),
|
157
|
+
t[:nuke_inner_whitespace] ? 0 : -1, !t[:nuke_inner_whitespace])
|
158
|
+
@dont_indent_next_line = t[:nuke_outer_whitespace]
|
159
|
+
return
|
160
|
+
end
|
161
|
+
|
162
|
+
if parse
|
163
|
+
push_script(value, t.merge(:in_tag => true))
|
164
|
+
concat_merged_text("</#{t[:name]}>" + (t[:nuke_outer_whitespace] ? "" : "\n"))
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def compile_comment
|
169
|
+
open = "<!--#{@node.value[:conditional]}"
|
170
|
+
|
171
|
+
# Render it statically if possible
|
172
|
+
unless block_given?
|
173
|
+
push_text("#{open} #{@node.value[:text]} #{@node.value[:conditional] ? "<![endif]-->" : "-->"}")
|
174
|
+
return
|
175
|
+
end
|
176
|
+
|
177
|
+
push_text(open, 1)
|
178
|
+
@output_tabs += 1
|
179
|
+
yield if block_given?
|
180
|
+
@output_tabs -= 1
|
181
|
+
push_text(@node.value[:conditional] ? "<![endif]-->" : "-->", -1)
|
182
|
+
end
|
183
|
+
|
184
|
+
def compile_doctype
|
185
|
+
doctype = text_for_doctype
|
186
|
+
push_text doctype if doctype
|
187
|
+
end
|
188
|
+
|
189
|
+
def compile_filter
|
190
|
+
unless filter = Filters.defined[@node.value[:name]]
|
191
|
+
raise Error.new("Filter \"#{@node.value[:name]}\" is not defined.", @node.line - 1)
|
192
|
+
end
|
193
|
+
filter.internal_compile(self, @node.value[:text])
|
194
|
+
end
|
195
|
+
|
196
|
+
def text_for_doctype
|
197
|
+
if @node.value[:type] == "xml"
|
198
|
+
return nil if html?
|
199
|
+
wrapper = @options[:attr_wrapper]
|
200
|
+
return "<?xml version=#{wrapper}1.0#{wrapper} encoding=#{wrapper}#{@node.value[:encoding] || "utf-8"}#{wrapper} ?>"
|
201
|
+
end
|
202
|
+
|
203
|
+
if html5?
|
204
|
+
'<!DOCTYPE html>'
|
205
|
+
else
|
206
|
+
if xhtml?
|
207
|
+
if @node.value[:version] == "1.1"
|
208
|
+
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
|
209
|
+
elsif @node.value[:version] == "5"
|
210
|
+
'<!DOCTYPE html>'
|
211
|
+
else
|
212
|
+
case @node.value[:type]
|
213
|
+
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
214
|
+
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
|
215
|
+
when "mobile"; '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
|
216
|
+
when "rdfa"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">'
|
217
|
+
when "basic"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
|
218
|
+
else '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
elsif html4?
|
223
|
+
case @node.value[:type]
|
224
|
+
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
|
225
|
+
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
|
226
|
+
else '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Evaluates `text` in the context of the scope object, but
|
233
|
+
# does not output the result.
|
234
|
+
def push_silent(text, can_suppress = false)
|
235
|
+
flush_merged_text
|
236
|
+
return if can_suppress && options[:suppress_eval]
|
237
|
+
@precompiled << "#{resolve_newlines}#{text}\n"
|
238
|
+
@output_line += text.count("\n") + 1
|
239
|
+
end
|
240
|
+
|
241
|
+
# Adds `text` to `@buffer` with appropriate tabulation
|
242
|
+
# without parsing it.
|
243
|
+
def push_merged_text(text, tab_change = 0, indent = true)
|
244
|
+
text = !indent || @dont_indent_next_line || @options[:ugly] ? text : "#{' ' * @output_tabs}#{text}"
|
245
|
+
@to_merge << [:text, text, tab_change]
|
246
|
+
@dont_indent_next_line = false
|
247
|
+
end
|
248
|
+
|
249
|
+
# Concatenate `text` to `@buffer` without tabulation.
|
250
|
+
def concat_merged_text(text)
|
251
|
+
@to_merge << [:text, text, 0]
|
252
|
+
end
|
253
|
+
|
254
|
+
def push_text(text, tab_change = 0)
|
255
|
+
push_merged_text("#{text}\n", tab_change)
|
256
|
+
end
|
257
|
+
|
258
|
+
def flush_merged_text
|
259
|
+
return if @to_merge.empty?
|
260
|
+
|
261
|
+
str = ""
|
262
|
+
mtabs = 0
|
263
|
+
@to_merge.each do |type, val, tabs|
|
264
|
+
case type
|
265
|
+
when :text
|
266
|
+
str << inspect_obj(val)[1...-1]
|
267
|
+
mtabs += tabs
|
268
|
+
when :script
|
269
|
+
if mtabs != 0 && !@options[:ugly]
|
270
|
+
val = "_hamlout.adjust_tabs(#{mtabs}); " + val
|
271
|
+
end
|
272
|
+
str << "\#{#{val}}"
|
273
|
+
mtabs = 0
|
274
|
+
else
|
275
|
+
raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.")
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
unless str.empty?
|
280
|
+
@precompiled <<
|
281
|
+
if @options[:ugly]
|
282
|
+
"_hamlout.buffer << \"#{str}\";"
|
283
|
+
else
|
284
|
+
"_hamlout.push_text(\"#{str}\", #{mtabs}, #{@dont_tab_up_next_text.inspect});"
|
285
|
+
end
|
286
|
+
end
|
287
|
+
@to_merge = []
|
288
|
+
@dont_tab_up_next_text = false
|
289
|
+
end
|
290
|
+
|
291
|
+
# Causes `text` to be evaluated in the context of
|
292
|
+
# the scope object and the result to be added to `@buffer`.
|
293
|
+
#
|
294
|
+
# If `opts[:preserve_script]` is true, Haml::Helpers#find_and_flatten is run on
|
295
|
+
# the result before it is added to `@buffer`
|
296
|
+
def push_script(text, opts = {})
|
297
|
+
return if options[:suppress_eval]
|
298
|
+
|
299
|
+
args = %w[preserve_script in_tag preserve_tag escape_html nuke_inner_whitespace]
|
300
|
+
args.map! {|name| opts[name.to_sym]}
|
301
|
+
args << !block_given? << @options[:ugly]
|
302
|
+
|
303
|
+
no_format = @options[:ugly] &&
|
304
|
+
!(opts[:preserve_script] || opts[:preserve_tag] || opts[:escape_html])
|
305
|
+
output_expr = "(#{text}\n)"
|
306
|
+
static_method = "_hamlout.#{static_method_name(:format_script, *args)}"
|
307
|
+
|
308
|
+
# Prerender tabulation unless we're in a tag
|
309
|
+
push_merged_text '' unless opts[:in_tag]
|
310
|
+
|
311
|
+
unless block_given?
|
312
|
+
script = no_format ? "#{text}\n" : "#{static_method}(#{output_expr});"
|
313
|
+
@to_merge << [:script, resolve_newlines + script]
|
314
|
+
@output_line += script.count("\n")
|
315
|
+
concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace]
|
316
|
+
return
|
317
|
+
end
|
318
|
+
|
319
|
+
flush_merged_text
|
320
|
+
push_silent "haml_temp = #{text}"
|
321
|
+
yield
|
322
|
+
push_silent('end', :can_suppress) unless @node.value[:dont_push_end]
|
323
|
+
@precompiled << "_hamlout.buffer << #{no_format ? "haml_temp.to_s;" : "#{static_method}(haml_temp);"}"
|
324
|
+
concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace] || @options[:ugly]
|
325
|
+
end
|
326
|
+
|
327
|
+
# This is a class method so it can be accessed from Buffer.
|
328
|
+
def self.build_attributes(is_html, attr_wrapper, escape_attrs, attributes = {})
|
329
|
+
quote_escape = attr_wrapper == '"' ? """ : "'"
|
330
|
+
other_quote_char = attr_wrapper == '"' ? "'" : '"'
|
331
|
+
|
332
|
+
if attributes['data'].is_a?(Hash)
|
333
|
+
attributes = attributes.dup
|
334
|
+
attributes =
|
335
|
+
Haml::Util.map_keys(attributes.delete('data')) {|name| "data-#{name}"}.merge(attributes)
|
336
|
+
end
|
337
|
+
|
338
|
+
result = attributes.collect do |attr, value|
|
339
|
+
next if value.nil?
|
340
|
+
|
341
|
+
value = filter_and_join(value, ' ') if attr == 'class'
|
342
|
+
value = filter_and_join(value, '_') if attr == 'id'
|
343
|
+
|
344
|
+
if value == true
|
345
|
+
next " #{attr}" if is_html
|
346
|
+
next " #{attr}=#{attr_wrapper}#{attr}#{attr_wrapper}"
|
347
|
+
elsif value == false
|
348
|
+
next
|
349
|
+
end
|
350
|
+
|
351
|
+
escaped =
|
352
|
+
if escape_attrs == :once
|
353
|
+
Haml::Helpers.escape_once(value.to_s)
|
354
|
+
elsif escape_attrs
|
355
|
+
CGI.escapeHTML(value.to_s)
|
356
|
+
else
|
357
|
+
value.to_s
|
358
|
+
end
|
359
|
+
value = Haml::Helpers.preserve(escaped)
|
360
|
+
if escape_attrs
|
361
|
+
# We want to decide whether or not to escape quotes
|
362
|
+
value.gsub!('"', '"')
|
363
|
+
this_attr_wrapper = attr_wrapper
|
364
|
+
if value.include? attr_wrapper
|
365
|
+
if value.include? other_quote_char
|
366
|
+
value = value.gsub(attr_wrapper, quote_escape)
|
367
|
+
else
|
368
|
+
this_attr_wrapper = other_quote_char
|
369
|
+
end
|
370
|
+
end
|
371
|
+
else
|
372
|
+
this_attr_wrapper = attr_wrapper
|
373
|
+
end
|
374
|
+
" #{attr}=#{this_attr_wrapper}#{value}#{this_attr_wrapper}"
|
375
|
+
end
|
376
|
+
result.compact.sort.join
|
377
|
+
end
|
378
|
+
|
379
|
+
def self.filter_and_join(value, separator)
|
380
|
+
return "" if value == ""
|
381
|
+
value = [value] unless value.is_a?(Array)
|
382
|
+
value = value.flatten.collect {|item| item ? item.to_s : nil}.compact.join(separator)
|
383
|
+
return !value.empty? && value
|
384
|
+
end
|
385
|
+
|
386
|
+
def prerender_tag(name, self_close, attributes)
|
387
|
+
attributes_string = Compiler.build_attributes(
|
388
|
+
html?, @options[:attr_wrapper], @options[:escape_attrs], attributes)
|
389
|
+
"<#{name}#{attributes_string}#{self_close && xhtml? ? ' /' : ''}>"
|
390
|
+
end
|
391
|
+
|
392
|
+
def resolve_newlines
|
393
|
+
diff = @node.line - @output_line
|
394
|
+
return "" if diff <= 0
|
395
|
+
@output_line = @node.line
|
396
|
+
"\n" * [diff, 0].max
|
397
|
+
end
|
398
|
+
|
399
|
+
# Get rid of and whitespace at the end of the buffer
|
400
|
+
# or the merged text
|
401
|
+
def rstrip_buffer!(index = -1)
|
402
|
+
last = @to_merge[index]
|
403
|
+
if last.nil?
|
404
|
+
push_silent("_hamlout.rstrip!", false)
|
405
|
+
@dont_tab_up_next_text = true
|
406
|
+
return
|
407
|
+
end
|
408
|
+
|
409
|
+
case last.first
|
410
|
+
when :text
|
411
|
+
last[1].rstrip!
|
412
|
+
if last[1].empty?
|
413
|
+
@to_merge.slice! index
|
414
|
+
rstrip_buffer! index
|
415
|
+
end
|
416
|
+
when :script
|
417
|
+
last[1].gsub!(/\(haml_temp, (.*?)\);$/, '(haml_temp.rstrip, \1);')
|
418
|
+
rstrip_buffer! index - 1
|
419
|
+
else
|
420
|
+
raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.")
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
def compile(node)
|
425
|
+
parent, @node = @node, node
|
426
|
+
block = proc {node.children.each {|c| compile c}}
|
427
|
+
send("compile_#{node.type}", &(block unless node.children.empty?))
|
428
|
+
ensure
|
429
|
+
@node = parent
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|