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:
parent
3693d828c5
commit
bf5be4da81
4 changed files with 84 additions and 13 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue