attr_reader :template_cache def initialize(app=nil) @app = app @template_cache = Tilt::Cache.new yield self if block_given? end # Template rendering methods. Each method takes the name of a template # to render as a Symbol and returns a String with the rendered output, # as well as an optional hash with additional options. # # `template` is either the name or path of the template as symbol # (Use `:'subdir/myview'` for views in subdirectories), or a string # that will be rendered. # # Possible options are: # :layout If set to false, no layout is rendered, otherwise # the specified layout is used (Ignored for `sass` and `less`) # :locals A hash with local variables that should be available # in the template module Templates include Tilt::CompileSite def erb(template, options={}, locals={}) options[:outvar] = '@_out_buf' render :erb, template, options, locals end def erubis(template, options={}, locals={}) options[:outvar] = '@_out_buf' render :erubis, template, options, locals end def haml(template, options={}, locals={}) render :haml, template, options, locals end def sass(template, options={}, locals={}) options[:layout] = false render :sass, template, options, locals end def less(template, options={}, locals={}) options[:layout] = false render :less, template, options, locals end def builder(template=nil, options={}, locals={}, &block) options, template = template, nil if template.is_a?(Hash) template = Proc.new { block } if template.nil? render :builder, template, options, locals end private def render(engine, data, options={}, locals={}, &block) # merge app-level options options = configs.send(engine).merge(options) if configs.respond_to?(engine) # extract generic options locals = options.delete(:locals) || locals || {} views = options.delete(:views) || configs.views || "./views" layout = options.delete(:layout) layout = :layout if layout.nil? || layout == true # compile and render template template = compile_template(engine, data, options, views) output = template.render(self, locals, &block) # render layout if layout begin options = options.merge(:views => views, :layout => false) output = render(engine, layout, options, locals) { output } rescue Errno::ENOENT end end output end def compile_template(engine, data, options, views) template_cache.fetch engine, data, options do template = Tilt[engine] raise "Template engine not found: #{engine}" if template.nil? case when data.is_a?(Symbol) body, path, line = self.class.templates[data] if body body = body.call if body.respond_to?(:call) template.new(path, line.to_i, options) { body } else path = ::File.join(views, "#{data}.#{engine}") template.new(path, 1, options) end when data.is_a?(Proc) || data.is_a?(String) body = data.is_a?(String) ? Proc.new { data } : data path, line = self.class.caller_locations.first template.new(path, line.to_i, options, &body) else raise ArgumentError end end end end