require File.dirname(__FILE__) + '/helpers' module Haml #:nodoc: class Engine include Haml::Helpers # Set the maximum length for a line to be considered a one-liner # Lines <= the maximum will be rendered on one line, # i.e.
Hello world
ONE_LINER_LENGTH = 50 SPECIAL_CHARACTERS = %w(# . = ~ % /).collect { |c| c[0] } MULTILINE_CHAR_VALUE = '|'[0] MULTILINE_STARTERS = SPECIAL_CHARACTERS - ["/"[0]] def initialize(template, action_view=nil) @view = action_view @template = template #String @result = String.new @to_close_queue = [] end def to_html # Process each line of the template @template.each_with_index do |line, index| count, line = count_soft_tabs(line) surpress_render, line, count = handle_multiline(count, line) if !surpress_render && count && line count, line = process_line(count, line) end end # Close all the open tags @to_close_queue.length.times { close_tag } # Return the result string @result end def process_line(count, line) if line.strip[0, 3] == '!!!' @result << %|\n| else if count <= @to_close_queue.size && @to_close_queue.size > 0 (@to_close_queue.size - count).times { close_tag } end case line[0..0] when '.', '#' render_div(line) when '%' render_tag(line) when '/' render_comment(line) when '=' add template_eval(line[1, line.length]).to_s if @view when '~' add find_and_flatten(template_eval(line[1, line.length])).to_s if @view else add line.strip end end return count, line end def handle_multiline(count, line) # Multilines are denoting by ending with a `|` (124) if (line[-1] == MULTILINE_CHAR_VALUE) && @multiline_buffer # A multiline string is active, and is being continued @multiline_buffer += line[0...-1] supress_render = true elsif (line[-1] == MULTILINE_CHAR_VALUE) && (MULTILINE_STARTERS.include? line[0]) # A multiline string has just been activated, start adding the lines @multiline_buffer = line[0...-1] @multiline_count = count supress_render = true elsif @multiline_buffer # A multiline string has just ended, make line into the result process_line(@multiline_count, @multiline_buffer) @multiline_buffer = nil supress_render = false end return supress_render, line, count end def add(line) return if line.nil? line.to_s.each_line do |me| @result << tabs(@to_close_queue.size) << me.chomp << "\n" end end def build_attributes(attributes = {}) attributes.empty? ? String.new : String.new(' ') << (attributes.collect {|a,v| "#{a.to_s}='#{v.to_s}'" unless v.nil? }).compact.join(' ') end def open_tag(name, attributes = {}) add "<#{name.to_s}#{build_attributes(attributes)}>" @to_close_queue.push name end def close_tag add "#{@to_close_queue.pop}>" end def one_line_tag(name, value, attributes = {}) add "<#{name.to_s}#{build_attributes(attributes)}>#{value}#{name.to_s}>" end def one_liner?(value) value.length <= ONE_LINER_LENGTH && value.scan(/\n/).empty? end def print_tag(name, value, attributes = {}) unless value.empty? if one_liner? value one_line_tag(name, value, attributes) else open_tag(name, attributes) add value close_tag end else open_tag(name, attributes) add value end end # Creates single line tags, i.e.