Skip to content
Browse files

Template#initialize_engine - called first use of template class

  • Loading branch information...
1 parent 2f2aa38 commit 54a860469153aa1557d63daafacf12d0b9638379 @rtomayko committed Nov 12, 2009
Showing with 88 additions and 30 deletions.
  1. +59 −27 lib/tilt.rb
  2. +29 −3 test/spec_tilt_template.rb
View
86 lib/tilt.rb
@@ -67,14 +67,31 @@ class Template
# default, template data is read from the file specified. When a block
# is given, it should read template data and return as a String. When
# file is nil, a block is required.
+ #
+ # The #initialize_engine method is called if this is the very first
+ # time this template subclass has been initialized.
def initialize(file=nil, line=1, options={}, &block)
raise ArgumentError, "file or block required" if file.nil? && block.nil?
options, line = line, 1 if line.is_a?(Hash)
@file = file
@line = line || 1
@options = options || {}
@reader = block || lambda { |t| File.read(file) }
+
+ if !self.class.engine_initialized
+ initialize_engine
+ self.class.engine_initialized = true
+ end
+ end
+
+ # Called once and only once for each template subclass the first time
+ # the template class is initialized. This should be used to require the
+ # underlying template library and perform any initial setup.
+ def initialize_engine
end
+ @engine_initialized = false
+ class << self ; attr_accessor :engine_initialized ; end
+
# Load template source and compile the template. The template is
# loaded and compiled the first time this method is called; subsequent
@@ -192,8 +209,11 @@ def initialize(*args)
@template_procs = {}
end
+ def initialize_engine
+ require_template_library 'erb' unless defined? ::ERB
+ end
+
def compile!
- require_template_library 'erb' unless defined?(::ERB)
@engine = ::ERB.new(data, options[:safe], options[:trim], '@_out_buf')
end
@@ -238,8 +258,11 @@ def local_assignment_code(locals)
# Erubis template implementation. See:
# http://www.kuwata-lab.com/erubis/
class ErubisTemplate < ERBTemplate
+ def initialize_engine
+ require_template_library 'erubis' unless defined? ::Erubis
+ end
+
def compile!
- require_template_library 'erubis' unless defined?(::Erubis)
Erubis::Eruby.class_eval(%Q{def add_preamble(src) src << "@_out_buf = _buf = '';" end})
@engine = ::Erubis::Eruby.new(data, options)
end
@@ -250,8 +273,11 @@ def compile!
# Haml template implementation. See:
# http://haml.hamptoncatlin.com/
class HamlTemplate < Template
+ def initialize_engine
+ require_template_library 'haml' unless defined? ::Haml::Engine
+ end
+
def compile!
- require_template_library 'haml' unless defined?(::Haml::Engine)
@engine = ::Haml::Engine.new(data, haml_options)
end
@@ -272,8 +298,11 @@ def haml_options
#
# Sass templates do not support object scopes, locals, or yield.
class SassTemplate < Template
+ def initialize_engine
+ require_template_library 'sass' unless defined? ::Sass::Engine
+ end
+
def compile!
- require_template_library 'sass' unless defined?(::Sass::Engine)
@engine = ::Sass::Engine.new(data, sass_options)
end
@@ -292,10 +321,13 @@ def sass_options
# Builder template implementation. See:
# http://builder.rubyforge.org/
class BuilderTemplate < Template
- def compile!
+ def initialize_engine
require_template_library 'builder' unless defined?(::Builder)
end
+ def compile!
+ end
+
def evaluate(scope, locals, &block)
xml = ::Builder::XmlMarkup.new(:indent => 2)
if data.respond_to?(:to_str)
@@ -328,8 +360,11 @@ def template_source
# It's suggested that your program require 'liquid' at load
# time when using this template engine.
class LiquidTemplate < Template
+ def initialize_engine
+ require_template_library 'liquid' unless defined? ::Liquid::Template
+ end
+
def compile!
- require_template_library 'liquid' unless defined?(::Liquid::Template)
@engine = ::Liquid::Template.parse(data)
end
@@ -358,8 +393,11 @@ def flags
[:smart, :filter_html].select { |flag| options[flag] }
end
+ def initialize_engine
+ require_template_library 'rdiscount' unless defined? ::RDiscount
+ end
+
def compile!
- require_template_library 'rdiscount' unless defined?(::RDiscount)
@engine = RDiscount.new(data, *flags)
end
@@ -381,38 +419,33 @@ def evaluate(scope, locals, &block)
class MustacheTemplate < Template
attr_reader :engine
- # Locates and compiles the Mustache object used to create new views. The
- def compile!
- require_template_library 'mustache' unless defined?(::Mustache)
+ def initialize_engine
+ require_template_library 'mustache' unless defined? ::Mustache
+ end
- # Set the Mustache view namespace if we can
+ def compile!
Mustache.view_namespace = options[:namespace]
-
- # Figure out which Mustache class to use.
@engine = options[:view] || Mustache.view_class(name)
-
- # set options on the view class
options.each do |key, value|
next if %w[view namespace mustaches].include?(key.to_s)
@engine.send("#{key}=", value) if @engine.respond_to? "#{key}="
end
end
def evaluate(scope=nil, locals={}, &block)
- # Create a new instance for playing with
instance = @engine.new
- # Copy instance variables from scope to the view
+ # copy instance variables from scope to the view
scope.instance_variables.each do |name|
instance.instance_variable_set(name, scope.instance_variable_get(name))
end
- # Locals get added to the view's context
+ # locals get added to the view's context
locals.each do |local, value|
instance[local] = value
end
- # If we're passed a block it's a subview. Sticking it in yield
+ # if we're passed a block it's a subview. Sticking it in yield
# lets us use {{yield}} in layout.html to render the actual page.
instance[:yield] = block.call if block
@@ -426,18 +459,18 @@ def evaluate(scope=nil, locals={}, &block)
# RDoc template. See:
# http://rdoc.rubyforge.org/
#
- # It's suggested that your program require:
- #
- # require 'rdoc/markup'
- # require 'rdoc/markup/to_html'
- #
- # at load time when using this template engine.
+ # It's suggested that your program require 'rdoc/markup' and
+ # 'rdoc/markup/to_html' at load time when using this template
+ # engine.
class RDocTemplate < Template
- def compile!
+ def initialize_engine
unless defined?(::RDoc::Markup)
require_template_library 'rdoc/markup'
require_template_library 'rdoc/markup/to_html'
end
+ end
+
+ def compile!
markup = RDoc::Markup::ToHtml.new
@engine = markup.convert(data)
end
@@ -447,5 +480,4 @@ def evaluate(scope, locals, &block)
end
end
register 'rdoc', RDocTemplate
-
end
View
32 test/spec_tilt_template.rb
@@ -44,9 +44,30 @@
}.should.not.raise
end
- it "raises NotImplementedError when #compile! not defined" do
- inst = Tilt::Template.new { |template| "Hello World!" }
- lambda { inst.render }.should.raise NotImplementedError
+ class InitializingMockTemplate < Tilt::Template
+ @@initialized_count = 0
+ def self.initialized_count
+ @@initialized_count
+ end
+
+ def initialize_engine
+ @@initialized_count += 1
+ end
+
+ def compile!
+ end
+ end
+
+ it "calls #initialize_engine the very first time " do
+ InitializingMockTemplate.engine_initialized.should.be.nil
+ InitializingMockTemplate.initialized_count.should.equal 0
+
+ InitializingMockTemplate.new { "Hello World!" }
+ InitializingMockTemplate.engine_initialized.should.equal true
+ InitializingMockTemplate.initialized_count.should.equal 1
+
+ InitializingMockTemplate.new { "Hello World!" }
+ InitializingMockTemplate.initialized_count.should.equal 1
end
class CompilingMockTemplate < Tilt::Template
@@ -57,6 +78,11 @@ def compile!
def compiled? ; @compiled ; end
end
+ it "raises NotImplementedError when #compile! not defined" do
+ inst = Tilt::Template.new { |template| "Hello World!" }
+ lambda { inst.render }.should.raise NotImplementedError
+ end
+
it "raises NotImplementedError when #evaluate or #template_source not defined" do
inst = CompilingMockTemplate.new { |t| "Hello World!" }
lambda { inst.render }.should.raise NotImplementedError

0 comments on commit 54a8604

Please sign in to comment.
Something went wrong with that request. Please try again.