lib/roger/template.rb in roger-1.4.6 vs lib/roger/template.rb in roger-1.5.0
- old
+ new
@@ -1,163 +1,92 @@
require "tilt"
require "mime/types"
require "yaml"
require "ostruct"
-require File.dirname(__FILE__) + "/template/template_context"
-
# We're enforcing Encoding to UTF-8
Encoding.default_external = "UTF-8"
module Roger
+ # Blank template is an empty template
+ #
+ # This is usefull for wrapping other templates
+ class BlankTemplate
+ def render(_locals = {}, &_block)
+ yield if block_given?
+ end
+ end
+
# Roger template processing class
- class Template
+ class Template < BlankTemplate
# The source
attr_accessor :source
# Store the frontmatter
attr_accessor :data
- # The actual Tilt template
- attr_accessor :template
-
# The path to the source file for this template
attr_accessor :source_path
+ # The current tilt template being used
+ attr_reader :current_tilt_template
+
class << self
- def open(path, options = {})
- fail "Unknown file #{path}" unless File.exist?(path)
- new(File.read(path), options.update(source_path: path))
+ def open(path, context = nil, options = {})
+ new(File.read(path), context, options.update(source_path: path))
end
-
- # Register a helper module that should be included in
- # every template context.
- def helper(mod)
- @helpers ||= []
- @helpers << mod
- end
-
- def helpers
- @helpers || []
- end
end
# @option options [String,Pathname] :source_path The path to
# the source of the template being processed
- # @option options [String,Pathname] :layouts_path The path to where all layouts reside
- # @option options [String,Pathname] :partials_path The path to where all partials reside
- def initialize(source, options = {})
- @options = options
+ def initialize(source, context = nil, options = {})
+ @context = context
self.source_path = options[:source_path]
self.data, self.source = extract_front_matter(source)
- self.template = Tilt.new(source_path.to_s) { self.source }
- initialize_layout
+ @templates = Tilt.templates_for(source_path)
end
- def render(env = {})
- context = prepare_context(env)
-
- if @layout_template
- content_for_layout = template.render(context, {}) # yields
-
- @layout_template.render(context, {}) do |content_for|
- if content_for
- context._content_for_blocks[content_for]
- else
- content_for_layout
- end
- end
- else
- template.render(context, {})
+ def render(locals = {}, &block)
+ @templates.inject(source) do |src, template|
+ render_with_tilt_template(template, src, locals, &block)
end
end
- def find_template(name, path_type)
- unless [:partials_path, :layouts_path].include?(path_type)
- fail(ArgumentError, "path_type must be one of :partials_path or :layouts_path")
- end
+ # Actual path on disk, nil if it doesn't exist
+ # The nil case is mostly used with inline rendering.
+ def real_source_path
+ return @_real_source_path if @_real_source_path_cached
- return nil unless @options[path_type]
-
- @resolvers ||= {}
- @resolvers[path_type] ||= Resolver.new(@options[path_type])
-
- @resolvers[path_type].find_template(name, preferred_extension: target_extension)
- end
-
- # Try to infer the final extension of the output file.
- def target_extension
- return @target_extension if @target_extension
-
- if type = MIME::Types[target_mime_type].first
- # Dirty little hack to enforce the use of .html instead of .htm
- if type.sub_type == "html"
- @target_extension = "html"
- else
- @target_extension = type.extensions.first
- end
+ @_real_source_path_cached = true
+ if File.exist?(source_path)
+ @_real_source_path = Pathname.new(source_path).realpath
else
- @target_extension = File.extname(source_path.to_s).sub(/^\./, "")
+ @_real_source_path = nil
end
end
- def source_extension
- parts = File.basename(File.basename(source_path.to_s)).split(".")
- if parts.size > 2
- parts[-2..-1].join(".")
- else
- File.extname(source_path.to_s).sub(/^\./, "")
- end
- end
-
- # Try to figure out the mime type based on the Tilt class and if that doesn't
- # work we try to infer the type by looking at extensions (needed for .erb)
- def target_mime_type
- mime =
- mime_type_from_template ||
- mime_type_from_filename ||
- mime_type_from_sub_extension
-
- mime.to_s if mime
- end
-
protected
- def prepare_context(env)
- context = TemplateContext.new(self, env)
+ # Render source with a specific tilt template class
+ def render_with_tilt_template(template_class, src, locals, &_block)
+ @current_tilt_template = template_class
+ template = template_class.new(source_path) { src }
- # Extend context with all helpers
- self.class.helpers.each do |mod|
- context.extend(mod)
+ if block_given?
+ block_content = yield
+ else
+ block_content = ""
end
- context
- end
-
- def initialize_layout
- return unless data[:layout]
- layout_template_path = find_template(data[:layout], :layouts_path)
-
- @layout_template = Tilt.new(layout_template_path.to_s) if layout_template_path
- end
-
- def mime_type_from_template
- template.class.default_mime_type
- end
-
- def mime_type_from_filename
- path = File.basename(source_path.to_s)
- MIME::Types.type_for(path).first
- end
-
- # Will get mime_type from source_path extension
- # but it will only look at the second extension so
- # .html.erb will look at .html
- def mime_type_from_sub_extension
- parts = File.basename(source_path.to_s).split(".")
- MIME::Types.type_for(parts[0..-2].join(".")).first if parts.size > 2
+ template.render(@context, locals) do |name|
+ if name
+ @context._content_for_blocks[name]
+ else
+ block_content
+ end
+ end
end
# Get the front matter portion of the file and extract it.
def extract_front_matter(source)
fm_regex = /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m