lib/roger/template.rb in roger-1.1.3 vs lib/roger/template.rb in roger-1.2.1
- old
+ new
@@ -1,136 +1,154 @@
-require 'tilt'
-require 'mime/types'
-require 'yaml'
-require 'ostruct'
+require "tilt"
+require "mime/types"
+require "yaml"
+require "ostruct"
# We're enforcing Encoding to UTF-8
Encoding.default_external = "UTF-8"
module Roger
-
+ # Roger template processing class
class Template
-
# 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
-
+
class << self
def open(path, options = {})
- raise "Unknown file #{path}" unless File.exist?(path)
- self.new(File.read(path), options.update(:source_path => path))
- end
+ fail "Unknown file #{path}" unless File.exist?(path)
+ new(File.read(path), options.update(source_path: path))
+ end
end
-
-
- # @option options [String,Pathname] :source_path The path to the source of the template being processed
+
+ # @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
+ # @option options [String,Pathname] :partials_path The path to where all partials reside
def initialize(source, options = {})
@options = options
self.source_path = options[:source_path]
self.data, self.source = extract_front_matter(source)
- self.template = Tilt.new(self.source_path.to_s){ self.source }
-
- if self.data[:layout] && layout_template_path = self.find_template(self.data[:layout], :layouts_path)
- @layout_template = Tilt.new(layout_template_path.to_s)
- end
+ self.template = Tilt.new(source_path.to_s) { self.source }
+
+ initialize_layout
end
-
+
def render(env = {})
context = TemplateContext.new(self, env)
-
+
if @layout_template
- content_for_layout = self.template.render(context, {}) # yields
-
+ 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
- self.template.render(context, {})
+ template.render(context, {})
end
end
-
+
def find_template(name, path_type)
- raise(ArgumentError, "path_type must be one of :partials_path or :layouts_path") unless [:partials_path, :layouts_path].include?(path_type)
+ unless [:partials_path, :layouts_path].include?(path_type)
+ fail(ArgumentError, "path_type must be one of :partials_path or :layouts_path")
+ end
return nil unless @options[path_type]
- @resolvers ||= {}
+ @resolvers ||= {}
@resolvers[path_type] ||= Resolver.new(@options[path_type])
-
- @resolvers[path_type].find_template(name, :preferred_extension => self.target_extension)
+
+ @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[self.target_mime_type].first
+ 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
else
- @target_extension = File.extname(self.source_path.to_s).sub(/^\./, "")
+ @target_extension = File.extname(source_path.to_s).sub(/^\./, "")
end
end
def source_extension
- parts = File.basename(File.basename(self.source_path.to_s)).split(".")
+ parts = File.basename(File.basename(source_path.to_s)).split(".")
if parts.size > 2
parts[-2..-1].join(".")
else
- File.extname(self.source_path.to_s).sub(/^\./, "")
+ 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 = self.template.class.default_mime_type
- return mime if mime
+ mime =
+ mime_type_from_template ||
+ mime_type_from_filename ||
+ mime_type_from_sub_extension
- path = File.basename(self.source_path.to_s)
- mime = MIME::Types.type_for(path).first
- return mime.to_s if mime
-
- parts = File.basename(path).split(".")
- if parts.size > 2
- mime = MIME::Types.type_for(parts[0..-2].join(".")).first
- return mime.to_s if mime
- else
- nil
- end
+ mime.to_s if mime
end
-
+
protected
+ 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
+ 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
-
+
if match = source.match(fm_regex)
source = source.sub(fm_regex, "")
begin
- data = (YAML.load(match[1]) || {}).inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
+ data = (YAML.load(match[1]) || {}).inject({}) do |memo, (k, v)|
+ memo[k.to_sym] = v
+ memo
+ end
rescue *YAML_ERRORS => e
puts "YAML Exception: #{e.message}"
return false
end
else
@@ -139,34 +157,35 @@
[data, source]
rescue
[{}, source]
end
-
end
-
+
+ # The context that is passed to all templates
class TemplateContext
attr_accessor :_content_for_blocks
- def initialize(template, env={})
+ def initialize(template, env = {})
@_content_for_blocks = {}
- @_template, @_env = template, env
+ @_template = template
+ @_env = env
# Block counter to make sure erbtemp binding is always unique
@block_counter = 0
end
-
+
# The current Roger::Template in use
def template
@_template
end
# Access to the front-matter of the document (if any)
def document
- @_data ||= OpenStruct.new(self.template.data)
+ @_data ||= OpenStruct.new(template.data)
end
-
+
# The current environment variables.
def env
@_env
end
@@ -184,42 +203,51 @@
# ```
def content_for(block_name, &block)
@_content_for_blocks[block_name] = capture(&block)
end
+ # rubocop:disable Lint/Eval
def capture(&block)
- raise ArgumentError, "content_for works only with ERB Templates" if !self.template.template.kind_of?(Tilt::ERBTemplate)
+ unless template.template.is_a?(Tilt::ERBTemplate)
+ fail ArgumentError, "content_for works only with ERB Templates"
+ end
@block_counter += 1
counter = @block_counter
eval "@_erbout_tmp#{counter} = _erbout", block.binding
eval "_erbout = \"\"", block.binding
- t = Tilt::ERBTemplate.new(){ "<%= yield %>" }
+ t = Tilt::ERBTemplate.new { "<%= yield %>" }
t.render(&block)
ensure
eval "_erbout = @_erbout_tmp#{counter}", block.binding
end
-
+
def partial(name, options = {}, &block)
- if template_path = self.template.find_template(name, :partials_path)
- partial_template = Tilt.new(template_path.to_s)
+ template_path = template.find_template(name, :partials_path)
+ if template_path
+ out = render_partial(template_path, options, &block)
if block_given?
- block_content = capture(&block)
- else
- block_content = ""
- end
- out = partial_template.render(self, options[:locals] || {}){ block_content }
-
- if block_given?
eval "_erbout.concat(#{out.dump})", block.binding
else
out
end
else
- raise ArgumentError, "No such partial #{name}, referenced from #{self.template.source_path}"
+ fail ArgumentError, "No such partial #{name}, referenced from #{template.source_path}"
end
end
-
+ # rubocop:enable Lint/Eval
+
+ protected
+
+ # Capture a block and render the partial
+ def render_partial(template_path, options, &block)
+ partial_template = Tilt.new(template_path.to_s)
+ if block_given?
+ block_content = capture(&block)
+ else
+ block_content = ""
+ end
+ partial_template.render(self, options[:locals] || {}) { block_content }
+ end
end
-
end