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:
parent
714c540e4b
commit
7fd2f6b25b
|
@ -24,77 +24,68 @@ module Zero
|
|||
# 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 simple renderer with a mapping from html to text/html
|
||||
# Renderer.new('app/templates', {'html' => 'text/html'})
|
||||
#
|
||||
# @example create a renderer with a small map
|
||||
# Renderer.new('app', {
|
||||
# 'html' => ['text/html', 'application/html+xml'],
|
||||
# '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 type_map [Hash] a map of simple types to complex ones
|
||||
def initialize(template_path, type_map = {})
|
||||
@template_path = template_path
|
||||
@type_map = type_map
|
||||
# @param path [String] the relative path to templates
|
||||
# @param layout [String] the key of the layouts
|
||||
# @param types [Hash{String => Array}] a map of short type names to long ones
|
||||
def initialize(path, layout = 'layout', types)
|
||||
@path = path
|
||||
@layout = layout
|
||||
@types = types
|
||||
end
|
||||
|
||||
# returns the hash of type conversions
|
||||
# @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
|
||||
# @return [String] the base template path
|
||||
attr_reader :template_path
|
||||
attr_reader :path
|
||||
# get the tree of templates
|
||||
#
|
||||
# This function returns all templates with their keys.
|
||||
# @api private
|
||||
# @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.
|
||||
# @return [Self] returns the object
|
||||
def read_template_path!
|
||||
@templates = TemplateFinder.new(template_path, @type_map).get_templates
|
||||
def templates
|
||||
@templates ||= TemplateFinder.new(path, types)
|
||||
end
|
||||
|
||||
# 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)
|
||||
# This method will render the template according to the requested types.
|
||||
# @param template [String] the template to render
|
||||
# @param types [Array<String>] a list of types requested to render
|
||||
# @param context [Object] any object to use for rendering
|
||||
# @return [String] the result of rendering
|
||||
def render(template, types, context)
|
||||
unless templates.exist_for_types?(layout, types)
|
||||
return load_template(template, types).render(context)
|
||||
end
|
||||
load_layout_template(types).render(context) do
|
||||
load_template(template, types).render(context)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# get the prepared template for the name and type
|
||||
# @api private
|
||||
# @param name [String] the name of the template
|
||||
# @param types [Array] the types for the template
|
||||
# @return [Tilt::Template] a prepared tilt template
|
||||
def template(name, 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}'!"
|
||||
def load_template(template, types)
|
||||
templates.get(template, types)
|
||||
end
|
||||
|
||||
def load_layout_template(types)
|
||||
templates.get(layout, types)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
special layout loaded
|
||||
|
||||
<%= yield %>
|
|
@ -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
|
|
@ -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
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
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(:type_map) {{
|
||||
'html' => ['text/html', 'text/xml', '*/*'],
|
||||
|
@ -12,43 +12,54 @@ describe Zero::Renderer, '#render' do
|
|||
let(:foo_types) { ['foo/bar', 'bar/foo'] }
|
||||
let(:binding) { SpecTemplateContext.new('foo') }
|
||||
|
||||
before :each do
|
||||
subject.read_template_path!
|
||||
context 'with default layout' do
|
||||
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
|
||||
|
||||
it 'returns a tilt template' do
|
||||
subject.render('index', html_types, binding).should be_kind_of(String)
|
||||
end
|
||||
context 'with special layout' do
|
||||
subject { described_class.new(template_path, layout, type_map) }
|
||||
let(:layout) { 'special_layout' }
|
||||
|
||||
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, "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 'uses the layout for rendering' do
|
||||
expect(subject.render('index', html_types, binding)
|
||||
).to match(/layout loaded/)
|
||||
end
|
||||
|
||||
it 'renders the template into the layout' do
|
||||
expect(subject.render('index', html_types, binding)
|
||||
).to match(/success/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue