Make plain text parser better

This is very difficult for me to implement.
Original implementation is Haml::Util in https://github.com/haml/haml.

Thanks for MIT License.
This commit is contained in:
Takashi Kokubun 2015-03-30 14:08:49 +09:00
parent 773d1cf8f3
commit 2998f95ea5
4 changed files with 53 additions and 11 deletions

View File

@ -1,4 +1,5 @@
Copyright (c) 2015 Takashi Kokubun
Copyright (c) 2006-2009 Hampton Catlin and Natalie Weizenbaum
MIT License

View File

@ -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

View File

@ -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

View File

@ -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 }}
<ht#{2}ml>
HAML
a3aa" [1, 2] b
a3aa" ["1", 2] b " !
a{:a=>3}
<ht2ml>
HTML