diff --git a/lib/papercraft/compiler.rb b/lib/papercraft/compiler.rb index d8bca2e..dd5ca76 100644 --- a/lib/papercraft/compiler.rb +++ b/lib/papercraft/compiler.rb @@ -158,7 +158,7 @@ def compile(template, initial_level = 0) def to_code pad = ' ' * @level - "#{pad}->(__buffer__#{args}) do\n#{prelude}#{@code_buffer}#{pad} __buffer__\n#{pad}end" + "#{pad}->(__buffer__#{args}, &__block__) do\n#{prelude}#{@code_buffer}#{pad} __buffer__\n#{pad}end" end def args @@ -231,6 +231,8 @@ def parse_fcall(node, block = nil) return emit_html5(node, block) when :emit return emit_emit(node.children[1], block) + when :emit_yield + return emit_emit_yield when :text return emit_text_fcall(args.first) end @@ -332,10 +334,14 @@ def emit_emit(args, block) name = value.children.first.to_s value = get_const(name) case value - when Papercraft::Template + when Papercraft::Template, Proc + value = Papercraft.html(&value) if value.is_a?(Proc) @sub_templates << value idx = @sub_templates.size - 1 - emit_code("__sub_templates__[#{idx}].(__buffer__)\n") + @line_break = false + emit_code("__sub_templates__[#{idx}].(__buffer__)") + emit_code_block(block) if block + emit_code("\n") else emit_output { emit_literal(value) } end @@ -349,6 +355,19 @@ def emit_emit(args, block) # end end + def emit_code_block(block) + emit_code(" {\n") + @level += 1 + parse(block.children[2]) + flush_emit_buffer + @level -= 1 + emit_code("}") + end + + def emit_emit_yield + emit_code("__block__.call\n") + end + def emit_tag_attributes(atts) list = atts.children.first.children while true @@ -454,7 +473,7 @@ def parse_integer(node) value = node.children.first emit_literal(value.inspect) end - + def parse_true(node) emit_expression { emit_literal('true') } end @@ -482,6 +501,10 @@ def parse_list(node, emit_array = true, range = nil) def parse_vcall(node) tag = node.children.first + case tag + when :emit_yield + return emit_emit_yield + end emit_tag(tag, nil) end diff --git a/test/test_compiler.rb b/test/test_compiler.rb index 7af1f26..1a072e0 100644 --- a/test/test_compiler.rb +++ b/test/test_compiler.rb @@ -63,7 +63,7 @@ def test_compiler_simple code = compiled_template_code(templ) expected = <<~RUBY - ->(__buffer__) do + ->(__buffer__, &__block__) do __buffer__ << "

foo

bar

" __buffer__ end @@ -79,7 +79,7 @@ def test_compiler_simple_with_attributes code = compiled_template_code(templ) expected = <<~RUBY - ->(__buffer__) do + ->(__buffer__, &__block__) do __buffer__ << "

foo

bar

" __buffer__ end @@ -292,7 +292,7 @@ def test_text c = t.compile expected = <<~RUBY.chomp - ->(__buffer__) do + ->(__buffer__, &__block__) do __buffer__ << "foo&bar" __buffer__ << CGI.escapeHTML((__baz__).to_s) __buffer__ << "boo" @@ -331,12 +331,12 @@ def test_emit_template end end -class SyntaxTest < Minitest::Test +class CompilerSyntaxTest < Minitest::Test def template_body(body) body.chomp.lines.map { |l| " #{l}" }.join end - def test_case + def test_compiler_syntax_case t = C { |x| case x when :foo @@ -359,7 +359,7 @@ def test_empty_template assert_equal '', t.render end - def test_tag_content_expr + def test_compiler_syntax_tag_content_expr t = c { p (1 + 2) } @@ -372,7 +372,7 @@ def test_tag_content_expr assert_equal '

3

', t.to_proc.render end - def test_tag_content_var + def test_compiler_syntax_tag_content_var foo = 42 t = c { p foo @@ -387,7 +387,7 @@ def test_tag_content_var FOO = 43 - def test_tag_content_const + def test_compiler_syntax_tag_content_const t = c { p FOO } @@ -399,7 +399,7 @@ def test_tag_content_const assert_equal '

43

', t.to_proc.render end - def test_method_chain + def test_compiler_syntax_method_chain t = c { 1.next.next.next p 2.next.next.next @@ -413,7 +413,7 @@ def test_method_chain assert_equal '

5

', t.to_proc.render end - def test_ivar + def test_compiler_syntax_ivar @foo = 'bar' t = c { @@ -427,7 +427,7 @@ def test_ivar assert_equal '

bar

', t.to_proc.render end - def test_sub_template_with_args + def test_compiler_syntax_sub_template_with_args sub = ->(x) { p x } @@ -445,4 +445,22 @@ def test_sub_template_with_args assert_equal template_body(expected), t.code_buffer.chomp assert_equal '

42

', t.to_proc.render end + + T1 = ->() { div { emit_yield } } + + def test_compiler_syntax_emit_yield + t = c { + emit(T1) { + p 'foo' + } + } + + expected = <<~RUBY + __sub_templates__[0].(__buffer__) { + __buffer__ << \"

foo

\" + } + RUBY + assert_equal template_body(expected), t.code_buffer.chomp + assert_equal '

foo

', t.to_proc.render + end end