diff --git a/LICENSE.txt b/LICENSE.txt index fa237b90..5c6ad1c2 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,5 @@ Copyright (c) 2015 Takashi Kokubun +Copyright (c) 2006-2009 Hampton Catlin and Natalie Weizenbaum MIT License diff --git a/lib/hamlit/compilers/text.rb b/lib/hamlit/compilers/text.rb index d5555be1..246bc645 100644 --- a/lib/hamlit/compilers/text.rb +++ b/lib/hamlit/compilers/text.rb @@ -1,17 +1,14 @@ -# NOTE: This compiler has an extremely bad effect for performance. +require 'hamlit/concerns/string_literal' + +# FIXME: This compiler has an extremely bad effect for performance. # We should optimize this. module Hamlit module Compilers module Text + include Concerns::StringLiteral + def on_haml_text(exp) - compile_text(exp) - end - - private - - # FIXME: This can't parse '!' - def compile_text(exp) - [:dynamic, "%Q!#{exp}!"] + [:dynamic, string_literal(exp)] end end end diff --git a/lib/hamlit/concerns/string_literal.rb b/lib/hamlit/concerns/string_literal.rb new file mode 100644 index 00000000..44e0c61c --- /dev/null +++ b/lib/hamlit/concerns/string_literal.rb @@ -0,0 +1,44 @@ +module Hamlit + module Concerns + module StringLiteral + def string_literal(str) + unescape_interpolation(str) + end + + private + + def unescape_interpolation(str) + res = '' + rest = handle_interpolation(str.inspect) do |scan| + escapes = (scan[2].size - 1) / 2 + res << scan.matched[0...-3 - escapes] + if escapes % 2 == 1 + res << '#{' + else + content = eval('"' + balance(scan, ?{, ?}, 1)[0][0...-1] + '"') + res << '#{' + content + '}' + end + end + res + rest + end + + def handle_interpolation(str) + scan = StringScanner.new(str) + yield scan while scan.scan(/(.*?)(\\*)\#\{/) + scan.rest + end + + def balance(scanner, start, finish, count = 0) + str = '' + scanner = StringScanner.new(scanner) unless scanner.is_a? StringScanner + regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE) + while scanner.scan(regexp) + str << scanner.matched + count += 1 if scanner.matched[-1] == start + count -= 1 if scanner.matched[-1] == finish + return [str.strip, scanner.rest] if count == 0 + end + end + end + end +end diff --git a/spec/hamlit/engine/text_spec.rb b/spec/hamlit/engine/text_spec.rb index 31d68e7e..eea1580e 100644 --- a/spec/hamlit/engine/text_spec.rb +++ b/spec/hamlit/engine/text_spec.rb @@ -2,11 +2,11 @@ describe Hamlit::Engine do describe 'text' do it 'renders string interpolation' do assert_render(<<-'HAML', <<-HTML) - #{ "a#{3}a" }a" #{[1, 2]} b + #{ "a#{3}a" }a" #{["1", 2]} b " ! a#{{ a: 3 }} HAML - a3aa" [1, 2] b + a3aa" ["1", 2] b " ! a{:a=>3} HTML