From 7fd2f6b25b2abd48a7292f7598e53ebd357e24f7 Mon Sep 17 00:00:00 2001 From: Gibheer Date: Wed, 27 Feb 2013 22:27:02 +0100 Subject: [PATCH] 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. --- lib/zero/renderer.rb | 85 +++++++++---------- .../templates/special_layout.html.erb | 3 + spec/unit/zero/renderer/initialize_spec.rb | 11 +++ .../renderer/read_template_path_bang_spec.rb | 16 ---- spec/unit/zero/renderer/render_spec.rb | 81 ++++++++++-------- spec/unit/zero/renderer/template_path.rb | 8 -- spec/unit/zero/renderer/templates_spec.rb | 13 +++ spec/unit/zero/renderer/type_map_spec.rb | 13 --- 8 files changed, 111 insertions(+), 119 deletions(-) create mode 100644 spec/fixtures/templates/special_layout.html.erb create mode 100644 spec/unit/zero/renderer/initialize_spec.rb delete mode 100644 spec/unit/zero/renderer/read_template_path_bang_spec.rb delete mode 100644 spec/unit/zero/renderer/template_path.rb create mode 100644 spec/unit/zero/renderer/templates_spec.rb delete mode 100644 spec/unit/zero/renderer/type_map_spec.rb diff --git a/lib/zero/renderer.rb b/lib/zero/renderer.rb index 2a848c2..f1930ea 100644 --- a/lib/zero/renderer.rb +++ b/lib/zero/renderer.rb @@ -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] 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 diff --git a/spec/fixtures/templates/special_layout.html.erb b/spec/fixtures/templates/special_layout.html.erb new file mode 100644 index 0000000..4288509 --- /dev/null +++ b/spec/fixtures/templates/special_layout.html.erb @@ -0,0 +1,3 @@ +special layout loaded + +<%= yield %> diff --git a/spec/unit/zero/renderer/initialize_spec.rb b/spec/unit/zero/renderer/initialize_spec.rb new file mode 100644 index 0000000..39d7302 --- /dev/null +++ b/spec/unit/zero/renderer/initialize_spec.rb @@ -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 diff --git a/spec/unit/zero/renderer/read_template_path_bang_spec.rb b/spec/unit/zero/renderer/read_template_path_bang_spec.rb deleted file mode 100644 index 9a2f875..0000000 --- a/spec/unit/zero/renderer/read_template_path_bang_spec.rb +++ /dev/null @@ -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 diff --git a/spec/unit/zero/renderer/render_spec.rb b/spec/unit/zero/renderer/render_spec.rb index 3270ac3..ed11857 100644 --- a/spec/unit/zero/renderer/render_spec.rb +++ b/spec/unit/zero/renderer/render_spec.rb @@ -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 diff --git a/spec/unit/zero/renderer/template_path.rb b/spec/unit/zero/renderer/template_path.rb deleted file mode 100644 index 261faa8..0000000 --- a/spec/unit/zero/renderer/template_path.rb +++ /dev/null @@ -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 diff --git a/spec/unit/zero/renderer/templates_spec.rb b/spec/unit/zero/renderer/templates_spec.rb new file mode 100644 index 0000000..f86961b --- /dev/null +++ b/spec/unit/zero/renderer/templates_spec.rb @@ -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 diff --git a/spec/unit/zero/renderer/type_map_spec.rb b/spec/unit/zero/renderer/type_map_spec.rb deleted file mode 100644 index 290e579..0000000 --- a/spec/unit/zero/renderer/type_map_spec.rb +++ /dev/null @@ -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