diff --git a/lib/hamlit/compiler/attribute_compiler.rb b/lib/hamlit/compiler/attribute_compiler.rb index 70d6463a..ce932cc8 100644 --- a/lib/hamlit/compiler/attribute_compiler.rb +++ b/lib/hamlit/compiler/attribute_compiler.rb @@ -5,41 +5,94 @@ module Hamlit class Compiler class AttributeCompiler def initialize(options = {}) - @quote = options[:attr_quote].inspect.freeze + @quote = options[:attr_quote] @format = options[:format] @escape_attrs = options[:escape_attrs] end def compile(node) - [:html, :attrs].tap do |temple| - case - when !node.value[:attributes_hashes].empty? - compile_on_runtime!(temple, node) - when !node.value[:attributes].empty? - compile_static_attributes!(temple, node) - end + hashes = [] + node.value[:attributes_hashes].each do |attribute_str| + hash = HashParser.parse(attribute_str) + return runtime_compile(node) unless hash + hashes << hash end + static_compile(node.value[:attributes], hashes) end private - def compile_on_runtime!(temple, node) + def runtime_compile(node) attrs = node.value[:attributes_hashes] attrs.unshift(node.value[:attributes].inspect) if node.value[:attributes] != {} - temple << [:dynamic, "::Hamlit::AttributeBuilder.build(#{@quote}, #{@format.inspect}, #{attrs.join(', ')})"] + [:html, + :attrs, + [:dynamic, + '::Hamlit::AttributeBuilder.build' \ + "(#{@quote.inspect}, #{@format.inspect}, #{attrs.join(', ')})", + ], + ] end - def compile_static_attributes!(temple, node) - node.value[:attributes].sort_by(&:first).each do |name, value| - case - when value == true - temple << [:html, :attr, name, [:multi]] - when @escape_attrs - temple << [:html, :attr, name, [:escape, true, [:static, value]]] + def static_compile(static_hash, dynamic_hashes) + temple = [:html, :attrs] + keys = [*static_hash.keys, *dynamic_hashes.map(&:keys).flatten].uniq.sort + keys.each do |key| + case key + when 'id'.freeze + compile_id!(temple, key, static_hash, dynamic_hashes) + when 'class'.freeze + compile_class!(temple, key, static_hash, dynamic_hashes) + when 'data'.freeze + compile_data!(temple, key, static_hash, dynamic_hashes) + when *AttributeBuilder::BOOLEAN_ATTRIBUTES + compile_boolean!(temple, key, static_hash, dynamic_hashes) else - temple << [:html, :attr, name, [:static, value]] + compile_common!(temple, key, static_hash, dynamic_hashes) end end + temple + end + + def compile_id!(temple, key, static_hash, dynamic_hashes) + temple << build_attr(:static, key, static_hash[key]) if static_hash[key] + dynamic_hashes.each do |dynamic_hash| + temple << build_attr(:dynamic, key, dynamic_hash[key]) if dynamic_hash[key] + end + end + + def compile_class!(temple, key, static_hash, dynamic_hashes) + temple << build_attr(:static, key, static_hash[key]) if static_hash[key] + dynamic_hashes.each do |dynamic_hash| + temple << build_attr(:dynamic, key, dynamic_hash[key]) if dynamic_hash[key] + end + end + + def compile_data!(temple, key, static_hash, dynamic_hashes) + temple << build_attr(:static, key, static_hash[key]) if static_hash[key] + dynamic_hashes.each do |dynamic_hash| + temple << build_attr(:dynamic, key, dynamic_hash[key]) if dynamic_hash[key] + end + end + + def compile_boolean!(temple, key, static_hash, dynamic_hashes) + value = build_attr(:static, key, static_hash[key]) if static_hash[key] + dynamic_hashes.each do |dynamic_hash| + value = build_attr(:dynamic, key, dynamic_hash[key]) if dynamic_hash[key] + end + temple << value + end + + def compile_common!(temple, key, static_hash, dynamic_hashes) + value = build_attr(:static, key, static_hash[key]) if static_hash[key] + dynamic_hashes.each do |dynamic_hash| + value = build_attr(:dynamic, key, dynamic_hash[key]) if dynamic_hash[key] + end + temple << value + end + + def build_attr(type, key, value) + [:html, :attr, key, [:escape, @escape_attrs, [type, value]]] end end end diff --git a/test/hamlit/engine/attributes_test.rb b/test/hamlit/engine/attributes_test.rb new file mode 100644 index 00000000..ee025f62 --- /dev/null +++ b/test/hamlit/engine/attributes_test.rb @@ -0,0 +1,32 @@ +describe Hamlit::Engine do + include RenderAssertion + + it { assert_inline(%Q[%div], %Q[
]) } + it { assert_inline(%Q[.bar.foo], %Q[
]) } + it { assert_inline(%Q[.foo.bar], %Q[
]) } + it { assert_inline(%Q[%div(class='bar foo')], %Q[
]) } + it { assert_inline(%Q[%div(class='foo bar')], %Q[
]) } + it { assert_inline(%Q[%div{ class: 'bar foo' }], %Q[
]) } + it { assert_inline(%q[%a{ href: "'\"" }], %Q[]) } + it { assert_inline(%Q[%a{ href: '/search?foo=bar&hoge=' }], %Q[]) } + + specify do + assert_render(<<-HAML, <<-HTML) + - new = 'new' + - old = 'old' + %span(foo='new'){ foo: 'old' } + %span{ foo: 'old' }(foo='new') + %span(foo=new){ foo: 'old' } + %span{ foo: 'old' }(foo=new) + %span(foo=new){ foo: old } + %span{ foo: old }(foo=new) + HAML + + + + + + + HTML + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 9e18eff9..5faf1a04 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -36,6 +36,10 @@ module RenderAssertion assert_equal html, render(haml, options) end + def assert_inline(haml, html) + assert_equal html + "\n", render(haml + "\n") + end + def render(text, options = {}, &block) scope = options.delete(:scope) || Object.new locals = options.delete(:locals) || {}