Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
From f9297c3be76076f940e3f56106328cdf8053dd8d Mon Sep 17 00:00:00 2001 From: Ian Ownbey <ianownbey@ian-ownbeys-computer-2.local> Date: Sun, 10 Feb 2008 19:45:36 -0500 Subject: [PATCH] Allow formatting of nested brackets --- 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
This paste will be private.
From the Design Piracy series on my blog: