class Middleman::TemplateRenderer
def self.cache
def self.cache @_cache ||= Cache.new end
def self.locate_layout(app, name, preferred_engine=nil)
def self.locate_layout(app, name, preferred_engine=nil) resolve_opts = {} resolve_opts[:preferred_engine] = preferred_engine unless preferred_engine.nil? # Check layouts folder layout_file = resolve_template(app, File.join(app.config[:layouts_dir], name.to_s), resolve_opts) # If we didn't find it, check root layout_file = resolve_template(app, name, resolve_opts) unless layout_file # Return the path layout_file end
def self.resolve_template(app, request_path, options={})
def self.resolve_template(app, request_path, options={}) # Find the path by searching relative_path = Util.strip_leading_slash(request_path.to_s) # By default, any engine will do preferred_engines = [] # If we're specifically looking for a preferred engine if options.key?(:preferred_engine) extension_class = ::Tilt[options[:preferred_engine]] # Get a list of extensions for a preferred engine preferred_engines += ::Tilt.mappings.select do |_, engines| engines.include? extension_class end.keys end preferred_engines << '*' preferred_engines << nil if options[:try_static] found_template = nil preferred_engines.each do |preferred_engine| path_with_ext = relative_path.dup path_with_ext << ('.' + preferred_engine) unless preferred_engine.nil? globbing = preferred_engine == '*' # Cache lookups in build mode only file = if app.build? cache.fetch(path_with_ext, preferred_engine) do app.files.find(:source, path_with_ext, globbing) end else app.files.find(:source, path_with_ext, globbing) end found_template = file if file && (preferred_engine.nil? || ::Tilt[file[:full_path]]) break if found_template end # If we found one, return it found_template end
def _render_with_all_renderers(path, locs, context, opts, &block)
def _render_with_all_renderers(path, locs, context, opts, &block) # Keep rendering template until we've used up all extensions. This # handles cases like `style.css.sass.erb` content = nil while ::Tilt[path] begin opts[:template_body] = content if content content_renderer = ::Middleman::FileRenderer.new(@app, path) content = content_renderer.render(locs, opts, context, &block) path = File.basename(path, File.extname(path)) rescue LocalJumpError raise "Tried to render a layout (calls yield) at #{path} like it was a template. Non-default layouts need to be in #{@app.config[:source]}/#{@app.config[:layouts_dir]}." end end content end
def fetch_layout(engine, opts)
def fetch_layout(engine, opts) # The layout name comes from either the system default or the options local_layout = opts.key?(:layout) ? opts[:layout] : @app.config[:layout] return unless local_layout # Look for engine-specific options engine_options = @app.config.respond_to?(engine) ? @app.config.send(engine) : {} # The engine for the layout can be set in options, engine_options or passed # into this method layout_engine = if opts.key?(:layout_engine) opts[:layout_engine] elsif engine_options.key?(:layout_engine) engine_options[:layout_engine] else engine end # Automatic mode if local_layout == :_auto_layout # Look for :layout of any extension # If found, use it. If not, continue locate_layout(:layout, layout_engine) else # Look for specific layout # If found, use it. If not, error. if layout_file = locate_layout(local_layout, layout_engine) layout_file else raise ::Middleman::TemplateRenderer::TemplateNotFound, "Could not locate layout: #{local_layout}" end end end
def initialize(app, path)
def initialize(app, path) @app = app @path = path end
def locate_layout(name, preferred_engine=nil)
def locate_layout(name, preferred_engine=nil) self.class.locate_layout(@app, name, preferred_engine) end
def render(locs={}, opts={}, &block)
def render(locs={}, opts={}, &block) path = @path.dup locals = locs.dup.freeze options = opts.dup extension = File.extname(path) engine = extension[1..-1].to_sym if defined?(::I18n) old_locale = ::I18n.locale ::I18n.locale = options[:lang] if options[:lang] end # Sandboxed class for template eval context = @app.template_context_class.new(@app, locals, options) # TODO: Only for HAML files context.init_haml_helpers if context.respond_to?(:init_haml_helpers) content = _render_with_all_renderers(path, locs, context, opts, &block) # If we need a layout and have a layout, use it if layout_file = fetch_layout(engine, options) layout_renderer = ::Middleman::FileRenderer.new(@app, layout_file[:relative_path].to_s) content = layout_renderer.render(locals, options, context) { content } end # Return result content ensure # Pop all the saved variables from earlier as we may be returning to a # previous render (layouts, partials, nested layouts). ::I18n.locale = old_locale if defined?(::I18n) end
def resolve_template(request_path, options={})
def resolve_template(request_path, options={}) self.class.resolve_template(@app, request_path, options) end