lib/roger/template.rb in roger-1.3.5 vs lib/roger/template.rb in roger-1.4.0
- old
+ new
@@ -1,10 +1,12 @@
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
# Roger template processing class
@@ -24,10 +26,21 @@
class << self
def open(path, options = {})
fail "Unknown file #{path}" unless File.exist?(path)
new(File.read(path), 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
@@ -41,11 +54,11 @@
initialize_layout
end
def render(env = {})
- context = TemplateContext.new(self, env)
+ context = prepare_context(env)
if @layout_template
content_for_layout = template.render(context, {}) # yields
@layout_template.render(context, {}) do |content_for|
@@ -109,10 +122,21 @@
mime.to_s if mime
end
protected
+ def prepare_context(env)
+ context = TemplateContext.new(self, env)
+
+ # Extend context with all helpers
+ self.class.helpers.each do |mod|
+ context.extend(mod)
+ 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
@@ -156,98 +180,8 @@
end
[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 = {})
- @_content_for_blocks = {}
- @_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(template.data)
- end
-
- # The current environment variables.
- def env
- @_env
- end
-
- # Capture content in blocks in the template for later use in the layout.
- # Currently only works in ERB templates. Use like this in the template:
- #
- # ```
- # <% content_for :name %> bla bla <% end %>
- # ```
- #
- # Place it like this in the layout:
- #
- # ```
- # <%= yield :name %>
- # ```
- def content_for(block_name, &block)
- @_content_for_blocks[block_name] = capture(&block)
- end
-
- # rubocop:disable Lint/Eval
- def capture(&block)
- 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.render(&block)
- ensure
- eval "_erbout = @_erbout_tmp#{counter}", block.binding
- end
-
- def partial(name, options = {}, &block)
- template_path = template.find_template(name, :partials_path)
- if template_path
- out = render_partial(template_path, options, &block)
- if block_given?
- eval "_erbout.concat(#{out.dump})", block.binding
- else
- out
- end
- else
- 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