diff --git a/REFERENCE b/REFERENCE index 17c2cc5d..ab6ad038 100644 --- a/REFERENCE +++ b/REFERENCE @@ -85,9 +85,10 @@ closing tags for any element. ==== {} Brackets represent a Ruby hash that is used for specifying the attributes of an -element. It is literally evaluated as a Ruby hash, so logic will work in it. At -the moment, though, it doesn't see local variables. The hash is placed after -the tag is defined. For example: +element. It is literally evaluated as a Ruby hash, so logic will work in it, and +local variables may be used. Quote characters within the attribute will be replaced +by appropriate escape sequences. The hash is placed after the tag is defined. For +example: %head{ :name => "doc_head" } %script{ 'type' => "text/" + "javascript", :src => "javascripts/script_#{2 + 7}" } diff --git a/lib/haml/buffer.rb b/lib/haml/buffer.rb index 40be89c6..ff200ac8 100644 --- a/lib/haml/buffer.rb +++ b/lib/haml/buffer.rb @@ -18,6 +18,7 @@ module Haml # Creates a new buffer. def initialize(options = {}) @options = options + @quote_escape = options[:attr_wrapper] == '"' ? """ : "'" @buffer = "" @one_liner_pending = false end @@ -150,9 +151,12 @@ module Haml end result = attributes.sort.collect do |a,v| unless v.nil? - first_quote_type = v.to_s.scan(/['"]/).first - quote_type = (first_quote_type == "'") ? '"' : "'" - "#{a.to_s}=#{quote_type}#{v.to_s}#{quote_type}" + v = v.to_s + attr_wrapper = @options[:attr_wrapper] + if v.include? attr_wrapper + v = v.gsub(attr_wrapper, @quote_escape) + end + "#{a.to_s}=#{attr_wrapper}#{v}#{attr_wrapper}" end end result = result.compact.join(' ') diff --git a/lib/haml/engine.rb b/lib/haml/engine.rb index 4839c002..77634124 100644 --- a/lib/haml/engine.rb +++ b/lib/haml/engine.rb @@ -97,10 +97,17 @@ module Haml # [:precompiled] A string containing a precompiled Haml template. # If this is passed, template is ignored # and no precompilation is done. + # + # [:attr_wrapper] The character that should wrap element attributes. + # This defaults to ' (an apostrophe). Characters + # of this type within the attributes will be escaped + # (e.g. by replacing them with ') if + # the character is an apostrophe or a quotation mark. def initialize(template, options = {}) @options = { - :suppress_eval => false + :suppress_eval => false, + :attr_wrapper => "'" }.merge options @precompiled = @options[:precompiled] @@ -117,7 +124,7 @@ module Haml # a string. def to_html(scope = Object.new, &block) @scope_object = scope - @buffer = Haml::Buffer.new + @buffer = Haml::Buffer.new(@options) # Compile the @precompiled buffer compile &block diff --git a/test/engine_test.rb b/test/engine_test.rb index c6f63e42..38985aab 100644 --- a/test/engine_test.rb +++ b/test/engine_test.rb @@ -16,6 +16,11 @@ class EngineTest < Test::Unit::TestCase def test_stop_eval assert_equal("", render("= 'Hello'", :suppress_eval => true)) end + + def test_attr_wrapper + assert_equal("
\n
\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*')) + assert_equal("\n
\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"')) + end # This is ugly because Hashes are unordered; we don't always know the order # in which attributes will be returned. diff --git a/test/results/just_stuff.xhtml b/test/results/just_stuff.xhtml index 9147b5d9..9783cc21 100644 --- a/test/results/just_stuff.xhtml +++ b/test/results/just_stuff.xhtml @@ -3,6 +3,7 @@ +Boo!