Class: Tilt::Mapping

Inherits:
Object
  • Object
show all
Defined in:
lib/tilt/mapping.rb

Overview

Tilt::Mapping associates file extensions with template implementations.

mapping = Tilt::Mapping.new
mapping.register(Tilt::RDocTemplate, 'rdoc')
mapping['index.rdoc'] # => Tilt::RDocTemplate
mapping.new('index.rdoc').render

You can use #register to register a template class by file extension, #registered? to see if a file extension is mapped, #[] to lookup template classes, and #new to instantiate template objects.

Mapping also supports lazy template implementations. Note that regularly registered template implementations always have preference over lazily registered template implementations. You should use #register if you depend on a specific template implementation and #register_lazy if there are multiple alternatives.

mapping = Tilt::Mapping.new
mapping.register_lazy('RDiscount::Template', 'rdiscount/template', 'md')
mapping['index.md']
# => RDiscount::Template

#register_lazy takes a class name, a filename, and a list of file extensions. When you try to lookup a template name that matches the file extension, Tilt will automatically try to require the filename and constantize the class name.

Unlike #register, there can be multiple template implementations registered lazily to the same file extension. Tilt will attempt to load the template implementations in order (registered last would be tried first), returning the first which doesn’t raise LoadError.

If all of the registered template implementations fails, Tilt will raise the exception of the first, since that was the most preferred one.

mapping = Tilt::Mapping.new
mapping.register_lazy('Bluecloth::Template', 'bluecloth/template', 'md')
mapping.register_lazy('RDiscount::Template', 'rdiscount/template', 'md')
mapping['index.md']
# => RDiscount::Template

In the previous example we say that RDiscount has a *higher priority* than BlueCloth. Tilt will first try to ‘require “rdiscount/template”`, falling back to `require “bluecloth/template”`. If none of these are successful, the first error will be raised.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMapping

Returns a new instance of Mapping.



55
56
57
58
# File 'lib/tilt/mapping.rb', line 55

def initialize
  @template_map = Hash.new
  @lazy_map = Hash.new { |h, k| h[k] = [] }
end

Instance Attribute Details

#lazy_mapObject (readonly)



53
54
55
# File 'lib/tilt/mapping.rb', line 53

def lazy_map
  @lazy_map
end

#template_mapObject (readonly)



53
54
55
# File 'lib/tilt/mapping.rb', line 53

def template_map
  @template_map
end

Instance Method Details

#[](file) ⇒ template class Also known as: template_for

Looks up a template class based on file name and/or extension.

Examples:

mapping['views/hello.erb'] # => Tilt::ERBTemplate
mapping['hello.erb']       # => Tilt::ERBTemplate
mapping['erb']             # => Tilt::ERBTemplate

Returns:

  • (template class)


209
210
211
212
# File 'lib/tilt/mapping.rb', line 209

def [](file)
  _, ext = split(file)
  ext && lookup(ext)
end

#extensions_for(template_class) ⇒ Object

Finds the extensions the template class has been registered under.

Parameters:

  • template_class (template class)


240
241
242
243
244
245
246
247
248
249
# File 'lib/tilt/mapping.rb', line 240

def extensions_for(template_class)
  res = []
  template_map.each do |ext, klass|
    res << ext if template_class == klass
  end
  lazy_map.each do |ext, choices|
    res << ext if choices.any? { |klass, file| template_class.to_s == klass }
  end
  res.uniq
end

#initialize_copy(other) ⇒ Object



61
62
63
64
# File 'lib/tilt/mapping.rb', line 61

def initialize_copy(other)
  @template_map = other.template_map.dup
  @lazy_map = other.lazy_map.dup
end

#new(file, line = nil, options = {}, &block) ⇒ Object

Instantiates a new template class based on the file.

Examples:

mapping.new('index.mt') # => instance of MyEngine::Template

Raises:

  • (RuntimeError)

    if there is no template class registered for the file name.

See Also:

  • Template.new


193
194
195
196
197
198
199
# File 'lib/tilt/mapping.rb', line 193

def new(file, line=nil, options={}, &block)
  if template_class = self[file]
    template_class.new(file, line, options, &block)
  else
    fail "No template engine registered for #{File.basename(file)}"
  end
end

#register(template_class, *extensions) ⇒ void

This method returns an undefined value.

Registers a template implementation by file extension. There can only be one template implementation per file extension, and this method will override any existing mapping.

Examples:

mapping.register MyEngine::Template, 'mt'
mapping['index.mt'] # => MyEngine::Template

Parameters:

  • template_class
  • extensions (Array<String>)

    List of extensions.



105
106
107
108
109
110
111
112
113
114
# File 'lib/tilt/mapping.rb', line 105

def register(template_class, *extensions)
  if template_class.respond_to?(:to_str)
    # Support register(ext, template_class) too
    extensions, template_class = [template_class], extensions[0]
  end

  extensions.each do |ext|
    @template_map[ext.to_s] = template_class
  end
end

#register_lazy(class_name, file, *extensions) ⇒ void

This method returns an undefined value.

Registers a lazy template implementation by file extension. You can have multiple lazy template implementations defined on the same file extension, in which case the template implementation defined last will be attempted loaded first.

Examples:

mapping.register_lazy 'MyEngine::Template', 'my_engine/template',  'mt'

defined?(MyEngine::Template) # => false
mapping['index.mt'] # => MyEngine::Template
defined?(MyEngine::Template) # => true

Parameters:

  • class_name (String)

    Class name of a template class.

  • file (String)

    Filename where the template class is defined.

  • extensions (Array<String>)

    List of extensions.



82
83
84
85
86
87
88
89
90
91
92
# File 'lib/tilt/mapping.rb', line 82

def register_lazy(class_name, file, *extensions)
  # Internal API
  if class_name.is_a?(Symbol)
    Tilt.autoload class_name, file
    class_name = "Tilt::#{class_name}"
  end

  extensions.each do |ext|
    @lazy_map[ext].unshift([class_name, file])
  end
end

#register_pipeline(ext, options = {}) ⇒ void

This method returns an undefined value.

Register a new template class using the given extension that represents a pipeline of multiple existing template, where the output from the previous template is used as input to the next template.

This will register a template class that processes the input with the erb template processor, and takes the output of that and feeds it to the scss template processor, returning the output of the scss template processor as the result of the pipeline.

Examples:

mapping.register_pipeline('scss.erb')
mapping.register_pipeline('scss.erb', 'erb'=>{:outvar=>'@foo'})
mapping.register_pipeline('scsserb', :extra_exts => 'scss.erb',
                          :templates=>['erb', 'scss'])

Parameters:

  • ext (String)

    Primary extension to register

  • :templates (Hash)

    a customizable set of options

  • :extra_exts (Hash)

    a customizable set of options

  • String (Hash)

    a customizable set of options



140
141
142
143
144
145
146
147
148
149
# File 'lib/tilt/mapping.rb', line 140

def register_pipeline(ext, options={})
  templates = options[:templates] || ext.split('.').reverse
  templates = templates.map{|t| [self[t], options[t] || {}]}

  klass = Class.new(Pipeline)
  klass.send(:const_set, :TEMPLATES, templates)

  register(klass, ext, *Array(options[:extra_exts]))
  klass
end

#registered?(ext) ⇒ Boolean

Checks if a file extension is registered (either eagerly or lazily) in this mapping.

Examples:

mapping.registered?('erb')  # => true
mapping.registered?('nope') # => false

Parameters:

  • ext (String)

    File extension.

Returns:

  • (Boolean)


180
181
182
# File 'lib/tilt/mapping.rb', line 180

def registered?(ext)
  @template_map.has_key?(ext.downcase) or lazy?(ext)
end

#templates_for(file) ⇒ Array<template class>

Looks up a list of template classes based on file name. If the file name has multiple extensions, it will return all template classes matching the extensions from the end.

Examples:

mapping.templates_for('views/index.haml.erb')
# => [Tilt::ERBTemplate, Tilt::HamlTemplate]

Returns:

  • (Array<template class>)


225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/tilt/mapping.rb', line 225

def templates_for(file)
  templates = []

  while true
    prefix, ext = split(file)
    break unless ext
    templates << lookup(ext)
    file = prefix
  end

  templates
end

#unregister(*extensions) ⇒ Object

Unregisters an extension. This removes the both normal registrations and lazy registrations.

Examples:

mapping.register MyEngine::Template, 'mt'
mapping['index.mt'] # => MyEngine::Template
mapping.unregister('mt')
mapping['index.mt'] # => nil

Parameters:

  • extensions (Array<String>)

    List of extensions.

Returns:

  • nil



162
163
164
165
166
167
168
169
170
# File 'lib/tilt/mapping.rb', line 162

def unregister(*extensions)
  extensions.each do |ext|
    ext = ext.to_s
    @template_map.delete(ext)
    @lazy_map.delete(ext)
  end

  nil
end