Skip to content

Commit

Permalink
Compiler: add support for #emit_yield
Browse files Browse the repository at this point in the history
  • Loading branch information
noteflakes committed Feb 19, 2024
1 parent eb0514b commit 41f1958
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 15 deletions.
31 changes: 27 additions & 4 deletions lib/papercraft/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
40 changes: 29 additions & 11 deletions test/test_compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def test_compiler_simple

code = compiled_template_code(templ)
expected = <<~RUBY
->(__buffer__) do
->(__buffer__, &__block__) do
__buffer__ << "<h1>foo</h1><h2>bar</h2>"
__buffer__
end
Expand All @@ -79,7 +79,7 @@ def test_compiler_simple_with_attributes

code = compiled_template_code(templ)
expected = <<~RUBY
->(__buffer__) do
->(__buffer__, &__block__) do
__buffer__ << "<h1 class=\\"foot\\">foo</h1><h2 id=\\"bar\\" onclick=\\"f(&quot;abc&quot;, &quot;def&quot;)\\">bar</h2>"
__buffer__
end
Expand Down Expand Up @@ -292,7 +292,7 @@ def test_text

c = t.compile
expected = <<~RUBY.chomp
->(__buffer__) do
->(__buffer__, &__block__) do
__buffer__ << "foo&amp;bar"
__buffer__ << CGI.escapeHTML((__baz__).to_s)
__buffer__ << "boo"
Expand Down Expand Up @@ -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
Expand All @@ -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)
}
Expand All @@ -372,7 +372,7 @@ def test_tag_content_expr
assert_equal '<p>3</p>', t.to_proc.render
end

def test_tag_content_var
def test_compiler_syntax_tag_content_var
foo = 42
t = c {
p foo
Expand All @@ -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
}
Expand All @@ -399,7 +399,7 @@ def test_tag_content_const
assert_equal '<p>43</p>', 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
Expand All @@ -413,7 +413,7 @@ def test_method_chain
assert_equal '<p>5</p>', t.to_proc.render
end

def test_ivar
def test_compiler_syntax_ivar
@foo = 'bar'

t = c {
Expand All @@ -427,7 +427,7 @@ def test_ivar
assert_equal '<p>bar</p>', t.to_proc.render
end

def test_sub_template_with_args
def test_compiler_syntax_sub_template_with_args
sub = ->(x) {
p x
}
Expand All @@ -445,4 +445,22 @@ def test_sub_template_with_args
assert_equal template_body(expected), t.code_buffer.chomp
assert_equal '<div><p>42</p></div>', 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__ << \"<p>foo</p>\"
}
RUBY
assert_equal template_body(expected), t.code_buffer.chomp
assert_equal '<div><p>foo</p></div>', t.to_proc.render
end
end

0 comments on commit 41f1958

Please sign in to comment.