lib/renee-render.rb in renee-render-0.1.1 vs lib/renee-render.rb in renee-render-0.2.0

- old
+ new

@@ -1,109 +1,116 @@ require 'tilt' +require 'callsite' +# Top-level Renee constant class Renee # This module is responsible for handling the rendering of templates # using Tilt supporting all included template engines. module Render ## - # Exception responsible for when a generic rendering error occurs. - # - class RenderError < RuntimeError; end - - ## # Exception responsible for when an expected template does not exist. # - class TemplateNotFound < RenderError; end + class TemplateNotFound < RuntimeError; end # Same as render but automatically halts. # @param (see #render) # @return (see #render) # @see #render - def render!(*args, &blk) - halt render(*args, &blk) + def render!(file, engine = nil, options = nil, &blk) + halt render(file, engine, options, &blk) end + # Same as inline but automatically halts. + # @param (see #inline) + # @return (see #inline) + # @see #inline + def inline!(data, engine, options = {}, &blk) + options[:_caller] = Callsite.parse(caller.first) + halt inline(data, engine, options, &blk) + end + ## + # Renders a file given the engine and the content. + # + # @param [String] file The path to the file to render + # @param [Symbol] engine The name of the engine to use to render the content. If this isn't specified + # it will be detected based on the extension of the file. + # @param [Hash] options The options to pass in for rendering. + # + # @return [String] The result of rendering the data with specified engine. + # + # @example + # render "index", :haml # => "<p>test</p>" + # render "index" # => "<p>test</p>" + # + # @api public + # + def render(file, engine = nil, options = nil, &block) + options, engine = engine, nil if engine.is_a?(Hash) + render_setup(engine, options, block) do |view_options, views| + template_cache.fetch(engine, file, view_options) do + file_path, found_engine = find_template(views, file, engine) + template = Tilt[found_engine] + raise TemplateNotFound, "Template engine not found: #{found_engine.inspect}" unless template + raise TemplateNotFound, "Template #{file.inspect} (with engine #{engine.inspect}) not found in #{views.inspect}!" unless file_path + # TODO suppress errors for layouts? + template.new(file_path, 1, view_options) + end + end + end # render + + ## # Renders a string given the engine and the content. # - # @param [Symbol] engine The template engine to use for rendering. - # @param [String] data The content or file to render. - # @param [Hash] options The rendering options to pass onto tilt. + # @param [String] data The string data to render. + # @param [Symbol] engine The name of the engine to use to render the content. If this isn't specified + # it will be detected based on the extension of the file. + # @param [Hash] options The options to pass in for rendering. # # @return [String] The result of rendering the data with specified engine. # # @example - # render :haml, "%p test" => "<p>test</p>" - # render :haml, :index => "<p>test</p>" - # render "index" => "<p>test</p>" + # inline "%p test", :haml # => "<p>test</p>" # # @api public # - def render(engine, data=nil, options={}, &block) - # Handles the case where engine is unspecified by shifting the data (i.e render "index") - engine, data, options = nil, engine.to_sym, data if data.nil? || data.is_a?(Hash) + def inline(data, engine, options = nil, &block) + options, engine = engine, nil if engine.is_a?(Hash) + call_data = options.delete(:_caller) || Callsite.parse(caller.first) + render_setup(engine, options, block) do |view_options, views| + body = data.is_a?(Proc) ? data : Proc.new { data } + template = Tilt[engine] + raise "Template engine not found: #{engine}" if template.nil? + template.new(call_data.filename, call_data.line, view_options, &body) + end + end + private + def render_setup(engine, options, block) options ||= {} options[:outvar] ||= '@_out_buf' - # TODO allow default encoding to be set (as an option) - options[:default_encoding] ||= "utf-8" + options[:default_encoding] ||= settings.default_encoding || options[:encoding] || "utf-8" locals = options.delete(:locals) || {} views = options.delete(:views) || settings.views_path || "./views" layout = options.delete(:layout) - layout_engine = options.delete(:layout_engine) || engine + layout_engine = options.delete(:layout_engine) # TODO suppress template errors for layouts? # TODO allow content_type to be set with an option to render? scope = options.delete(:scope) || self # TODO default layout file convention? - template = compile_template(engine, data, options, views) + template = yield(options, views) output = template.render(scope, locals, &block) if layout # render layout # TODO handle when layout is missing better! options = options.merge(:views => views, :layout => false, :scope => scope) - return render(layout_engine, layout, options.merge(:locals => locals)) { output } + render(layout, layout_engine, options.merge(:locals => locals)) { output } + else + output end - - output - end # render - - ## - # Constructs a template based on engine, data and options. - # - # @param [Symbol] engine The template engine to use for rendering. - # @param [String] data The content or file to render. - # @param [Hash] options The rendering options to pass onto tilt. - # @param [String] views The view_path from which to locate the template. - # - # @return [Tilt::Template] The tilt template to render with all required options. - # @raise [TemplateNotFound] The template to render could not be located. - # @raise [RenderError] The template to render could not be located. - # - # @api private - # - def compile_template(engine, data, options, views) - template_cache.fetch engine, data, options do - if data.is_a?(Symbol) # data is template path - file_path, engine = find_template(views, data, engine) - template = Tilt[engine] - raise TemplateNotFound, "Template engine not found: #{engine}" if template.nil? - raise TemplateNotFound, "Template '#{data}' not found in '#{views}'!" unless file_path - # TODO suppress errors for layouts? - template.new(file_path, 1, options) - elsif data.is_a?(String) # data is body string - # TODO figure out path based on caller file - path, line = options[:path] || "caller file", options[:line] || 1 - body = data.is_a?(String) ? Proc.new { data } : data - template = Tilt[engine] - raise "Template engine not found: #{engine}" if template.nil? - template.new(path, line.to_i, options, &body) - else # data can't be handled - raise RenderError, "Cannot render data #{data.inspect}." - end - end # template_cache.fetch - end # compile_template + end ## # Searches view paths for template based on data and engine with rendering options. # Supports finding a template without an engine. # \ No newline at end of file