mirror of
https://github.com/haml/haml.git
synced 2022-11-09 12:33:31 -05:00
Merge AttributeCompiler into Compiler
This commit is contained in:
parent
c6465523cc
commit
c91944b307
8 changed files with 156 additions and 213 deletions
|
@ -1,141 +0,0 @@
|
|||
require 'ripper'
|
||||
require 'hamlit/filter'
|
||||
require 'hamlit/concerns/balanceable'
|
||||
|
||||
# AttributeCompiler compiles only old-style attribute, which is
|
||||
# surrounded by brackets.
|
||||
module Hamlit
|
||||
class AttributeCompiler < Hamlit::Filter
|
||||
include Concerns::Balanceable
|
||||
|
||||
TYPE_POSITION = 1
|
||||
|
||||
def on_haml_attrs(*exps)
|
||||
attrs = []
|
||||
exps.map do |exp|
|
||||
case exp
|
||||
when /\A{.+}\Z/
|
||||
attrs += compile_attribute(exp)
|
||||
else
|
||||
attrs << compile(exp)
|
||||
end
|
||||
end
|
||||
[:haml, :attrs, *attrs]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compile_attribute(str)
|
||||
tokens = Ripper.lex(str)
|
||||
attrs = parse_attributes(tokens)
|
||||
flatten_attributes(attrs).map do |key, value|
|
||||
[:html, :attr, key, [:dynamic, value]]
|
||||
end
|
||||
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
|
||||
|
||||
# Parse brace-balanced tokens and return the result as hash
|
||||
def parse_attributes(tokens)
|
||||
tokens = tokens.slice(1..-2) # strip braces
|
||||
attributes = {}
|
||||
|
||||
while tokens && tokens.any?
|
||||
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
|
||||
end
|
||||
|
||||
def read_key!(tokens)
|
||||
skip_tokens!(tokens, :on_sp)
|
||||
|
||||
(row, col), type, str = tokens.shift
|
||||
case type
|
||||
when :on_label
|
||||
str.gsub!(/:\Z/, '')
|
||||
when :on_symbeg
|
||||
if %w[:" :'].include?(str)
|
||||
str = read_string!(tokens)
|
||||
else
|
||||
(row, col), type, str = tokens.shift
|
||||
end
|
||||
assert_rocket!(tokens)
|
||||
when :on_tstring_beg
|
||||
str = read_string!(tokens)
|
||||
assert_rocket!(tokens)
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
def read_string!(tokens)
|
||||
(row, col), type, str = tokens.shift
|
||||
return '' if type == :on_tstring_end
|
||||
|
||||
raise SyntaxError if type_of(tokens.shift) != :on_tstring_end
|
||||
str
|
||||
end
|
||||
|
||||
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
|
||||
case type
|
||||
when :on_sp
|
||||
next
|
||||
when :on_comma
|
||||
tokens.unshift(token)
|
||||
break
|
||||
end
|
||||
|
||||
result += str
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def skip_tokens!(tokens, *types)
|
||||
while types.include?(type_of(tokens.first))
|
||||
tokens.shift
|
||||
end
|
||||
end
|
||||
|
||||
def assert_rocket!(tokens, *types)
|
||||
skip_tokens!(tokens, :on_sp)
|
||||
(row, col), type, str = tokens.shift
|
||||
|
||||
raise SyntaxError unless type == :on_op && str == '=>'
|
||||
end
|
||||
|
||||
def type_of(token)
|
||||
return nil unless token
|
||||
token[TYPE_POSITION]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,7 +2,6 @@ require 'hamlit/compilers/attributes'
|
|||
require 'hamlit/compilers/doctype'
|
||||
require 'hamlit/compilers/dynamic'
|
||||
require 'hamlit/compilers/filter'
|
||||
require 'hamlit/compilers/new_attribute'
|
||||
require 'hamlit/compilers/preserve'
|
||||
require 'hamlit/compilers/script'
|
||||
require 'hamlit/compilers/text'
|
||||
|
@ -14,7 +13,6 @@ module Hamlit
|
|||
include Compilers::Doctype
|
||||
include Compilers::Dynamic
|
||||
include Compilers::Filter
|
||||
include Compilers::NewAttribute
|
||||
include Compilers::Preserve
|
||||
include Compilers::Script
|
||||
include Compilers::Text
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
require 'hamlit/compilers/new_attribute'
|
||||
require 'hamlit/compilers/old_attribute'
|
||||
|
||||
module Hamlit
|
||||
module Compilers
|
||||
module Attributes
|
||||
def on_haml_attrs(*exps)
|
||||
attrs = []
|
||||
exps.each do |exp|
|
||||
case exp
|
||||
when /\A(.+)\Z/
|
||||
attrs += compile_new_attribute(exp)
|
||||
else
|
||||
attrs << compile(exp)
|
||||
end
|
||||
end
|
||||
include Compilers::NewAttribute
|
||||
include Compilers::OldAttribute
|
||||
|
||||
def on_haml_attrs(*attrs)
|
||||
attrs = compile_attributes(attrs)
|
||||
attrs = join_ids(attrs)
|
||||
attrs = combine_classes(attrs)
|
||||
attrs = pull_class_first(attrs)
|
||||
|
@ -20,6 +17,21 @@ module Hamlit
|
|||
|
||||
private
|
||||
|
||||
def compile_attributes(exps)
|
||||
attrs = []
|
||||
exps.each do |exp|
|
||||
case exp
|
||||
when /\A\(.+\)\Z/
|
||||
attrs += compile_new_attribute(exp)
|
||||
when /\A{.+}\Z/
|
||||
attrs += compile_old_attribute(exp)
|
||||
else
|
||||
attrs << compile(exp)
|
||||
end
|
||||
end
|
||||
attrs
|
||||
end
|
||||
|
||||
def pull_class_first(attrs)
|
||||
class_attrs = filter_attrs(attrs, 'class')
|
||||
combine_classes(class_attrs) + (attrs - class_attrs)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'ripper'
|
||||
|
||||
# NewAttributeCompiler compiles new-style attributes, which is
|
||||
# This module compiles new-style attributes, which is
|
||||
# surrounded by parentheses.
|
||||
module Hamlit
|
||||
module Compilers
|
||||
|
@ -9,7 +9,7 @@ module Hamlit
|
|||
|
||||
def compile_new_attribute(str)
|
||||
str = str.gsub(/\A\(|\)\Z/, '')
|
||||
attrs = parse_attributes(str)
|
||||
attrs = parse_new_attributes(str)
|
||||
attrs.map do |key, value|
|
||||
[:html, :attr, key, [:dynamic, value]]
|
||||
end
|
||||
|
@ -17,7 +17,7 @@ module Hamlit
|
|||
|
||||
private
|
||||
|
||||
def parse_attributes(str)
|
||||
def parse_new_attributes(str)
|
||||
attributes = {}
|
||||
|
||||
while str.length > 0
|
||||
|
|
130
lib/hamlit/compilers/old_attribute.rb
Normal file
130
lib/hamlit/compilers/old_attribute.rb
Normal file
|
@ -0,0 +1,130 @@
|
|||
require 'ripper'
|
||||
require 'hamlit/concerns/balanceable'
|
||||
|
||||
# This module compiles only old-style attribute, which is
|
||||
# surrounded by brackets.
|
||||
# FIXME: remove duplicated code with NewAttribute
|
||||
module Hamlit
|
||||
module Compilers
|
||||
module OldAttribute
|
||||
include Concerns::Balanceable
|
||||
|
||||
TYPE_POSITION = 1
|
||||
|
||||
def compile_old_attribute(str)
|
||||
tokens = Ripper.lex(str)
|
||||
attrs = parse_old_attributes(tokens)
|
||||
flatten_attributes(attrs).map do |key, value|
|
||||
[:html, :attr, key, [:dynamic, value]]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
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
|
||||
|
||||
# Parse brace-balanced tokens and return the result as hash
|
||||
def parse_old_attributes(tokens)
|
||||
tokens = tokens.slice(1..-2) # strip braces
|
||||
attributes = {}
|
||||
|
||||
while tokens && tokens.any?
|
||||
key = read_hash_key!(tokens)
|
||||
val = read_hash_value!(tokens)
|
||||
attributes[key] = val if key && val
|
||||
|
||||
hash_skip_tokens!(tokens, :on_sp)
|
||||
raise SyntaxError if tokens.any? && hash_type_of(tokens.shift) != :on_comma
|
||||
end
|
||||
|
||||
attributes
|
||||
end
|
||||
|
||||
def read_hash_key!(tokens)
|
||||
hash_skip_tokens!(tokens, :on_sp)
|
||||
|
||||
(row, col), type, str = tokens.shift
|
||||
case type
|
||||
when :on_label
|
||||
str.gsub!(/:\Z/, '')
|
||||
when :on_symbeg
|
||||
if %w[:" :'].include?(str)
|
||||
str = read_string!(tokens)
|
||||
else
|
||||
(row, col), type, str = tokens.shift
|
||||
end
|
||||
assert_rocket!(tokens)
|
||||
when :on_tstring_beg
|
||||
str = read_string!(tokens)
|
||||
assert_rocket!(tokens)
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
def read_string!(tokens)
|
||||
(row, col), type, str = tokens.shift
|
||||
return '' if type == :on_tstring_end
|
||||
|
||||
raise SyntaxError if hash_type_of(tokens.shift) != :on_tstring_end
|
||||
str
|
||||
end
|
||||
|
||||
def read_hash_value!(tokens)
|
||||
result = ''
|
||||
hash_skip_tokens!(tokens, :on_sp)
|
||||
|
||||
if hash_type_of(tokens.first) == :on_lbrace
|
||||
hash = fetch_balanced_braces(tokens)
|
||||
hash.length.times { tokens.shift }
|
||||
return parse_old_attributes(hash)
|
||||
end
|
||||
|
||||
while token = tokens.shift
|
||||
(row, col), type, str = token
|
||||
case type
|
||||
when :on_sp
|
||||
next
|
||||
when :on_comma
|
||||
tokens.unshift(token)
|
||||
break
|
||||
end
|
||||
|
||||
result += str
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def hash_skip_tokens!(tokens, *types)
|
||||
while types.include?(hash_type_of(tokens.first))
|
||||
tokens.shift
|
||||
end
|
||||
end
|
||||
|
||||
def assert_rocket!(tokens, *types)
|
||||
hash_skip_tokens!(tokens, :on_sp)
|
||||
(row, col), type, str = tokens.shift
|
||||
|
||||
raise SyntaxError unless type == :on_op && str == '=>'
|
||||
end
|
||||
|
||||
def hash_type_of(token)
|
||||
return nil unless token
|
||||
token[TYPE_POSITION]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,4 @@
|
|||
require 'temple'
|
||||
require 'hamlit/attribute_compiler'
|
||||
require 'hamlit/compiler'
|
||||
require 'hamlit/html/pretty'
|
||||
require 'hamlit/html/ugly'
|
||||
|
@ -17,7 +16,6 @@ module Hamlit
|
|||
|
||||
use Multiline
|
||||
use Parser
|
||||
use AttributeCompiler
|
||||
use Compiler
|
||||
use :Html, -> { create(html_compiler) }
|
||||
filter :Escapable
|
||||
|
|
|
@ -579,7 +579,7 @@ describe "haml" do
|
|||
end
|
||||
|
||||
# FIXME: it requires attribute sorter
|
||||
pending "Ruby-style tag with a CSS class and 'class' as a variable attribute" do
|
||||
specify "Ruby-style tag with a CSS class and 'class' as a variable attribute" do
|
||||
haml = %q{.hello{:class => var}}
|
||||
html = %q{<div class='hello world'></div>}
|
||||
locals = {:var=>"world"}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
describe Hamlit::AttributeCompiler do
|
||||
describe '#call' do
|
||||
it 'does not alter normal attrs' do
|
||||
assert_compile(
|
||||
[:haml,
|
||||
:attrs,
|
||||
[:html, :attr, 'id', [:static, 'foo']],
|
||||
[:html, :attr, 'class', [:static, 'bar']]],
|
||||
[:haml,
|
||||
:attrs,
|
||||
[:html, :attr, 'id', [:static, 'foo']],
|
||||
[:html, :attr, 'class', [:static, 'bar']]],
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not alter news-tyle attributes' do
|
||||
assert_compile(
|
||||
[:haml,
|
||||
:attrs,
|
||||
'(a=2)'],
|
||||
[:haml,
|
||||
:attrs,
|
||||
'(a=2)'],
|
||||
)
|
||||
end
|
||||
|
||||
it 'convers only string' do
|
||||
assert_compile(
|
||||
[:haml,
|
||||
:attrs,
|
||||
[:html, :attr, 'id', [:static, 'foo']],
|
||||
'{ foo: "bar" }',
|
||||
[:html, :attr, 'class', [:static, 'bar']]],
|
||||
[:haml,
|
||||
:attrs,
|
||||
[:html, :attr, 'id', [:static, 'foo']],
|
||||
[:html, :attr, 'foo', [:dynamic, '"bar"']],
|
||||
[:html, :attr, 'class', [:static, 'bar']]],
|
||||
)
|
||||
end
|
||||
|
||||
it 'converts nested attributes' do
|
||||
assert_compile(
|
||||
[:haml,
|
||||
:attrs,
|
||||
'{ a: { b: {}, c: "d" }, e: "f" }'],
|
||||
[:haml,
|
||||
:attrs,
|
||||
[:html, :attr, 'a-c', [:dynamic, '"d"']],
|
||||
[:html, :attr, 'e', [:dynamic, '"f"']]],
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue