2012-11-08 21:32:59 +01:00
|
|
|
module Zero
|
2012-11-22 07:32:17 +01:00
|
|
|
# the base renderer for getting render containers
|
2012-11-16 17:56:11 +01:00
|
|
|
#
|
2012-11-22 07:32:17 +01:00
|
|
|
# This class handles templates and render coontainers, which can be used for
|
|
|
|
# the actual rendering.
|
2012-11-16 17:56:11 +01:00
|
|
|
#
|
2012-11-22 07:32:17 +01:00
|
|
|
# To use this renderer you have to give it a template path and optionally
|
|
|
|
# a map of shorthand type descriptions to fully types. This will then be used
|
|
|
|
# to extend the internal map of templates to possible formats in a way, that
|
|
|
|
# you will be able to answer xhtml and html requests with the same template.
|
2012-11-16 17:56:11 +01:00
|
|
|
#
|
2012-11-22 07:32:17 +01:00
|
|
|
# When the object is initialized and you are sure, everything is loaded, call
|
|
|
|
# #read_template_path! and the template tree will be built. Without this step,
|
|
|
|
# you will probably don't get any output.
|
2012-11-16 17:56:11 +01:00
|
|
|
#
|
2012-11-22 07:32:17 +01:00
|
|
|
# After the setup, the renderer can be used to build render containers, which
|
|
|
|
# then can be used to actually render something.
|
2012-11-08 21:32:59 +01:00
|
|
|
class Renderer
|
2012-11-22 07:32:17 +01:00
|
|
|
# initializes a new Renderer
|
|
|
|
#
|
|
|
|
# This method takes a path to the base template directory and a type map.
|
|
|
|
# This type map is used to extend the possible renderings for different
|
|
|
|
# types, which the clients sends.
|
|
|
|
#
|
|
|
|
# @example create a simple renderer
|
|
|
|
# Renderer.new('app/templates')
|
|
|
|
#
|
|
|
|
# @example create a renderer with a small map
|
|
|
|
# Renderer.new('app', {
|
|
|
|
# 'html' => ['text/html', 'application/html+xml'],
|
|
|
|
# 'json' => ['application/json', 'application/aweomse+json']
|
|
|
|
# })
|
|
|
|
#
|
2012-11-26 08:51:51 +01:00
|
|
|
# @param template_path [String] a string to templates
|
|
|
|
# @param type_map [Hash] a map of simple types to complex ones
|
2012-11-22 07:32:17 +01:00
|
|
|
def initialize(template_path, type_map = {})
|
|
|
|
@template_path = template_path + '/'
|
|
|
|
@type_map = type_map
|
2012-11-16 17:56:11 +01:00
|
|
|
end
|
|
|
|
|
2012-11-22 07:32:17 +01:00
|
|
|
# returns the hash of type conversions
|
|
|
|
# @return [Hash] type conversion
|
|
|
|
attr_reader :type_map
|
|
|
|
# get the path to the templates
|
|
|
|
# @return [String] the base template path
|
|
|
|
attr_reader :template_path
|
|
|
|
# get the tree of templates
|
2012-11-16 17:56:11 +01:00
|
|
|
# @api private
|
2012-11-22 07:32:17 +01:00
|
|
|
# @return [Hash] the template tree
|
|
|
|
attr_reader :templates
|
|
|
|
|
|
|
|
# load the template tree
|
|
|
|
#
|
|
|
|
# This method gets all templates in the `template_path` and builds an
|
|
|
|
# internal tree structure, where templates and types direct the request to
|
|
|
|
# the wanted template.
|
2012-11-26 08:51:51 +01:00
|
|
|
# @return [Self] returns the object
|
2012-11-22 07:32:17 +01:00
|
|
|
def read_template_path!
|
2012-11-26 21:16:34 +01:00
|
|
|
# TODO clean up later
|
|
|
|
@templates = {}
|
|
|
|
search_files.each do |file|
|
|
|
|
parts = file.gsub(/#{template_path}/, '').split('.')
|
|
|
|
@templates[parts[0]] ||= {}
|
2012-11-29 21:11:31 +01:00
|
|
|
|
|
|
|
# Set default value
|
|
|
|
types = 'default'
|
|
|
|
# Overwrite default value, if it's set in template path
|
2012-11-26 21:16:34 +01:00
|
|
|
if parts.count > 2 then
|
2012-11-29 21:11:31 +01:00
|
|
|
types = parts[1]
|
|
|
|
end
|
|
|
|
|
|
|
|
read_type(types).each do |type|
|
|
|
|
@templates[parts[0]][type] = file
|
2012-11-26 21:16:34 +01:00
|
|
|
end
|
2012-11-08 21:32:59 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-11-26 20:11:39 +01:00
|
|
|
# render a template
|
|
|
|
#
|
|
|
|
# This method will render the given template, based on the type in the given
|
|
|
|
# context.
|
|
|
|
# @param name [String] the name of the template
|
|
|
|
# @param type [Array] a list of accept types used to find the template
|
|
|
|
# @param context [Object] the context in which to evaluate the template
|
|
|
|
# @return [String] the rendered content
|
|
|
|
def render(name, type, context)
|
|
|
|
template(name, type).render(context)
|
|
|
|
end
|
|
|
|
|
2012-11-22 07:32:17 +01:00
|
|
|
private
|
|
|
|
|
2012-11-26 08:51:51 +01:00
|
|
|
# search in `template_path` for templates beginning with `template_name`
|
|
|
|
# @api private
|
|
|
|
# @param template_name [String] the name of the template
|
|
|
|
# @return [#each] a list of all templates found
|
2012-11-26 21:16:34 +01:00
|
|
|
def search_files
|
|
|
|
Dir[template_path + '**/*.*']
|
2012-11-23 21:28:05 +01:00
|
|
|
end
|
|
|
|
|
2012-11-26 08:51:51 +01:00
|
|
|
# gets the type information from a file and converts it to an array of
|
|
|
|
# possible matching types
|
|
|
|
# @api private
|
|
|
|
# @param short_notation [String] a short notation of a type, like `html`
|
|
|
|
# @return [Array] a list of matching types, like `text/html`
|
2012-11-22 07:32:17 +01:00
|
|
|
def read_type(short_notation)
|
|
|
|
to_type_list(type_map[short_notation] || short_notation)
|
2012-11-16 17:56:11 +01:00
|
|
|
end
|
|
|
|
|
2012-11-26 08:51:51 +01:00
|
|
|
# convert a map to an array if it is not one
|
|
|
|
# @api private
|
|
|
|
# @param original_map [Object] the type(s) to convert
|
|
|
|
# @return [Array] a list of objects
|
2012-11-22 07:32:17 +01:00
|
|
|
def to_type_list(original_map)
|
|
|
|
return original_map if original_map.respond_to?(:each)
|
|
|
|
[original_map]
|
2012-11-08 21:32:59 +01:00
|
|
|
end
|
2012-11-26 20:11:39 +01:00
|
|
|
|
|
|
|
# get the prepared template for the name and type
|
|
|
|
# @api private
|
|
|
|
# @param name [String] the name of the template
|
2012-11-27 19:26:24 +01:00
|
|
|
# @param types [Array] the types for the template
|
2012-11-26 20:11:39 +01:00
|
|
|
# @return [Tilt::Template] a prepared tilt template
|
|
|
|
def template(name, types)
|
|
|
|
types.each do |type|
|
|
|
|
template = templates[name][type]
|
|
|
|
unless template.nil?
|
|
|
|
return template if template.kind_of?(Tilt::Template)
|
|
|
|
return Tilt.new(template)
|
|
|
|
end
|
|
|
|
end
|
2012-11-26 21:16:34 +01:00
|
|
|
raise ArgumentError.new "No template found for '#{name}'!"
|
2012-11-26 20:11:39 +01:00
|
|
|
end
|
2012-11-08 21:32:59 +01:00
|
|
|
end
|
|
|
|
end
|