Class: Tilt::Mapping

Inherits:
BaseMapping
  • 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, BaseMapping#[] to lookup template classes, and BaseMapping#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('Maruku::Template', 'maruku/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 Maruku. Tilt will first try to ‘require “rdiscount/template”`, falling back to `require “maruku/template”`. If none of these are successful, the first error will be raised.

Constant Summary collapse

LOCK =
Mutex.new

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMapping

Returns a new instance of Mapping.



131
132
133
134
# File 'lib/tilt/mapping.rb', line 131

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

Instance Attribute Details

#lazy_mapObject (readonly)



129
130
131
# File 'lib/tilt/mapping.rb', line 129

def lazy_map
  @lazy_map
end

#template_mapObject (readonly)



129
130
131
# File 'lib/tilt/mapping.rb', line 129

def template_map
  @template_map
end

Instance Method Details

#extensions_for(template_class) ⇒ Object

Finds the extensions the template class has been registered under.

Parameters:

  • template_class (template class)


287
288
289
290
291
292
293
294
295
296
297
# File 'lib/tilt/mapping.rb', line 287

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

#finalizedObject

Return a finalized mapping. A finalized mapping will only include support for template libraries already loaded, and will not allow registering new template libraries or lazy loading template libraries not yet loaded. Finalized mappings improve performance by not requiring synchronization and ensure that the mapping will not attempt to load additional files (useful when restricting file system access after template libraries in use are loaded).



151
152
153
154
155
156
157
158
# File 'lib/tilt/mapping.rb', line 151

def finalized
  LOCK.synchronize{@lazy_map.dup}.each do |pattern, classes|
    register_defined_classes(LOCK.synchronize{classes.map(&:first)}, pattern)
  end

  # Check if a template class is already present
  FinalizedMapping.new(LOCK.synchronize{@template_map.dup}.freeze)
end

#initialize_copy(other) ⇒ Object



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

def initialize_copy(other)
  LOCK.synchronize do
    @template_map = other.template_map.dup
    @lazy_map = other.lazy_map.dup
  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.



200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/tilt/mapping.rb', line 200

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|
    ext = ext.to_s
    LOCK.synchronize do
      @template_map[ext] = template_class
    end
  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.



176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/tilt/mapping.rb', line 176

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

  v = [class_name, file].freeze
  extensions.each do |ext|
    LOCK.synchronize{@lazy_map[ext].unshift(v)}
  end
end

#register_pipeline(ext, options = EMPTY_HASH) ⇒ 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



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

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

  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)


280
281
282
283
# File 'lib/tilt/mapping.rb', line 280

def registered?(ext)
  ext_downcase = ext.downcase
  LOCK.synchronize{@template_map.has_key?(ext_downcase)} or lazy?(ext)
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



260
261
262
263
264
265
266
267
268
269
270
# File 'lib/tilt/mapping.rb', line 260

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

  nil
end