Render order of YRender is the same as output order, so it can be easily modified for stream rendering.
Last active
December 18, 2015 13:48
-
-
Save luikore/5792186 to your computer and use it in GitHub Desktop.
Prove of concept: Nested layout render with Y-combinator.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# simulate template rendering | |
class Template < Struct.new(:name) | |
def render | |
puts "#{name}_begin" | |
r = "#{name}_begin\n" | |
r << yield if block_given? | |
puts "#{name}_end\n" | |
r << "#{name}_end\n" | |
end | |
end | |
def Y f | |
g = -> h, *x { f[h[h], *x] }.curry 2 | |
g[g] | |
end | |
YRender = Y -> f, n, layouts { | |
if n == 0 | |
layouts[0].render | |
else | |
layouts[n].render { f.call n - 1, layouts } | |
end | |
} | |
def render_all_y layouts | |
YRender.call (layouts.size - 1), layouts | |
end | |
def render_all_inside_out layouts | |
layouts.inject '' do |r, e| | |
e.render { r } | |
end | |
end | |
def render_all_outside_in layouts | |
outside, *inside = layouts.reverse.map do |e| | |
e.render { '<render:yield/>' } | |
end | |
inside.each do |r| | |
outside.gsub! '<render:yield/>', r | |
end | |
outside | |
end | |
def render_all_in_order layouts | |
top = layouts.pop | |
if layouts.empty? | |
top.render | |
else | |
top.render { render_all_in_order layouts } | |
end | |
end | |
layouts = -> { %w'page layout2 layout1'.map{|name| Template.new name } } | |
puts "\n== Y ==" | |
render_all_y layouts[] | |
puts "\n== inside -> outside ==" | |
render_all_inside_out layouts[] | |
puts "\n== ouside -> inside ==" | |
render_all_outside_in layouts[] | |
puts "\n== recursive in order ==" | |
render_all_in_order layouts[] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment