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.



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

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

Instance Attribute Details

#lazy_mapObject (readonly)



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

def lazy_map
  @lazy_map
end

#template_mapObject (readonly)



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

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)


152
153
154
155
# File 'lib/tilt/mapping.rb', line 152

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)


183
184
185
186
187
188
189
190
191
192
# File 'lib/tilt/mapping.rb', line 183

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
end

#initialize_copy(other) ⇒ Object



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

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


136
137
138
139
140
141
142
# File 'lib/tilt/mapping.rb', line 136

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.



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

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.



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

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

#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)


123
124
125
# File 'lib/tilt/mapping.rb', line 123

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>)


168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/tilt/mapping.rb', line 168

def templates_for(file)
  templates = []

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

  templates
end