From f9297c3be76076f940e3f56106328cdf8053dd8d Mon Sep 17 00:00:00 2001
From: Ian Ownbey <iownbey@notesake.com>
Date: Sun, 10 Feb 2008 19:45:36 -0500
Subject: [PATCH] Allow formatting of nested brackets and bring line parsing to its own function
---
lib/haml/precompiler.rb | 32 +++++++++++++++++++++++---------
test/haml/engine_test.rb | 7 +++++++
2 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/lib/haml/precompiler.rb b/lib/haml/precompiler.rb
index 74408dd..64206b3 100644
--- a/lib/haml/precompiler.rb
+++ b/lib/haml/precompiler.rb
@@ -473,15 +473,30 @@ END
def prerender_tag(name, atomic, attributes)
"<#{name}#{Precompiler.build_attributes(@options[:attr_wrapper], attributes)}#{atomic ? ' />' : '>'}"
end
+
+ # Parses a line into tag_name, attributes, attributes_hash, object_ref, action, value
+ def parse_line(line)
+ %w{ tag_name attributes action value }.each {|x| eval("#{x} = String.new")}
+ raise SyntaxError.new("Invalid tag: \"#{line}\"") unless match = line.scan(/[%]([-:\w]+)([-\w\.\#]*)(.*)/)[0]
+ tag_name, attributes, rest = match
+ if rest[0] == ?{
+ scanner = StringScanner.new(rest)
+ attributes_hash, rest = balance_brackets(scanner, 0)
+ attributes_hash = attributes_hash[1, attributes_hash.length] if attributes_hash
+ end
+ if rest
+ object_ref, rest = rest.scan(/(\[.*\])?(.*)/)[0]
+ action, value = rest.scan(/([=\/\~]?)?(.*)?/)[0]
+ end
+ value = value.to_s.strip
+ [tag_name, attributes, attributes_hash, object_ref, action, value]
+ end
# Parses a line that will render as an XHTML tag, and adds the code that will
# render that tag to <tt>@precompiled</tt>.
def render_tag(line)
- raise SyntaxError.new("Invalid tag: \"#{line}\"") unless match = line.scan(TAG_REGEX)[0]
- tag_name, attributes, attributes_hash, object_ref, action, value = match
- value = value.to_s.strip
- attributes_hash = attributes_hash[1...-1] if attributes_hash
-
+ tag_name, attributes, attributes_hash, object_ref, action, value = parse_line(line)
+
raise SyntaxError.new("Illegal element: classes and ids must have values.") if attributes =~ /[\.#](\.|#|\z)/
case action
@@ -621,21 +636,20 @@ END
while scan.scan(/(.*?)\\\#\{/)
str << scan.matched[0...-3]
- str << eval("\"\\\#{#{balance_brackets(scan)}}\"")
+ str << eval("\"\\\#{#{balance_brackets(scan)[0]}}\"")
end
str + scan.rest
end
- def balance_brackets(scanner)
+ def balance_brackets(scanner, count = 1)
str = ''
- count = 1
while scanner.scan(/(.*?)[\{\}]/)
str << scanner.matched
count += 1 if scanner.matched[-1] == ?{
count -= 1 if scanner.matched[-1] == ?}
- return str[0...-1] if count == 0
+ return [str[0...-1], scanner.rest] if count == 0
end
raise SyntaxError.new("Unbalanced brackets.")
diff --git a/test/haml/engine_test.rb b/test/haml/engine_test.rb
index a178ecc..944cfe9 100644
--- a/test/haml/engine_test.rb
+++ b/test/haml/engine_test.rb
@@ -133,6 +133,13 @@ class EngineTest < Test::Unit::TestCase
assert_equal("<p escaped='quo4te'>\n</p>\n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}"))
end
+ def test_correct_parsing_with_brackets
+ assert_equal("<p class='foo'>{tada} foo</p>\n", render("%p{:class => 'foo'} {tada} foo"))
+ assert_equal("<p class='foo'>deep {nested { things }}</p>\n", render("%p{:class => 'foo'} deep {nested { things }}"))
+ assert_equal("<p class='bar foo'>{a { d</p>\n", render("%p{{:class => 'foo'}, :class => 'bar'} {a { d"))
+ assert_equal("<p>}</p>\n", render("%p }"))
+ end
+
def test_empty_attrs
assert_equal("<p attr=''>empty</p>\n", render("%p{ :attr => '' } empty"))
assert_equal("<p attr=''>empty</p>\n", render("%p{ :attr => x } empty", :locals => {:x => ''}))
--
1.5.3.6