mirror of
https://github.com/haml/haml.git
synced 2022-11-09 12:33:31 -05:00
115 lines
2.5 KiB
Ruby
115 lines
2.5 KiB
Ruby
require 'ripper'
|
|
|
|
# This module compiles new-style attributes, which is
|
|
# surrounded by parentheses.
|
|
module Hamlit
|
|
module Compilers
|
|
module NewAttribute
|
|
TYPE_POSITION = 1
|
|
|
|
def compile_new_attribute(str)
|
|
str = str.gsub(/\A\(|\)\Z/, '')
|
|
attrs = parse_new_attributes(str)
|
|
attrs.map do |key, value|
|
|
next true_attribute(key) if value == 'true'
|
|
[:html, :attr, key, [:dynamic, value]]
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def parse_new_attributes(str)
|
|
attributes = {}
|
|
|
|
while str.length > 0
|
|
tokens = Ripper.lex(str)
|
|
key = read_key!(tokens)
|
|
val = read_value!(tokens)
|
|
attributes[key] = val if key && val
|
|
|
|
token = tokens.first
|
|
break unless token
|
|
|
|
pos = token.first.last
|
|
str = str[pos..-1]
|
|
end
|
|
|
|
attributes
|
|
end
|
|
|
|
def read_key!(tokens)
|
|
skip_tokens!(tokens, :on_sp)
|
|
(row, col), type, key = tokens.shift
|
|
|
|
skip_tokens!(tokens, :on_sp)
|
|
(row, col), type, str = tokens.shift
|
|
raise SyntaxError if str != '='
|
|
|
|
key
|
|
end
|
|
|
|
def read_value!(tokens)
|
|
skip_tokens!(tokens, :on_sp)
|
|
return if tokens.empty?
|
|
|
|
case tokens.first[TYPE_POSITION]
|
|
when :on_tstring_beg
|
|
val = fetch_balanced_quotes(tokens)
|
|
else
|
|
val = fetch_until(tokens, :on_sp)
|
|
end
|
|
val.length.times { tokens.shift }
|
|
val.map(&:last).join
|
|
end
|
|
|
|
def fetch_balanced_quotes(all_tokens)
|
|
tokens = []
|
|
open_count = 0
|
|
|
|
all_tokens.each do |token|
|
|
(row, col), type, str = token
|
|
case type
|
|
when :on_tstring_beg then open_count += 1
|
|
when :on_tstring_end then open_count -= 1
|
|
end
|
|
|
|
tokens << token
|
|
break if open_count == 0
|
|
end
|
|
|
|
tokens
|
|
end
|
|
|
|
def fetch_until(all_tokens, type)
|
|
tokens = []
|
|
|
|
all_tokens.each do |token|
|
|
break if token[TYPE_POSITION] == type
|
|
tokens << token
|
|
end
|
|
|
|
tokens
|
|
end
|
|
|
|
def skip_tokens!(tokens, *types)
|
|
while types.include?(type_of(tokens.first))
|
|
tokens.shift
|
|
end
|
|
end
|
|
|
|
def type_of(token)
|
|
return nil unless token
|
|
token[TYPE_POSITION]
|
|
end
|
|
|
|
def true_attribute(key)
|
|
case options[:format]
|
|
when :xhtml
|
|
[:html, :attr, key, [:static, key]]
|
|
else
|
|
[:html, :attr, key, [:multi]]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|