XRBSourceXRBTemplate

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
	
	@code = nil
	@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