class Template
An evaluatable text-format that can be used to generate output.
Nested
Definitions
def self.capture(*arguments, output: nil, &block)
Capture the output of a block from within a template.
Signature
-
returns
String
the output produced by calling the given block.
Implementation
def self.capture(*arguments, output: nil, &block)
scope = block.binding
previous_output = scope.local_variable_get(OUT)
output ||= previous_output.class.new(encoding: previous_output.encoding)
scope.local_variable_set(OUT, output)
begin
block.call(*arguments)
ensure
scope.local_variable_set(OUT, previous_output)
end
return output.to_str
end
def self.buffer(binding)
Signature
-
returns
Object
the buffer used for capturing output.
Implementation
def self.buffer(binding)
binding.local_variable_get(OUT)
end
def self.load_file(path, **options)
Load a template from a file.
Implementation
def self.load_file(path, **options)
self.new(FileBuffer.new(path), **options).freeze
end
def self.load(string, *arguments, **options)
Load a template from a string.
Implementation
def self.load(string, *arguments, **options)
self.new(Buffer.new(string), **options).freeze
end
def initialize(buffer, binding: BINDING)
Initialize a new template.
Signature
-
parameter
buffer
Buffer
The buffer containing the template.
-
parameter
binding
Binding
The binding in which the template is compiled. e.g.
TOPLEVEL_BINDING
.
Implementation
def initialize(buffer, binding: BINDING)
@buffer = buffer
@binding = binding
@compiled = nil
end
def code
The compiled code for the template.
Signature
-
returns
String
the compiled Ruby code.
Implementation
def code
@code ||= compile!
end
def compiled(scope = @binding.dup)
The compiled template as a proc.
Signature
-
parameter
scope
Object
The scope in which the template will be compiled.
-
returns
Proc
a proc that can be called with an output object.
Implementation
def compiled(scope = @binding.dup)
@compiled ||= eval("\# frozen_string_literal: true\nproc{|#{OUT}|;#{code}}", scope, @buffer.path, 0).freeze
end
def to_string(scope = Object.new, output = nil)
Renders the template to a string.
Signature
-
parameter
scope
Object
The scope in which the template will be evaluated.
-
parameter
output
String | Nil
The output string to append to.
Implementation
def to_string(scope = Object.new, output = nil)
builder = Builder.new(output, encoding: code.encoding)
scope.instance_exec(builder, &compiled)
return builder.output
end
def to_buffer(scope)
Renders the template to a buffer.
Implementation
def to_buffer(scope)
Buffer.new(to_string(scope), path: @buffer.path)
end
def to_proc(scope = @binding.dup)
Convert the template to a proc that can be called with an output object. The proc renders the template using to_string
and writes the output to the given output object. The output should implement <<
and close_write(error = nil)
methods.
Signature
-
parameter
scope
Object
The scope in which the template will be evaluated.
-
returns
Proc
a proc that can be called with an output object.
Implementation
def to_proc(scope = @binding.dup)
proc do |output|
to_string(scope, output)
rescue Exception => error
# I find this a bit ugly but we only use this code path on errors, so it's not performance critical.
if output.method(:close_write).arity != 0
# Inform the output that an error occured and the output was not generated correctly.
output.close_write(error)
output = nil
end
raise
ensure
output&.close_write
end
end