2006-06-30 15:14:44 +00:00
|
|
|
module HAML
|
|
|
|
|
|
|
|
class TemplateEngine
|
|
|
|
|
|
|
|
def initialize(base)
|
|
|
|
@base = base
|
|
|
|
@tab_index = ["", " "]
|
2006-07-20 04:01:23 +00:00
|
|
|
@happy_land = HappyLand.new(@base, @base.assigns)
|
2006-06-30 15:14:44 +00:00
|
|
|
#pre-build the tab index up to 9
|
|
|
|
10.times do |num|
|
|
|
|
@tab_index << @tab_index.last + " "
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def render(template = "", locals = {})
|
|
|
|
@result = ""
|
|
|
|
@to_close_queue = []
|
2006-07-20 04:01:23 +00:00
|
|
|
|
2006-07-19 22:23:01 +00:00
|
|
|
|
2006-07-20 04:01:23 +00:00
|
|
|
@happy_land.set_locals(locals)
|
|
|
|
|
|
|
|
#breakpoint
|
2006-06-30 15:14:44 +00:00
|
|
|
|
|
|
|
#main loop handling line reading
|
|
|
|
#and interpretation
|
|
|
|
template.each_line do |line|
|
2006-07-02 02:09:44 +00:00
|
|
|
if line.strip[0, 3] == "!!!"
|
|
|
|
@result << %|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n|
|
|
|
|
else
|
|
|
|
count, line = count_levels(line)
|
2006-07-19 22:23:01 +00:00
|
|
|
#puts count.to_s + "::" + line
|
2006-07-02 02:09:44 +00:00
|
|
|
if count <= @to_close_queue.size && @to_close_queue.size > 0
|
2006-07-19 22:23:01 +00:00
|
|
|
(@to_close_queue.size - count).times { close_tag }
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
2006-07-02 02:09:44 +00:00
|
|
|
case line.first
|
|
|
|
when '.', '#'
|
|
|
|
render_div(line)
|
|
|
|
when '%'
|
|
|
|
render_tag(line)
|
|
|
|
when '/'
|
|
|
|
render_comment(line)
|
|
|
|
when '='
|
|
|
|
add template_eval(line[1, line.length])
|
|
|
|
else
|
|
|
|
add line
|
|
|
|
end
|
|
|
|
end
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
2006-07-02 02:09:44 +00:00
|
|
|
|
|
|
|
@to_close_queue.length.times { close_tag }
|
2006-06-30 15:14:44 +00:00
|
|
|
@result
|
|
|
|
end
|
2006-06-30 21:40:07 +00:00
|
|
|
|
2006-06-30 15:14:44 +00:00
|
|
|
def add(line)
|
2006-06-30 21:40:07 +00:00
|
|
|
return nil if line.nil?
|
2006-07-02 02:09:44 +00:00
|
|
|
line.each_line { |me| add_single(me) }
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
|
|
|
|
2006-07-02 02:09:44 +00:00
|
|
|
def add_single(line = "")
|
|
|
|
@result << @tab_index[@to_close_queue.size]
|
|
|
|
@result << line.chomp + "\n"
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def open_tag(name, attributes = {})
|
2006-07-19 22:23:01 +00:00
|
|
|
add "<#{name.to_s}#{build_attributes(attributes)}>"
|
|
|
|
@to_close_queue.push(name)
|
|
|
|
end
|
|
|
|
|
|
|
|
def one_line_tag(name, value, attributes = {})
|
|
|
|
add "<#{name.to_s}#{build_attributes(attributes)}>#{value}</#{name.to_s}>"
|
|
|
|
end
|
2006-07-20 04:01:23 +00:00
|
|
|
|
|
|
|
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
|
2006-07-19 22:23:01 +00:00
|
|
|
|
|
|
|
#used to create single line tags... aka <hello />
|
|
|
|
def atomic_tag(name, attributes = {})
|
|
|
|
add "<#{name.to_s}#{build_attributes(attributes)} />"
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_attributes(attributes = {})
|
|
|
|
return "" if attributes.empty?
|
|
|
|
" " + (attributes.collect { |attr_name, val| attr_name.to_s + "='" + val + "'" }).join(" ")
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def close_tag
|
2006-07-02 02:09:44 +00:00
|
|
|
add "</#{name = @to_close_queue.pop}>"
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def render_div(line)
|
2006-07-02 02:09:44 +00:00
|
|
|
render_tag("%div" + line)
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def render_comment(line)
|
|
|
|
add "<!-- #{line} -->"
|
|
|
|
end
|
|
|
|
|
2006-06-30 21:40:07 +00:00
|
|
|
def render_tag(line)
|
2006-07-20 04:01:23 +00:00
|
|
|
broken_up = line.scan(/[%]([-_a-z1-9]+)([-_a-z\.\#]*)(\{.*\})?([=\/]?)?([^\n]*)?/)
|
|
|
|
broken_up.each do |tag_name, attributes, attributes_hash, action, value|
|
|
|
|
attributes = parse_attributes(attributes.to_s)
|
|
|
|
|
|
|
|
unless(attributes_hash.nil? || attributes_hash.empty?)
|
|
|
|
attributes_hash = template_eval(attributes_hash)
|
|
|
|
attributes = attributes.merge(attributes_hash)
|
2006-07-19 22:23:01 +00:00
|
|
|
end
|
2006-07-20 04:01:23 +00:00
|
|
|
|
2006-07-19 22:23:01 +00:00
|
|
|
#check to see if we're a one liner
|
|
|
|
if(action == "\/")
|
2006-07-20 04:01:23 +00:00
|
|
|
atomic_tag(tag_name, attributes)
|
|
|
|
elsif(action == "=")
|
|
|
|
print_tag(tag_name, template_eval(value).to_s, attributes)
|
2006-07-19 22:23:01 +00:00
|
|
|
else
|
2006-07-20 04:01:23 +00:00
|
|
|
print_tag(tag_name, value, attributes)
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-07-20 04:01:23 +00:00
|
|
|
|
2006-06-30 15:14:44 +00:00
|
|
|
def parse_attributes(list)
|
|
|
|
attributes = {}
|
|
|
|
list.scan(/([#.])([-a-zA-Z_()]+)/).each do |type, property|
|
|
|
|
case type
|
|
|
|
when "."
|
|
|
|
attributes[:class] = property
|
|
|
|
when "#"
|
|
|
|
attributes[:id] = property
|
|
|
|
end
|
|
|
|
end
|
|
|
|
attributes
|
|
|
|
end
|
|
|
|
|
|
|
|
def count_levels(line)
|
2006-07-19 22:23:01 +00:00
|
|
|
[line.index(/[^ ]/)/2, line.strip]
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
2006-07-20 04:01:23 +00:00
|
|
|
|
|
|
|
def one_liner?(value)
|
|
|
|
((value.length < 50) && value.scan(/\n/).empty?)
|
|
|
|
end
|
|
|
|
|
|
|
|
def template_eval(code)
|
|
|
|
#@base.instance_eval(code)
|
|
|
|
#render :inline => "<%=#{code}%>"
|
|
|
|
@happy_land.instance_eval(code)
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
class HappyLand #:nodoc
|
|
|
|
def initialize(base, hash_of_assigns, hash_of_locals = {})
|
|
|
|
base.instance_variables.each do |key|
|
|
|
|
value = base.instance_eval(key)
|
|
|
|
eval("#{key} = value")
|
|
|
|
end
|
|
|
|
hash_of_assigns.each do |key, value|
|
|
|
|
eval("@#{key} = value")
|
|
|
|
end
|
|
|
|
@__locals = hash_of_locals
|
|
|
|
@__base = base
|
|
|
|
end
|
|
|
|
|
|
|
|
def set_locals(hash_of_locals)
|
|
|
|
@__locals.merge!(hash_of_locals)
|
|
|
|
end
|
|
|
|
|
|
|
|
def instance_eval(code)
|
|
|
|
eval(code)
|
|
|
|
end
|
|
|
|
|
|
|
|
def method_missing(action, *args, &block)
|
|
|
|
if action.to_s.first == "@"
|
|
|
|
result = @__base.instance_eval(action)
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
result = @__base.send(action, *args, &block)
|
|
|
|
rescue
|
|
|
|
result = @__locals[action.to_s] || @__locals[action.to_sym]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
2006-06-30 15:14:44 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|