diff --git a/lib/hamlit/concerns/line_reader.rb b/lib/hamlit/concerns/line_reader.rb index 2849482f..b1751a87 100644 --- a/lib/hamlit/concerns/line_reader.rb +++ b/lib/hamlit/concerns/line_reader.rb @@ -6,6 +6,10 @@ module Hamlit @current_lineno = -1 end + def current_line + @lines[@current_lineno] + end + # Return nearest line ignoring empty lines. def next_line lineno = @current_lineno + 1 diff --git a/lib/hamlit/engine.rb b/lib/hamlit/engine.rb index c2501764..ba6b0566 100644 --- a/lib/hamlit/engine.rb +++ b/lib/hamlit/engine.rb @@ -1,12 +1,14 @@ require 'temple' require 'hamlit/attribute_compiler' -require 'hamlit/script_compiler' +require 'hamlit/multiline_preprocessor' require 'hamlit/parser' +require 'hamlit/script_compiler' module Hamlit class Engine < Temple::Engine define_options generator: Temple::Generators::ArrayBuffer + use MultilinePreprocessor use Parser use ScriptCompiler use AttributeCompiler diff --git a/lib/hamlit/multiline_preprocessor.rb b/lib/hamlit/multiline_preprocessor.rb new file mode 100644 index 00000000..560d037c --- /dev/null +++ b/lib/hamlit/multiline_preprocessor.rb @@ -0,0 +1,56 @@ +require 'temple' +require 'hamlit/concerns/line_reader' + +module Hamlit + class MultilinePreprocessor < Temple::Parser + include Concerns::LineReader + + def call(template) + reset_lines(template.split("\n")) + preprocess_multilines + end + + private + + def preprocess_multilines + result = [] + + while @lines[@current_lineno + 1] + @current_lineno += 1 + + if end_with_pipe?(current_line) + prefix = current_line[/\A */] + lines = scan_multilines + + result << prefix + build_multiline(lines) + (lines.length - 1).times { result << '' } + else + result << current_line + end + end + result.map { |line| "#{line}\n" }.join + end + + def end_with_pipe?(line) + return false unless line + line.strip =~ / \|\Z/ + end + + def scan_multilines + lines = [] + while end_with_pipe?(current_line) + lines << current_line + @current_lineno += 1 + end + @current_lineno -= 1 + lines + end + + def build_multiline(lines) + lines = lines.map do |line| + line.strip.gsub(/ *\|\Z/, '') + end + lines.join(' ') + end + end +end diff --git a/lib/hamlit/parser.rb b/lib/hamlit/parser.rb index a49b5e77..c53d8d1f 100644 --- a/lib/hamlit/parser.rb +++ b/lib/hamlit/parser.rb @@ -39,7 +39,7 @@ module Hamlit ast = [] while next_indent == @current_indent @current_lineno += 1 - ast << parse_line(@lines[@current_lineno]) + ast << parse_line(current_line) ast << [:static, "\n"] unless skip_newline?(ast.last) ast << [:newline] end diff --git a/spec/hamlit/engine/multiline_spec.rb b/spec/hamlit/engine/multiline_spec.rb new file mode 100644 index 00000000..4b867141 --- /dev/null +++ b/spec/hamlit/engine/multiline_spec.rb @@ -0,0 +1,24 @@ +describe Hamlit::Engine do + describe 'multiline' do + it 'joins multi-lines ending with pipe' do + assert_render(<<-HAML, <<-HTML) + a | + b | + HAML + a b + HTML + end + + it 'renders multi lines' do + assert_render(<<-HAML, <<-HTML) + = 'a' + | + 'b' + | + 'c' | + 'd' + HAML + abc + 'd' + HTML + end + end +end diff --git a/spec/hamlit/multiline_preprocessor_spec.rb b/spec/hamlit/multiline_preprocessor_spec.rb new file mode 100644 index 00000000..cb3ac5d1 --- /dev/null +++ b/spec/hamlit/multiline_preprocessor_spec.rb @@ -0,0 +1,42 @@ +describe Hamlit::MultilinePreprocessor do + describe '#call' do + def assert_multiline_preprocess(before, after) + result = described_class.new.call(before) + expect(result).to eq(after) + end + + it 'does not alter normal lines' do + assert_multiline_preprocess(<<-HAML, <<-HAML) + abc + d| + ef + HAML + abc + d| + ef + HAML + end + + it 'joins multi-lines' do + assert_multiline_preprocess(<<-HAML, <<-HAML) + abc | + d | + ef + HAML + abc d + + ef + HAML + end + + it 'joins multi-lines' do + assert_multiline_preprocess(<<-HAML, <<-HAML) + = 'a' + | + 'b' | + HAML + = 'a' + 'b' + + HAML + end + end +end