mirror of
https://github.com/haml/haml.git
synced 2022-11-09 12:33:31 -05:00
Rewrite AttributeCompiler
This commit is contained in:
parent
06304a2e8c
commit
4cd30ab662
3 changed files with 107 additions and 18 deletions
|
@ -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]]
|
||||
end
|
||||
end
|
||||
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
|
||||
|
|
32
test/hamlit/engine/attributes_test.rb
Normal file
32
test/hamlit/engine/attributes_test.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
describe Hamlit::Engine do
|
||||
include RenderAssertion
|
||||
|
||||
it { assert_inline(%Q[%div], %Q[<div></div>]) }
|
||||
it { assert_inline(%Q[.bar.foo], %Q[<div class='bar foo'></div>]) }
|
||||
it { assert_inline(%Q[.foo.bar], %Q[<div class='foo bar'></div>]) }
|
||||
it { assert_inline(%Q[%div(class='bar foo')], %Q[<div class='bar foo'></div>]) }
|
||||
it { assert_inline(%Q[%div(class='foo bar')], %Q[<div class='foo bar'></div>]) }
|
||||
it { assert_inline(%Q[%div{ class: 'bar foo' }], %Q[<div class='bar foo'></div>]) }
|
||||
it { assert_inline(%q[%a{ href: "'\"" }], %Q[<a href=''"'></a>]) }
|
||||
it { assert_inline(%Q[%a{ href: '/search?foo=bar&hoge=<fuga>' }], %Q[<a href='/search?foo=bar&hoge=<fuga>'></a>]) }
|
||||
|
||||
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
|
||||
<span foo='old'></span>
|
||||
<span foo='old'></span>
|
||||
<span foo='old'></span>
|
||||
<span foo='old'></span>
|
||||
<span foo='old'></span>
|
||||
<span foo='old'></span>
|
||||
HTML
|
||||
end
|
||||
end
|
|
@ -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) || {}
|
||||
|
|
Loading…
Reference in a new issue