class Template

Base class for template implementations. Subclasses must implement the prepare method and one of the evaluate or precompiled_template methods.

Constants

CLASS_METHOD

Attributes

data[R]

Template source; loaded from a file or given directly.

file[R]

The name of the file where the template data was loaded from.

line[R]

The line number in file where template data was loaded from.

options[R]

A Hash of template engine specific options. This is passed directly to the underlying engine and is not used by the generic template interface.

Public Class Methods

default_mime_type() click to toggle source

@deprecated Use ‘.metadata` instead.

   # File lib/tilt/template.rb
44 def default_mime_type
45   metadata[:mime_type]
46 end
default_mime_type=(value) click to toggle source

@deprecated Use ‘.metadata = val` instead.

   # File lib/tilt/template.rb
49 def default_mime_type=(value)
50   metadata[:mime_type] = value
51 end
metadata() click to toggle source

An empty Hash that the template engine can populate with various metadata.

   # File lib/tilt/template.rb
39 def metadata
40   @metadata ||= {}
41 end
new(file=nil, line=1, options={}, &block) click to toggle source

Create a new template with the file, line, and options specified. By default, template data is read from the file. When a block is given, it should read template data and return as a String. When file is nil, a block is required.

All arguments are optional.

    # File lib/tilt/template.rb
 60 def initialize(file=nil, line=1, options={}, &block)
 61   @file, @line, @options = nil, 1, {}
 62 
 63   [options, line, file].compact.each do |arg|
 64     case
 65     when arg.respond_to?(:to_str)  ; @file = arg.to_str
 66     when arg.respond_to?(:to_int)  ; @line = arg.to_int
 67     when arg.respond_to?(:to_hash) ; @options = arg.to_hash.dup
 68     when arg.respond_to?(:path)    ; @file = arg.path
 69     when arg.respond_to?(:to_path) ; @file = arg.to_path
 70     else raise TypeError, "Can't load the template file. Pass a string with a path " +
 71       "or an object that responds to 'to_str', 'path' or 'to_path'"
 72     end
 73   end
 74 
 75   raise ArgumentError, "file or block required" if (@file || block).nil?
 76 
 77   # used to hold compiled template methods
 78   @compiled_method = {}
 79 
 80   # used on 1.9 to set the encoding if it is not set elsewhere (like a magic comment)
 81   # currently only used if template compiles to ruby
 82   @default_encoding = @options.delete :default_encoding
 83 
 84   # load template data and prepare (uses binread to avoid encoding issues)
 85   @reader = block || lambda { |t| read_template_file }
 86   @data = @reader.call(self)
 87 
 88   if @data.respond_to?(:force_encoding)
 89     if default_encoding
 90       @data = @data.dup if @data.frozen?
 91       @data.force_encoding(default_encoding)
 92     end
 93 
 94     if !@data.valid_encoding?
 95       raise Encoding::InvalidByteSequenceError, "#{eval_file} is not valid #{@data.encoding}"
 96     end
 97   end
 98 
 99   prepare
100 end

Public Instance Methods

basename(suffix='') click to toggle source

The basename of the template file.

    # File lib/tilt/template.rb
115 def basename(suffix='')
116   File.basename(file, suffix) if file
117 end
eval_file() click to toggle source

The filename used in backtraces to describe the template.

    # File lib/tilt/template.rb
125 def eval_file
126   file || '(__TEMPLATE__)'
127 end
metadata() click to toggle source

An empty Hash that the template engine can populate with various metadata.

    # File lib/tilt/template.rb
131 def metadata
132   if respond_to?(:allows_script?)
133     self.class.metadata.merge(:allows_script => allows_script?)
134   else
135     self.class.metadata
136   end
137 end
name() click to toggle source

The template file’s basename with all extensions chomped off.

    # File lib/tilt/template.rb
120 def name
121   basename.split('.', 2).first if basename
122 end
render(scope=nil, locals={}, &block) click to toggle source

Render the template in the given scope with the locals specified. If a block is given, it is typically available within the template via yield.

    # File lib/tilt/template.rb
105 def render(scope=nil, locals={}, &block)
106   scope ||= Object.new
107   current_template = Thread.current[:tilt_current_template]
108   Thread.current[:tilt_current_template] = self
109   evaluate(scope, locals || {}, &block)
110 ensure
111   Thread.current[:tilt_current_template] = current_template
112 end

Protected Instance Methods

default_encoding() click to toggle source

The encoding of the source data. Defaults to the default_encoding-option if present. You may override this method in your template class if you have a better hint of the data’s encoding.

    # File lib/tilt/template.rb
147 def default_encoding
148   @default_encoding
149 end
evaluate(scope, locals, &block) click to toggle source

Execute the compiled template and return the result string. Template evaluation is guaranteed to be performed in the scope object with the locals specified and with support for yielding to the block.

This method is only used by source generating templates. Subclasses that override render() may not support all features.

    # File lib/tilt/template.rb
168 def evaluate(scope, locals, &block)
169   locals_keys = locals.keys
170   locals_keys.sort!{|x, y| x.to_s <=> y.to_s}
171   case scope
172   when Object
173     method = compiled_method(locals_keys, Module === scope ? scope : scope.class)
174   else
175     if RUBY_VERSION >= '2'
176       method = compiled_method(locals_keys, CLASS_METHOD.bind(scope).call)
177     else
178       method = compiled_method(locals_keys, Object)
179     end
180   end
181   method.bind(scope).call(locals, &block)
182 end
precompiled(local_keys) click to toggle source

Generates all template source by combining the preamble, template, and postamble and returns a two-tuple of the form: [source, offset], where source is the string containing (Ruby) source code for the template and offset is the integer line offset where line reporting should begin.

Template subclasses may override this method when they need complete control over source generation or want to adjust the default line offset. In most cases, overriding the precompiled_template method is easier and more appropriate.

    # File lib/tilt/template.rb
193 def precompiled(local_keys)
194   preamble = precompiled_preamble(local_keys)
195   template = precompiled_template(local_keys)
196   postamble = precompiled_postamble(local_keys)
197   source = String.new
198 
199   # Ensure that our generated source code has the same encoding as the
200   # the source code generated by the template engine.
201   if source.respond_to?(:force_encoding)
202     template_encoding = extract_encoding(template)
203 
204     source.force_encoding(template_encoding)
205     template.force_encoding(template_encoding)
206   end
207 
208   source << preamble << "\n" << template << "\n" << postamble
209 
210   [source, preamble.count("\n")+1]
211 end
precompiled_postamble(local_keys) click to toggle source
    # File lib/tilt/template.rb
227 def precompiled_postamble(local_keys)
228   ''
229 end
precompiled_preamble(local_keys) click to toggle source
    # File lib/tilt/template.rb
223 def precompiled_preamble(local_keys)
224   ''
225 end
precompiled_template(local_keys) click to toggle source

A string containing the (Ruby) source code for the template. The default Template#evaluate implementation requires either this method or the precompiled method be overridden. When defined, the base Template guarantees correct file/line handling, locals support, custom scopes, proper encoding, and support for template compilation.

    # File lib/tilt/template.rb
219 def precompiled_template(local_keys)
220   raise NotImplementedError
221 end
prepare() click to toggle source

Do whatever preparation is necessary to setup the underlying template engine. Called immediately after template data is loaded. Instance variables set in this method are available when evaluate is called.

Subclasses must provide an implementation of this method.

    # File lib/tilt/template.rb
156 def prepare
157   raise NotImplementedError
158 end

Private Instance Methods

binary(string) { || ... } click to toggle source
    # File lib/tilt/template.rb
300 def binary(string)
301   original_encoding = string.encoding
302   string.force_encoding(Encoding::BINARY)
303   yield
304 ensure
305   string.force_encoding(original_encoding)
306 end
compile_template_method(local_keys, scope_class=nil) click to toggle source
    # File lib/tilt/template.rb
261     def compile_template_method(local_keys, scope_class=nil)
262       source, offset = precompiled(local_keys)
263       local_code = local_extraction(local_keys)
264 
265       method_name = "__tilt_#{Thread.current.object_id.abs}"
266       method_source = String.new
267 
268       if method_source.respond_to?(:force_encoding)
269         method_source.force_encoding(source.encoding)
270       end
271 
272       method_source << <<-RUBY
273         TOPOBJECT.class_eval do
274           def #{method_name}(locals)
275             #{local_code}
276       RUBY
277       offset += method_source.count("\n")
278       method_source << source
279       method_source << "\nend;end;"
280       (scope_class || Object).class_eval(method_source, eval_file, line - offset)
281       unbind_compiled_method(method_name)
282     end
compiled_method(locals_keys, scope_class=nil) click to toggle source

The compiled method for the locals keys provided.

    # File lib/tilt/template.rb
245 def compiled_method(locals_keys, scope_class=nil)
246   LOCK.synchronize do
247     @compiled_method[[scope_class, locals_keys]] ||= compile_template_method(locals_keys, scope_class)
248   end
249 end
extract_encoding(script) click to toggle source
    # File lib/tilt/template.rb
290 def extract_encoding(script)
291   extract_magic_comment(script) || script.encoding
292 end
extract_magic_comment(script) click to toggle source
    # File lib/tilt/template.rb
294 def extract_magic_comment(script)
295   binary(script) do
296     script[/\A[ \t]*\#.*coding\s*[=:]\s*([[:alnum:]\-_]+).*$/n, 1]
297   end
298 end
local_extraction(local_keys) click to toggle source
    # File lib/tilt/template.rb
251 def local_extraction(local_keys)
252   local_keys.map do |k|
253     if k.to_s =~ /\A[a-z_][a-zA-Z_0-9]*\z/
254       "#{k} = locals[#{k.inspect}]"
255     else
256       raise "invalid locals key: #{k.inspect} (keys must be variable names)"
257     end
258   end.join("\n")
259 end
read_template_file() click to toggle source

!@endgroup

    # File lib/tilt/template.rb
235 def read_template_file
236   data = File.open(file, 'rb') { |io| io.read }
237   if data.respond_to?(:force_encoding)
238     # Set it to the default external (without verifying)
239     data.force_encoding(Encoding.default_external) if Encoding.default_external
240   end
241   data
242 end
unbind_compiled_method(method_name) click to toggle source
    # File lib/tilt/template.rb
284 def unbind_compiled_method(method_name)
285   method = TOPOBJECT.instance_method(method_name)
286   TOPOBJECT.class_eval { remove_method(method_name) }
287   method
288 end