0
0
Fork 0

reworked the renderer

The renderer is now a bit smaller and asks the TemplateFinder for the
actual resources. That way it can just concentrate on rendering instead
of finding out, which stuff actually exists and which not.
This commit is contained in:
Gibheer 2013-02-27 22:27:02 +01:00
parent 714c540e4b
commit 7fd2f6b25b
8 changed files with 111 additions and 119 deletions

View File

@ -24,77 +24,68 @@ module Zero
# This type map is used to extend the possible renderings for different # This type map is used to extend the possible renderings for different
# types, which the clients sends. # types, which the clients sends.
# #
# @example create a simple renderer # @example create a simple renderer with a mapping from html to text/html
# Renderer.new('app/templates') # Renderer.new('app/templates', {'html' => 'text/html'})
# #
# @example create a renderer with a small map # @example create a renderer with a small map
# Renderer.new('app', { # Renderer.new('app', {
# 'html' => ['text/html', 'application/html+xml'], # 'html' => ['text/html', 'application/html+xml'],
# 'json' => ['application/json', 'application/aweomse+json'] # 'json' => ['application/json', 'application/aweomse+json']
# }) # })
# @example create a renderer with a specific layout
# Renderer.new('app'. 'layouts/layout', {'html' => 'text/html'})
# #
# @param template_path [String] a string to templates # @param path [String] the relative path to templates
# @param type_map [Hash] a map of simple types to complex ones # @param layout [String] the key of the layouts
def initialize(template_path, type_map = {}) # @param types [Hash{String => Array}] a map of short type names to long ones
@template_path = template_path def initialize(path, layout = 'layout', types)
@type_map = type_map @path = path
@layout = layout
@types = types
end end
# returns the hash of type conversions # returns the hash of type conversions
# @return [Hash] type conversion # @return [Hash] type conversion
attr_reader :type_map attr_reader :types
# returns the key for layout files
# @return [String] the key for layouts
attr_reader :layout
# get the path to the templates # get the path to the templates
# @return [String] the base template path # @return [String] the base template path
attr_reader :template_path attr_reader :path
# get the tree of templates # get the tree of templates
#
# This function returns all templates with their keys.
# @api private # @api private
# @return [Hash] the template tree # @return [Hash] the template tree
attr_reader :templates def templates
@templates ||= TemplateFinder.new(path, types)
# 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.
# @return [Self] returns the object
def read_template_path!
@templates = TemplateFinder.new(template_path, @type_map).get_templates
end end
# render a template # render a template
# #
# This method will render the given template, based on the type in the given # This method will render the template according to the requested types.
# context. # @param template [String] the template to render
# @param name [String] the name of the template # @param types [Array<String>] a list of types requested to render
# @param type [Array] a list of accept types used to find the template # @param context [Object] any object to use for rendering
# @param context [Object] the context in which to evaluate the template # @return [String] the result of rendering
# @return [String] the rendered content def render(template, types, context)
def render(name, type, context) unless templates.exist_for_types?(layout, types)
template(name, type).render(context) return load_template(template, types).render(context)
end
load_layout_template(types).render(context) do
load_template(template, types).render(context)
end
end end
private private
# get the prepared template for the name and type def load_template(template, types)
# @api private templates.get(template, types)
# @param name [String] the name of the template end
# @param types [Array] the types for the template
# @return [Tilt::Template] a prepared tilt template def load_layout_template(types)
def template(name, types) templates.get(layout, types)
if templates.has_key? name
types.each do |type|
template = templates[name][type]
unless template.nil?
# TODO Will be implemented later
# return template if template.kind_of?(Tilt::Template)
return Tilt.new(template)
end
end
raise ArgumentError.new(
"No template found for any of this types #{types.join ', '}!"
)
end
raise ArgumentError.new "No template found for '#{name}'!"
end end
end end
end end

View File

@ -0,0 +1,3 @@
special layout loaded
<%= yield %>

View File

@ -0,0 +1,11 @@
require 'spec_helper'
describe Zero::Renderer, '#initialize' do
subject { described_class.new(template_path, type_map) }
let(:template_path) { 'foo/' }
let(:type_map) { {'html' => ['text/html'] } }
its(:path) { should be(template_path) }
its(:layout) { should match(/layout/) }
its(:types) { should be(type_map) }
end

View File

@ -1,16 +0,0 @@
require 'spec_helper'
describe Zero::Renderer, '#read_template_path!' do
subject { Zero::Renderer.new(template_path, type_map) }
let(:template_path) { 'spec/fixtures/templates/' }
let(:type_map) { {'html' => ['text/html']} }
let(:result) { {
'text/html' => template_path + 'index.html.erb',
'json' => template_path + 'index.json.erb'
} }
it "loads the templates" do
subject.read_template_path!
expect(subject.templates['index']).to eq(result)
end
end

View File

@ -1,7 +1,7 @@
require 'spec_helper' require 'spec_helper'
describe Zero::Renderer, '#render' do describe Zero::Renderer, '#render' do
subject { Zero::Renderer.new(template_path, type_map) } subject { described_class.new(template_path, type_map) }
let(:template_path) { 'spec/fixtures/templates/' } let(:template_path) { 'spec/fixtures/templates/' }
let(:type_map) {{ let(:type_map) {{
'html' => ['text/html', 'text/xml', '*/*'], 'html' => ['text/html', 'text/xml', '*/*'],
@ -12,43 +12,54 @@ describe Zero::Renderer, '#render' do
let(:foo_types) { ['foo/bar', 'bar/foo'] } let(:foo_types) { ['foo/bar', 'bar/foo'] }
let(:binding) { SpecTemplateContext.new('foo') } let(:binding) { SpecTemplateContext.new('foo') }
before :each do context 'with default layout' do
subject.read_template_path! it 'returns a tilt template' do
subject.render('index', html_types, binding).should be_kind_of(String)
end
it 'renders html content' do
subject.render('index', html_types, binding).should match('success')
end
it 'returns a tilt template for different types' do
subject.render('index', json_types, binding).should be_kind_of(String)
end
it 'renders json content' do
subject.render('index', json_types, binding).should match("{text: 'success'}")
end
it 'returns an ArgumentError, if given template does not exist' do
expect {
subject.render('foobar', html_types, binding)
}.to raise_error(ArgumentError, /Template 'foobar' does not exist/)
end
it 'returns an ArgumentError, if no template fits types' do
expect {
subject.render('index', foo_types, binding)
}.to raise_error(
ArgumentError, /Template 'index' not found/)
end
it 'uses the context' do
subject.render('context', html_types, binding).should match('foo')
end
end end
it 'returns a tilt template' do context 'with special layout' do
subject.render('index', html_types, binding).should be_kind_of(String) subject { described_class.new(template_path, layout, type_map) }
end let(:layout) { 'special_layout' }
it 'renders html content' do it 'uses the layout for rendering' do
subject.render('index', html_types, binding).should match('success') expect(subject.render('index', html_types, binding)
end ).to match(/layout loaded/)
end
it 'returns a tilt template for different types' do
subject.render('index', json_types, binding).should be_kind_of(String)
end
it 'renders json content' do
subject.render('index', json_types, binding).should match("{text: 'success'}")
end
it 'returns an ArgumentError, if given template does not exist' do
expect {
subject.render('foobar', html_types, binding)
}.to raise_error(ArgumentError, "No template found for 'foobar'!")
end
it 'returns an ArgumentError, if no template fits types' do
expect {
subject.render('index', foo_types, binding)
}.to raise_error(
ArgumentError,
"No template found for any of this types #{foo_types.join ', '}!"
)
end
it 'uses the context' do
subject.render('context', html_types, binding).should match('foo')
it 'renders the template into the layout' do
expect(subject.render('index', html_types, binding)
).to match(/success/)
end
end end
end end

View File

@ -1,8 +0,0 @@
require 'spec_helper'
describe Zero::Renderer, '#template_path' do
subject { Zero::Renderer.new(template_path) }
let(:template_path) { 'foo' }
its(:type_map) { should be(template_path) }
end

View File

@ -0,0 +1,13 @@
require 'spec_helper'
describe Zero::Renderer, '#templates' do
let(:object) { described_class.new(template_path, types) }
subject { object.templates }
let(:template_path) { 'spec/fixtures/templates/' }
let(:types) { {'html' => ['text/html']} }
it 'loads the template tree' do
expect(subject).to be_kind_of(Zero::Renderer::TemplateFinder)
end
end

View File

@ -1,13 +0,0 @@
require 'spec_helper'
describe Zero::Renderer, '#type_map' do
subject { Zero::Renderer.new(template_path, type_map) }
let(:template_path) { 'foo' }
let(:type_map) { {'html' => ['text/html']} }
its(:type_map) { should be(type_map) }
it 'returns an empty Hash, if type_map is not set while initialization' do
Zero::Renderer.new(template_path).type_map.should eq({})
end
end