1
0
Fork 0
mirror of https://github.com/haml/haml.git synced 2022-11-09 12:33:31 -05:00

Correctly parse nested attributes

This commit is contained in:
Takashi Kokubun 2015-03-14 17:21:11 +09:00
parent 3693d828c5
commit bf5be4da81
4 changed files with 84 additions and 13 deletions

View file

@ -114,7 +114,7 @@ module Hamlit
end
def parse_attributes(scanner)
AttributeParser.parse(scanner).map do |key, value|
AttributeParser.flat_parse(scanner).map do |key, value|
[:html, :attr, key, [:dynamic, value]]
end
end

View file

@ -13,6 +13,26 @@ module Hamlit
parse_attributes(tokens)
end
def flat_parse(scanner)
flatten_attributes(parse(scanner))
end
def flatten_attributes(attributes)
flattened = {}
attributes.each do |key, value|
case value
when Hash
flatten_attributes(value).each do |k, v|
flattened["#{key}-#{k}"] = v
end
else
flattened[key] = value
end
end
flattened
end
private
# Return tokens lexed by Ripper, balancing count of braces.
@ -52,6 +72,9 @@ module Hamlit
key = read_key!(tokens)
val = read_value!(tokens)
attributes[key] = val if key && val
skip_tokens!(tokens, :on_sp)
raise SyntaxError if tokens.any? && type_of(tokens.shift) != :on_comma
end
attributes
@ -88,6 +111,13 @@ module Hamlit
def read_value!(tokens)
result = ''
skip_tokens!(tokens, :on_sp)
if type_of(tokens.first) == :on_lbrace
hash, _ = fetch_balanced_braces(tokens)
hash.length.times { tokens.shift }
return parse_attributes(hash)
end
while token = tokens.shift
(row, col), type, str = token
@ -95,6 +125,7 @@ module Hamlit
when :on_sp
next
when :on_comma
tokens.unshift(token)
break
end
@ -112,6 +143,7 @@ module Hamlit
def assert_rocket!(tokens, *types)
skip_tokens!(tokens, :on_sp)
(row, col), type, str = tokens.shift
raise SyntaxError unless type == :on_op && str == '=>'
end

View file

@ -39,5 +39,13 @@ describe Hamlit::Engine do
<span data-disable="true">bar</span>
HTML
end
it 'parses attributes' do
assert_render(<<-'HAML', <<-HTML)
%span{ data: { disable: true } } bar
HAML
<span data-disable="true">bar</span>
HTML
end
end
end

View file

@ -25,6 +25,14 @@ describe Hamlit::Parser::AttributeParser do
assert_hash(%!{ "foo" => 'bar' }!, { 'foo' => "'bar'" })
end
it 'parses a nested hash' do
assert_hash('{ a: { b: 1 } }', { 'a' => { 'b' => '1' } })
assert_hash(
'{ a: { b: 1, c: 2 }, d: 3, e: {} }',
{ 'a' => { 'b' => '1', 'c' => '2' }, 'd' => '3', 'e' => {} },
)
end
it 'parses a quoted-symbol-key hash' do
assert_hash(%!{ :"data-disable" => true }!, { 'data-disable' => 'true' })
assert_hash(%!{ :'data-disable' => true }!, { 'data-disable' => 'true' })
@ -32,22 +40,45 @@ describe Hamlit::Parser::AttributeParser do
it 'parses a multiple-keys hash' do
assert_hash('{a:"b",c:"d#{e}"}', { 'a' => '"b"', 'c' => '"d#{e}"' })
assert_hash('{ a: 2, :b => "3"}', { 'a' => '2', 'b' => '"3"' })
assert_hash('{ a: 2, :b => ","}', { 'a' => '2', 'b' => '","' })
end
it 'scans balanced hash' do
line = '{ a: 1, b: { c: 4 } }='
s = StringScanner.new(line)
described_class.parse(s)
expect(s.peek(1)).to eq('=')
describe 'scanner position' do
it 'scans balanced hash' do
line = '{ a: 1, b: { c: 4 } }='
s = StringScanner.new(line)
described_class.parse(s)
expect(s.peek(1)).to eq('=')
end
it 'scans balanced hash from internal position' do
line = "%span{class: 'foo'} bar"
s = StringScanner.new(line)
s.scan(/%span/)
described_class.parse(s)
expect(s.peek(1)).to eq(' ')
end
end
end
describe '.flatten_attributes' do
def assert_flatten(attributes, flattened)
result = described_class.flatten_attributes(attributes)
expect(result).to eq(flattened)
end
it 'scans balanced hash from internal position' do
line = "%span{class: 'foo'} bar"
s = StringScanner.new(line)
s.scan(/%span/)
described_class.parse(s)
expect(s.peek(1)).to eq(' ')
it 'flattens hash keys' do
assert_flatten(
{ 'a' => '1', 'b' => { 'c' => '3' } },
{ 'a' => '1', 'b-c' => '3' },
)
end
it 'flattens hash keys' do
assert_flatten(
{ 'a' => { 'b' => {}, 'c' => { 'd' => 'e' }, 'f' => 'g' } },
{ 'a-c-d' => 'e', 'a-f' => 'g' },
)
end
end
end