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>
<hr>
<p>Footer template part</p>
<p>Same exact value but in a different part: <%= localrand %></p>
</footer>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,18 +7,20 @@ module Hyde
module Templates
# ERB Template language adapter
class ERB < Hyde::Template
# @see Hyde::Template#new
def initialize(input, toplevel: nil, locals: nil)
# @see {Hyde::Template#new}
def initialize(input, vars = nil, parent:)
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)"
end
# Run the template.
def run
@context.instance_exec(@template,@binding) do |template, binding|
template.result binding
end
@template.result @binding
end
end
end

View File

@ -93,6 +93,7 @@ module Hyde
<head>
<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>
<meta charset="utf-8">
</head>
<body>
<div class="header">