Included Modules

Haml::Compiler

Private Class Methods

build_attributes(is_html, attr_wrapper, escape_attrs, attributes = {}) click to toggle source

This is a class method so it can be accessed from Buffer.

     # File lib/haml/compiler.rb, line 348
348:     def self.build_attributes(is_html, attr_wrapper, escape_attrs, attributes = {})
349:       quote_escape = attr_wrapper == '"' ? """ : "'"
350:       other_quote_char = attr_wrapper == '"' ? "'" : '"'
351: 
352:       if attributes['data'].is_a?(Hash)
353:         attributes = attributes.dup
354:         attributes =
355:           Haml::Util.map_keys(attributes.delete('data')) {|name| "data-#{name}"}.merge(attributes)
356:       end
357: 
358:       result = attributes.collect do |attr, value|
359:         next if value.nil?
360: 
361:         value = filter_and_join(value, ' ') if attr == 'class'
362:         value = filter_and_join(value, '_') if attr == 'id'
363: 
364:         if value == true
365:           next " #{attr}" if is_html
366:           next " #{attr}=#{attr_wrapper}#{attr}#{attr_wrapper}"
367:         elsif value == false
368:           next
369:         end
370: 
371:         escaped =
372:           if escape_attrs == :once
373:             Haml::Helpers.escape_once(value.to_s)
374:           elsif escape_attrs
375:             Haml::Helpers.html_escape(value.to_s)
376:           else
377:             value.to_s
378:           end
379:         value = Haml::Helpers.preserve(escaped)
380:         if escape_attrs
381:           # We want to decide whether or not to escape quotes
382:           value = value.gsub('"', '"')
383:           this_attr_wrapper = attr_wrapper
384:           if value.include? attr_wrapper
385:             if value.include? other_quote_char
386:               value = value.gsub(attr_wrapper, quote_escape)
387:             else
388:               this_attr_wrapper = other_quote_char
389:             end
390:           end
391:         else
392:           this_attr_wrapper = attr_wrapper
393:         end
394:         " #{attr}=#{this_attr_wrapper}#{value}#{this_attr_wrapper}"
395:       end
396:       result.compact.sort.join
397:     end
filter_and_join(value, separator) click to toggle source
     # File lib/haml/compiler.rb, line 399
399:     def self.filter_and_join(value, separator)
400:       return "" if value == ""
401:       value = [value] unless value.is_a?(Array)
402:       value = value.flatten.collect {|item| item ? item.to_s : nil}.compact.join(separator)
403:       return !value.empty? && value
404:     end

Public Instance Methods

compile_silent_script(&block) click to toggle source
compile_silent_script_with_haml_block_deprecation(&block) click to toggle source
    # File lib/haml/template/plugin.rb, line 59
59:       def compile_silent_script_with_haml_block_deprecation(&block)
60:         unless block && !@node.value[:keyword] &&
61:             @node.value[:text] =~ ActionView::Template::Handlers::Erubis::BLOCK_EXPR
62:           return compile_silent_script_without_haml_block_deprecation(&block)
63:         end
64: 
65:         @node.value[:text] = "_hamlout.append_if_string= #{@node.value[:text]}"
66:         compile_silent_script_without_haml_block_deprecation(&block)
67:       end
Also aliased as: compile_silent_script

Private Instance Methods

compile(node) click to toggle source
     # File lib/haml/compiler.rb, line 444
444:     def compile(node)
445:       parent, @node = @node, node
446:       block = proc {node.children.each {|c| compile c}}
447:       send("compile_#{node.type}", &(block unless node.children.empty?))
448:     ensure
449:       @node = parent
450:     end
compile_comment() click to toggle source
     # File lib/haml/compiler.rb, line 185
185:     def compile_comment
186:       open = "<!--#{@node.value[:conditional]}"
187: 
188:       # Render it statically if possible
189:       unless block_given?
190:         push_text("#{open} #{@node.value[:text]} #{@node.value[:conditional] ? "<![endif]-->" : "-->"}")
191:         return
192:       end
193: 
194:       push_text(open, 1)
195:       @output_tabs += 1
196:       yield if block_given?
197:       @output_tabs -= 1
198:       push_text(@node.value[:conditional] ? "<![endif]-->" : "-->", 1)
199:     end
compile_doctype() click to toggle source
     # File lib/haml/compiler.rb, line 201
201:     def compile_doctype
202:       doctype = text_for_doctype
203:       push_text doctype if doctype
204:     end
compile_filter() click to toggle source
     # File lib/haml/compiler.rb, line 206
206:     def compile_filter
207:       unless filter = Filters.defined[@node.value[:name]]
208:         raise Error.new("Filter \"#{@node.value[:name]}\" is not defined.", @node.line - 1)
209:       end
210:       filter.internal_compile(self, @node.value[:text])
211:     end
compile_haml_comment() click to toggle source
    # File lib/haml/compiler.rb, line 89
89:     def compile_haml_comment; end
compile_plain() click to toggle source
    # File lib/haml/compiler.rb, line 52
52:     def compile_plain
53:       push_text @node.value[:text]
54:     end
compile_root() click to toggle source
    # File lib/haml/compiler.rb, line 44
44:     def compile_root
45:       @dont_indent_next_line = @dont_tab_up_next_text = false
46:       @output_line = 1
47:       @indentation = nil
48:       yield
49:       flush_merged_text
50:     end
compile_script(&block) click to toggle source
    # File lib/haml/compiler.rb, line 56
56:     def compile_script(&block)
57:       push_script(@node.value[:text],
58:         :preserve_script => @node.value[:preserve],
59:         :escape_html => @node.value[:escape_html], &block)
60:     end
compile_silent_script() click to toggle source
    # File lib/haml/compiler.rb, line 62
62:     def compile_silent_script
63:       return if @options[:suppress_eval]
64:       push_silent(@node.value[:text])
65:       keyword = @node.value[:keyword]
66:       ruby_block = block_given? && !keyword
67: 
68:       if block_given?
69:         # Store these values because for conditional statements,
70:         # we want to restore them for each branch
71:         @node.value[:dont_indent_next_line] = @dont_indent_next_line
72:         @node.value[:dont_tab_up_next_text] = @dont_tab_up_next_text
73:         yield
74:         push_silent("end", :can_suppress) unless @node.value[:dont_push_end]
75:       elsif keyword == "end"
76:         if @node.parent.children.last.equal?(@node)
77:           # Since this "end" is ending the block,
78:           # we don't need to generate an additional one
79:           @node.parent.value[:dont_push_end] = true
80:         end
81:         # Don't restore dont_* for end because it isn't a conditional branch.
82:       elsif Parser::MID_BLOCK_KEYWORDS.include?(keyword)
83:         # Restore dont_* for this conditional branch
84:         @dont_indent_next_line = @node.parent.value[:dont_indent_next_line]
85:         @dont_tab_up_next_text = @node.parent.value[:dont_tab_up_next_text]
86:       end
87:     end
compile_silent_script_without_haml_block_deprecation() click to toggle source
compile_tag() click to toggle source
     # File lib/haml/compiler.rb, line 91
 91:     def compile_tag
 92:       t = @node.value
 93: 
 94:       # Get rid of whitespace outside of the tag if we need to
 95:       rstrip_buffer! if t[:nuke_outer_whitespace]
 96: 
 97:       dont_indent_next_line =
 98:         (t[:nuke_outer_whitespace] && !block_given?) ||
 99:         (t[:nuke_inner_whitespace] && block_given?)
100: 
101:       if @options[:suppress_eval]
102:         object_ref = "nil"
103:         parse = false
104:         value = t[:parse] ? nil : t[:value]
105:         attributes_hashes = {}
106:         preserve_script = false
107:       else
108:         object_ref = t[:object_ref]
109:         parse = t[:parse]
110:         value = t[:value]
111:         attributes_hashes = t[:attributes_hashes]
112:         preserve_script = t[:preserve_script]
113:       end
114: 
115:       # Check if we can render the tag directly to text and not process it in the buffer
116:       if object_ref == "nil" && attributes_hashes.empty? && !preserve_script
117:         tag_closed = !block_given? && !t[:self_closing] && !parse
118: 
119:         open_tag = prerender_tag(t[:name], t[:self_closing], t[:attributes])
120:         if tag_closed
121:           open_tag << "#{value}</#{t[:name]}>"
122:           open_tag << "\n" unless t[:nuke_outer_whitespace]
123:         elsif !(parse || t[:nuke_inner_whitespace] ||
124:             (t[:self_closing] && t[:nuke_outer_whitespace]))
125:           open_tag << "\n"
126:         end
127: 
128:         push_merged_text(open_tag,
129:           tag_closed || t[:self_closing] || t[:nuke_inner_whitespace] ? 0 : 1,
130:           !t[:nuke_outer_whitespace])
131: 
132:         @dont_indent_next_line = dont_indent_next_line
133:         return if tag_closed
134:       else
135:         if attributes_hashes.empty?
136:           attributes_hashes = ''
137:         elsif attributes_hashes.size == 1
138:           attributes_hashes = ", #{attributes_hashes.first}"
139:         else
140:           attributes_hashes = ", (#{attributes_hashes.join(").merge(")})"
141:         end
142: 
143:         push_merged_text "<#{t[:name]}", 0, !t[:nuke_outer_whitespace]
144:         push_generated_script(
145:           "_hamlout.attributes(#{inspect_obj(t[:attributes])}, #{object_ref}#{attributes_hashes})")
146:         concat_merged_text(
147:           if t[:self_closing] && xhtml?
148:             " />" + (t[:nuke_outer_whitespace] ? "" : "\n")
149:           else
150:             ">" + ((if t[:self_closing] && html?
151:                       t[:nuke_outer_whitespace]
152:                     else
153:                       !block_given? || t[:preserve_tag] || t[:nuke_inner_whitespace]
154:                     end) ? "" : "\n")
155:           end)
156: 
157:         if value && !parse
158:           concat_merged_text("#{value}</#{t[:name]}>#{t[:nuke_outer_whitespace] ? "" : "\n"}")
159:         elsif !t[:nuke_inner_whitespace] && !t[:self_closing]
160:           @to_merge << [:text, '', 1]
161:         end
162: 
163:         @dont_indent_next_line = dont_indent_next_line
164:       end
165: 
166:       return if t[:self_closing]
167: 
168:       if value.nil?
169:         @output_tabs += 1 unless t[:nuke_inner_whitespace]
170:         yield if block_given?
171:         @output_tabs -= 1 unless t[:nuke_inner_whitespace]
172:         rstrip_buffer! if t[:nuke_inner_whitespace]
173:         push_merged_text("</#{t[:name]}>" + (t[:nuke_outer_whitespace] ? "" : "\n"),
174:           t[:nuke_inner_whitespace] ? 0 : 1, !t[:nuke_inner_whitespace])
175:         @dont_indent_next_line = t[:nuke_outer_whitespace]
176:         return
177:       end
178: 
179:       if parse
180:         push_script(value, t.merge(:in_tag => true))
181:         concat_merged_text("</#{t[:name]}>" + (t[:nuke_outer_whitespace] ? "" : "\n"))
182:       end
183:     end
concat_merged_text(text) click to toggle source

Concatenate `text` to `@buffer` without tabulation.

     # File lib/haml/compiler.rb, line 267
267:     def concat_merged_text(text)
268:       @to_merge << [:text, text, 0]
269:     end
flush_merged_text() click to toggle source
     # File lib/haml/compiler.rb, line 275
275:     def flush_merged_text
276:       return if @to_merge.empty?
277: 
278:       str = ""
279:       mtabs = 0
280:       @to_merge.each do |type, val, tabs|
281:         case type
282:         when :text
283:           str << inspect_obj(val)[1...1]
284:           mtabs += tabs
285:         when :script
286:           if mtabs != 0 && !@options[:ugly]
287:             val = "_hamlout.adjust_tabs(#{mtabs}); " + val
288:           end
289:           str << "\#{#{val}}"
290:           mtabs = 0
291:         else
292:           raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.")
293:         end
294:       end
295: 
296:       unless str.empty?
297:         @precompiled <<
298:           if @options[:ugly]
299:             "_hamlout.buffer << \"#{str}\";"
300:           else
301:             "_hamlout.push_text(\"#{str}\", #{mtabs}, #{@dont_tab_up_next_text.inspect});"
302:           end
303:       end
304:       @to_merge = []
305:       @dont_tab_up_next_text = false
306:     end
locals_code(names) click to toggle source
    # File lib/haml/compiler.rb, line 33
33:     def locals_code(names)
34:       names = names.keys if Hash == names
35: 
36:       names.map do |name|
37:         # Can't use || because someone might explicitly pass in false with a symbol
38:         sym_local = "_haml_locals[#{inspect_obj(name.to_sym)}]"
39:         str_local = "_haml_locals[#{inspect_obj(name.to_s)}]"
40:         "#{name} = #{sym_local}.nil? ? #{str_local} : #{sym_local}"
41:       end.join(';') + ';'
42:     end
precompiled_method_return_value() click to toggle source

Returns the string used as the return value of the precompiled method. This method exists so it can be monkeypatched to return modified values.

    # File lib/haml/compiler.rb, line 29
29:     def precompiled_method_return_value
30:       "_erbout"
31:     end
precompiled_with_ambles(local_names) click to toggle source

Returns the precompiled string with the preamble and postamble

    # File lib/haml/compiler.rb, line 10
10:     def precompiled_with_ambles(local_names)
11:       preamble = beginextend Haml::Helpers_hamlout = @haml_buffer = Haml::Buffer.new(@haml_buffer, #{options_for_buffer.inspect})_erbout = _hamlout.buffer__in_erb_template = true.gsub("\n", ";")
12:       postamble = #{precompiled_method_return_value}ensure@haml_buffer = @haml_buffer.upper if @haml_bufferend.gsub("\n", ";")
13:       preamble + locals_code(local_names) + precompiled + postamble
14:     end
prerender_tag(name, self_close, attributes) click to toggle source
     # File lib/haml/compiler.rb, line 406
406:     def prerender_tag(name, self_close, attributes)
407:       attributes_string = Compiler.build_attributes(
408:         html?, @options[:attr_wrapper], @options[:escape_attrs], attributes)
409:       "<#{name}#{attributes_string}#{self_close && xhtml? ? ' /' : ''}>"
410:     end
push_generated_script(text) click to toggle source
     # File lib/haml/compiler.rb, line 342
342:     def push_generated_script(text)
343:       @to_merge << [:script, resolve_newlines + text]
344:       @output_line += text.count("\n")
345:     end
push_merged_text(text, tab_change = 0, indent = true) click to toggle source

Adds `text` to `@buffer` with appropriate tabulation without parsing it.

     # File lib/haml/compiler.rb, line 260
260:     def push_merged_text(text, tab_change = 0, indent = true)
261:       text = !indent || @dont_indent_next_line || @options[:ugly] ? text : "#{'  ' * @output_tabs}#{text}"
262:       @to_merge << [:text, text, tab_change]
263:       @dont_indent_next_line = false
264:     end
push_script(text, opts = {}) click to toggle source

Causes `text` to be evaluated in the context of the scope object and the result to be added to `@buffer`.

If `opts[:preserve_script]` is true, Haml::Helpers#find_and_flatten is run on the result before it is added to `@buffer`

     # File lib/haml/compiler.rb, line 313
313:     def push_script(text, opts = {})
314:       return if options[:suppress_eval]
315: 
316:       args = ]preserve_script in_tag preserve_tag escape_html nuke_inner_whitespace]
317:       args.map! {|name| opts[name.to_sym]}
318:       args << !block_given? << @options[:ugly]
319: 
320:       no_format = @options[:ugly] &&
321:         !(opts[:preserve_script] || opts[:preserve_tag] || opts[:escape_html])
322:       output_expr = "(#{text}\n)"
323:       static_method = "_hamlout.#{static_method_name(:format_script, *args)}"
324: 
325:       # Prerender tabulation unless we're in a tag
326:       push_merged_text '' unless opts[:in_tag]
327: 
328:       unless block_given?
329:         push_generated_script(no_format ? "#{text}\n" : "#{static_method}(#{output_expr});")
330:         concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace]
331:         return
332:       end
333: 
334:       flush_merged_text
335:       push_silent "haml_temp = #{text}"
336:       yield
337:       push_silent('end', :can_suppress) unless @node.value[:dont_push_end]
338:       @precompiled << "_hamlout.buffer << #{no_format ? "haml_temp.to_s;" : "#{static_method}(haml_temp);"}"
339:       concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace] || @options[:ugly]
340:     end
push_silent(text, can_suppress = false) click to toggle source

Evaluates `text` in the context of the scope object, but does not output the result.

     # File lib/haml/compiler.rb, line 251
251:     def push_silent(text, can_suppress = false)
252:       flush_merged_text
253:       return if can_suppress && options[:suppress_eval]
254:       @precompiled << "#{resolve_newlines}#{text}\n"
255:       @output_line += text.count("\n") + 1
256:     end
push_text(text, tab_change = 0) click to toggle source
     # File lib/haml/compiler.rb, line 271
271:     def push_text(text, tab_change = 0)
272:       push_merged_text("#{text}\n", tab_change)
273:     end
resolve_newlines() click to toggle source
     # File lib/haml/compiler.rb, line 412
412:     def resolve_newlines
413:       diff = @node.line - @output_line
414:       return "" if diff <= 0
415:       @output_line = @node.line
416:       "\n" * [diff, 0].max
417:     end
rstrip_buffer!(index = -1) click to toggle source

Get rid of and whitespace at the end of the buffer or the merged text

     # File lib/haml/compiler.rb, line 421
421:     def rstrip_buffer!(index = 1)
422:       last = @to_merge[index]
423:       if last.nil?
424:         push_silent("_hamlout.rstrip!", false)
425:         @dont_tab_up_next_text = true
426:         return
427:       end
428: 
429:       case last.first
430:       when :text
431:         last[1].rstrip!
432:         if last[1].empty?
433:           @to_merge.slice! index
434:           rstrip_buffer! index
435:         end
436:       when :script
437:         last[1].gsub!(/\(haml_temp, (.*?)\);$/, '(haml_temp.rstrip, \1);')
438:         rstrip_buffer! index - 1
439:       else
440:         raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.")
441:       end
442:     end
text_for_doctype() click to toggle source
     # File lib/haml/compiler.rb, line 213
213:     def text_for_doctype
214:       if @node.value[:type] == "xml"
215:         return nil if html?
216:         wrapper = @options[:attr_wrapper]
217:         return "<?xml version=#{wrapper}1.0#{wrapper} encoding=#{wrapper}#{@node.value[:encoding] || "utf-8"}#{wrapper} ?>"
218:       end
219: 
220:       if html5?
221:         '<!DOCTYPE html>'
222:       else
223:         if xhtml?
224:           if @node.value[:version] == "1.1"
225:             '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
226:           elsif @node.value[:version] == "5"
227:             '<!DOCTYPE html>'
228:           else
229:             case @node.value[:type]
230:             when "strict";   '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
231:             when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
232:             when "mobile";   '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
233:             when "rdfa";     '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">'
234:             when "basic";    '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
235:             else             '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
236:             end
237:           end
238: 
239:         elsif html4?
240:           case @node.value[:type]
241:           when "strict";   '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
242:           when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
243:           else             '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
244:           end
245:         end
246:       end
247:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.