# encoding: UTF-8 require File.expand_path('../../test_helper', __FILE__) require 'cgi' describe "Templates" do def first_pass(base_dir, filename, context=nil) render_with_renderer(Cutaneous::PublishRenderer, base_dir, filename, context) end def second_pass(base_dir, filename, context=nil) render_with_renderer(Cutaneous::RequestRenderer, base_dir, filename, context) end def render_with_renderer(renderer_class, base_dir, filename, context = nil) context ||= @context renderer = renderer_class.new(make_template_root(base_dir)) path = template_root / filename renderer.render(path, context) end def make_template_root(base_dir = "") @template_root = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/templates', base_dir)) @site.paths.add(:templates, @template_root) @template_root end before do @site = setup_site make_template_root @klass = Class.new(Spontaneous::Output.context_class) do include Spontaneous::Output::Context::ContextCore include Spontaneous::Output::Context::PreviewContext def escape(val) ::CGI.escapeHTML(val) end def title "THE TITLE" end def unsafe "" end def bell 'ding' end def show_errors? true end end @context = @klass.new(Object.new, :html) end after do teardown_site end describe "First render" do before do # @template = Cutaneous::PublishTemplate.new @engine = S::Output::Template::PublishEngine.new(@template_root) end it "ignore second level statements" do input = '{{title}}{{unsafe}}' output = @engine.render_string(input, @context) output.must_equal '{{title}}{{unsafe}}' end it "evaluate first level expressions" do output = @engine.render_string('${title}{{unsafe}}', @context) output.must_equal 'THE TITLE{{unsafe}}' end it "evaluate first level statements" do output = @engine.render_string('${title}%{ 2.times do }{{unsafe}}%{ end }', @context) output.must_equal 'THE TITLE{{unsafe}}{{unsafe}}' end it "generate 2nd render templates" do output = @engine.render_string("${title}%{ 2.times do }{{bell}}\n%{ end }", @context) second = S::Output::Template::RequestEngine.new(@template_root) output = second.render_string(output, @context) output.must_equal "THE TITLEding\nding\n" end it "handle multiline statements" do output = @engine.render_string((<<-TEMPLATE), @context) %{ something = 3 nothing = 4; another = 5 -} ${ something + nothing + another -} TEMPLATE output.must_equal "12" end it "correctly handle braces within statements" do output = @engine.render_string((<<-TEMPLATE), @context) %{ a = { :a => "a", :b => "b" } b = { :c => "c", :d => "d" } c = a.map { |k, v| "\#{k}-\#{v}"}.join("/") -} ${ a[:a] }${ a[:b] -} TEMPLATE output.must_equal "ab" end it "can convert a first-pass template to a second-pass template xxx" do input = "${ template 'content/template' }" output = @engine.render_string(input, @context) output.must_equal "{{{ title }}}\n" end end describe "Second render" do before do @engine = S::Output::Template::RequestEngine.new(@template_root) end it "a render unescaped expressions" do output = @engine.render_string('{{title}}{{{unsafe}}}', @context) output.must_equal "THE TITLE" end it "render escaped expressions" do output = @engine.render_string('{{ unsafe }}', @context) output.must_equal "#{ERB::Util.html_escape(@context.unsafe)}" end it "evaluate expressions" do output = @engine.render_string('{% 2.times do %}{{title}}{% end %}', @context) output.must_equal "THE TITLETHE TITLE" end end describe "Content" do before do @engine = S::Output::Template::PublishEngine.new(@template_root / "content") end it "render" do output = @engine.render_template('template', @context) output.must_equal "THE TITLE\n" end it "preprocess" do output = @engine.render_template('preprocess', @context) output.must_equal "THE TITLE{{bell}}\n" end it "include imports" do output = @engine.render_template('include', @context) output.must_equal "{{bell}}ding\n\n" end it "include imports in sub-directories" do output = @engine.render_template('include_dir', @context) output.must_equal "{{ bell }}ding\n\n" end it "preserve the format across includes" do context = @klass.new(Object.new) output = @engine.render_template('template', @context, "epub") output.must_equal "{{ bell }}ding\n\n" end it "render a second pass" do engine = S::Output::Template::RequestEngine.new(@template_root / "content") output = engine.render_template('second', @context) output.must_equal "THE TITLEding\n" end end describe "hierarchy" do before do @engine = S::Output::Template::PublishEngine.new(@template_root / "extended") end it "work" do output = @engine.render_template('main', @context) expected = "Main Title {{page.title}}Grandparent Nav\nMain Body\nParent Body\nGrandparent Body\nGrandparent Footer\nParent Footer\n" output.must_equal expected end it "allow the use of includes" do output = @engine.render_template('with_includes', @context) output.must_equal (<<-RENDER) Parent Title INCLUDE PARTIAL Grandparent Footer Parent Footer RENDER end it "allow passing of local variables to included templates" do output = @engine.render_template('with_includes_and_locals', @context) output.must_equal (<<-RENDER) Parent Title INCLUDE local title Grandparent Footer Parent Footer RENDER end it "keeps a reference to the render cache in included templates" do # The render cache is kept on the renderer so it needs to be passed by the # context#clone method @context._renderer = "renderer" output = @engine.render_template('with_includes_and_renderer', @context) output.must_equal "renderer\nrenderer\n" end end describe "conversion" do before do @context_class = Class.new(Spontaneous::Output.context_class) do include Spontaneous::Output::Context::ContextCore include Spontaneous::Output::Context::PreviewContext def escape(val) CGI.escapeHTML(val) end def monkey "magic" end def field @klass ||= Class.new(Object) do attr_accessor :_format def to_html "(#{_format})" end def to_s "'#{_format}'" end end @klass.new.tap { |i| i._format = __format } end def slot @klass ||= Class.new(Object) do def render(format, *args) "(#{format})" end end @klass.new end end @engine = S::Output::Template::PublishEngine.new(@template_root) @context = @context_class.new(Object.new) end it "call #render(format) if context responds to it" do output = @engine.render_string('${slot} ${ monkey }', @context) output.must_equal "(html) magic" end it "call to_format on non-strings" do output = @engine.render_string('${field} ${ monkey }', @context) output.must_equal "(html) magic" end it "call to_s on non-strings that have no specific handler" do @context = @context_class.new(Object.new) output = @engine.render_string('${field} ${ monkey }', @context, "weird") output.must_equal "'weird' magic" end end end