Skip to content

Instantly share code, notes, and snippets.

@luikore
Last active December 18, 2015 13:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save luikore/5792186 to your computer and use it in GitHub Desktop.
Save luikore/5792186 to your computer and use it in GitHub Desktop.
Prove of concept: Nested layout render with Y-combinator.
# 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[]

Render order of YRender is the same as output order, so it can be easily modified for stream rendering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment