Recursive templates, simplified erb template class

This commit is contained in:
Yessiest 2023-09-13 20:21:17 +04:00
parent d30b09fe2c
commit d807b64161
10 changed files with 59 additions and 26 deletions

View File

@ -1,4 +1,5 @@
<footer> <footer>
<hr> <hr>
<p>Footer template part</p> <p>Footer template part</p>
<p>Same exact value but in a different part: <%= localrand %></p>
</footer> </footer>

View File

@ -6,10 +6,9 @@ require 'hyde'
app = Hyde::Server.new do app = Hyde::Server.new do
remap ENV["PWD"] remap ENV["PWD"]
get "/" do get "/" do
status 200
header "content-type", "text/html" header "content-type", "text/html"
localrand = rand erb(file("index.rhtml"), { 'localrand' => rand }).run
bind = binding
erb(file("index.rhtml"), toplevel: bind).run
end end
end end

View File

@ -2,6 +2,7 @@
<html> <html>
<head> <head>
<title>Ruby template engine test</title> <title>Ruby template engine test</title>
<meta charset="utf-8">
</head> </head>
<body> <body>
<h1> <h1>
@ -10,5 +11,6 @@
<hr> <hr>
<p> This page exists only to test template engine functionality</p> <p> This page exists only to test template engine functionality</p>
<p> Random value = <%= localrand %></p> <p> Random value = <%= localrand %></p>
<%= import('footer.rhtml') %>
</body> </body>
</html> </html>

View File

@ -6,8 +6,10 @@ module Hyde
module ProbeConstructors module ProbeConstructors
# Create a new erb template # Create a new erb template
# @see Hyde::Template#new # @see Hyde::Template#new
def erb(input, toplevel: nil, locals: nil) def erb(input, vars = nil)
Hyde::Templates::ERB.new(input, toplevel: toplevel, locals: locals) Hyde::Templates::ERB.new(input,
vars,
parent: @origin)
end end
end end
end end

View File

@ -1,9 +1,16 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'erb'
require 'securerandom'
module Hyde module Hyde
module DSL module DSL
# Common methods for template contexts
module TemplateMethods module TemplateMethods
# Import a template part
def import(filepath)
@parent_template.import(file(filepath)).run
end
end end
end end
end end

View File

@ -103,8 +103,8 @@ module Hyde
# @return [Integer, nil] # @return [Integer, nil]
def content_size def content_size
case @body case @body
when String then @body.length when String then @body.bytesize
when Array then @body.join.length when Array then @body.join.bytesize
when File then @body.size when File then @body.size
end end
end end

View File

@ -23,7 +23,7 @@ module Hyde
"handle.default" => proc do |code, backtrace: nil| "handle.default" => proc do |code, backtrace: nil|
page = Hyde::Util.default_error_page(code, backtrace) page = Hyde::Util.default_error_page(code, backtrace)
headers = { headers = {
"content-length": page.length, "content-length": page.bytesize,
"content-type": "text/html" "content-type": "text/html"
} }
[headers, page] [headers, page]

View File

@ -3,6 +3,7 @@
require_relative 'dsl/constructors_probe' require_relative 'dsl/constructors_probe'
require_relative 'dsl/methods_common' require_relative 'dsl/methods_common'
require_relative 'dsl/methods_probe' require_relative 'dsl/methods_probe'
require_relative 'dsl/methods_template'
module Hyde module Hyde
# All template engine adapters subclassed from Template # All template engine adapters subclassed from Template
@ -12,29 +13,37 @@ module Hyde
# Context for template engines # Context for template engines
class TemplateContext class TemplateContext
include Hyde::DSL::CommonMethods
include Hyde::DSL::ProbeMethods
include Hyde::DSL::ProbeConstructors include Hyde::DSL::ProbeConstructors
include Hyde::DSL::ProbeMethods
include Hyde::DSL::CommonMethods
include Hyde::DSL::TemplateMethods
def initialize(parent) # @return [Binding]
def binding
Kernel.binding
end
def initialize(parent, parent_template)
@origin = parent @origin = parent
@parent_template = parent_template
end end
end end
# Interface for Template engines # Interface for Template engines
# @abstract does not represent any actual template engine. # @abstract does not represent any actual template engine.
class Template class Template
# @param input [String, File] # @param input [String, File] template text
# @param context [Binding, nil] # @param vars [Hash] local variables for tempalte
# @param locals [Hash, nil] # @param parent [Hyde::Node] parent node
def initialize(input, toplevel: nil, locals: nil) def initialize(input, vars = {}, parent:)
@template = input.is_a?(File) ? input.read : input @template = input.is_a?(File) ? input.read : input
@context = TemplateContext.new(parent, self)
@parent = parent
input.close if input.is_a? File input.close if input.is_a? File
@binding = toplevel or binding @binding = @context.binding
locals&.each do |k, v| vars.each do |k, v|
@binding.local_variable_set(k,v) @binding.local_variable_set(k, v)
end end
@context = TemplateContext.new(self)
end end
# Set local variable # Set local variable
@ -71,6 +80,16 @@ module Hyde
# ... (stub) # ... (stub)
end end
# Import a template from within current template
def import(filepath)
newtemp = self.class.new(filepath, {}, parent: @parent)
newtemp.binding = @binding
puts newtemp.pretty_inspect
newtemp
end
protected
attr_accessor :binding attr_accessor :binding
end end
end end

View File

@ -7,18 +7,20 @@ module Hyde
module Templates module Templates
# ERB Template language adapter # ERB Template language adapter
class ERB < Hyde::Template class ERB < Hyde::Template
# @see Hyde::Template#new # @see {Hyde::Template#new}
def initialize(input, toplevel: nil, locals: nil) def initialize(input, vars = nil, parent:)
super super
@template = ::ERB.new(@template) varname = "_part_#{SecureRandom.hex(10)}".to_sym
while @binding.local_variable_defined? varname
varname = "_part_#{SecureRandom.hex(10)}".to_sym
end
@template = ::ERB.new(@template, eoutvar: varname)
@template.filename = input.is_a?(File) ? input.path : "(Inline)" @template.filename = input.is_a?(File) ? input.path : "(Inline)"
end end
# Run the template. # Run the template.
def run def run
@context.instance_exec(@template,@binding) do |template, binding| @template.result @binding
template.result binding
end
end end
end end
end end

View File

@ -93,6 +93,7 @@ module Hyde
<head> <head>
<title>#{Util.escape_html(errortext)}</title> <title>#{Util.escape_html(errortext)}</title>
<style> .header {padding: 0.5rem; overflow: auto;} .title { font-weight: bolder; font-size: 48px; margin: 10px 10px; text-shadow: 1px 1px 1px #202222, 2px 2px 2px #404444; float: left } body { margin: 0; } .text { font-size 1rem; } .small { color: #7D7D7D; font-size: 12px;} .code { font-family: monospace; font-size: 0.7rem; } </style> <style> .header {padding: 0.5rem; overflow: auto;} .title { font-weight: bolder; font-size: 48px; margin: 10px 10px; text-shadow: 1px 1px 1px #202222, 2px 2px 2px #404444; float: left } body { margin: 0; } .text { font-size 1rem; } .small { color: #7D7D7D; font-size: 12px;} .code { font-family: monospace; font-size: 0.7rem; } </style>
<meta charset="utf-8">
</head> </head>
<body> <body>
<div class="header"> <div class="header">