lib/roda/plugins/render.rb in roda-2.28.0 vs lib/roda/plugins/render.rb in roda-2.29.0
- old
+ new
@@ -55,26 +55,18 @@
# :engine :: The tilt engine to use for rendering, also the default file extension for
# templates, defaults to 'erb'.
# :escape :: Use Roda's Erubis escaping support, which makes <tt><%= %></tt> escape output,
# <tt><%== %></tt> not escape output, and handles postfix conditions inside
# <tt><%= %></tt> tags. Can have a value of :erubi to use Erubi escaping support.
- # :escape_safe_classes :: String subclasses that should not be HTML escaped when used in
- # <tt><%= %></tt> tags, when :escape=>true is used. Can be an array for multiple classes.
- # :escaper :: Object used for escaping output of <tt><%= %></tt>, when :escape=>true is used,
- # overriding the default. If given, object should respond to +escape_xml+ with
- # a single argument and return an output string.
# :explicit_cache :: Only use the template cache if the :cache option is provided when rendering
# (useful for development). Defaults to true if RACK_ENV is development, allowing explicit
# caching of specific templates, but not caching by default.
# :inherit_cache :: Whether to create a dup of the cache in subclasses. The default is false, which
# starts subclasses with an empty cache.
# :layout :: The base name of the layout file, defaults to 'layout'. This can be provided as a hash
# with the :template or :inline options.
- # :layout_opts :: The options to use when rendering the layout, if different
- # from the default options. To pass local variables to the layout, include a :locals
- # option inside :layout_opts. To automatically merge the view template locals into
- # the layout template locals, include a :merge_locals option inside :layout_opts.
+ # :layout_opts :: The options to use when rendering the layout, if different from the default options.
# :template_opts :: The tilt options used when rendering all templates. defaults to:
# <tt>{:outvar=>'@_out_buf', :default_encoding=>Encoding.default_external}</tt>.
# :engine_opts :: The tilt options to use per template engine. Keys are
# engine strings, values are hashes of template options.
# :views :: The directory holding the view files, defaults to the 'views' subdirectory of the
@@ -145,27 +137,32 @@
# If you use a single layout in your application, you can also make layout
# rendering faster by specifying +:cache_key+ inside the +:layout_opts+
# plugin option.
module Render
OPTS={}.freeze
+ RodaPlugins.deprecate_constant(self, :OPTS)
- def self.load_dependencies(app, opts=OPTS)
+ # RODA3: Remove
+ def self.load_dependencies(app, opts=RodaPlugins::OPTS)
if opts[:escape] && opts[:escape] != :erubi
app.plugin :_erubis_escaping
end
end
# Setup default rendering options. See Render for details.
- def self.configure(app, opts=OPTS)
+ def self.configure(app, opts=RodaPlugins::OPTS)
if app.opts[:render]
orig_cache = app.opts[:render][:cache]
opts = app.opts[:render][:orig_opts].merge(opts)
end
app.opts[:render] = opts.dup
app.opts[:render][:orig_opts] = opts
opts = app.opts[:render]
+ if opts[:ext] && !opts[:engine]
+ RodaPlugins.warn "The :ext render plugin option is deprecated and will be removed in Roda 3. Switch to using the :engine option."
+ end
opts[:engine] = (opts[:engine] || opts[:ext] || "erb").dup.freeze
opts[:views] = app.expand_path(opts[:views]||"views").freeze
opts[:allowed_paths] ||= [opts[:views]].freeze
opts[:allowed_paths] = opts[:allowed_paths].map{|f| app.expand_path(f, nil)}.uniq.freeze
@@ -180,12 +177,29 @@
end
opts[:explicit_cache] = ENV['RACK_ENV'] == 'development' unless opts.has_key?(:explicit_cache)
opts[:layout_opts] = (opts[:layout_opts] || {}).dup
+ if opts[:layout_opts][:views]
+ opts[:layout_opts][:views] = app.expand_path(opts[:layout_opts][:views]).freeze
+ end
+ # RODA3: Remove
opts[:layout_opts][:_is_layout] = true
+ if opts[:locals]
+ RodaPlugins.warn "The :locals render plugin option is deprecated and will be removed in Roda 3. Locals should now be specified on a per-call basis, or you can use the render_locals plugin."
+ end
+
+ if opts[:layout_opts][:locals]
+ RodaPlugins.warn "The :layout_opts=>:locals render plugin option is deprecated and will be removed in Roda 3. Locals should now be specified on a per-call basis, or you can use the render_locals plugin."
+ end
+
+ if opts[:layout_opts][:merge_locals]
+ RodaPlugins.warn "The :layout_opts=>:merge_locals render plugin option is deprecated and will be removed in Roda 3. You can use the render_locals plugin for merging locals."
+ end
+
+ # RODA3: Remove
if opts[:layout_opts][:merge_locals] && opts[:locals]
opts[:layout_opts][:locals] = opts[:locals].merge(opts[:layout_opts][:locals] || {})
end
if layout = opts.fetch(:layout, true)
@@ -205,10 +219,11 @@
template_opts = opts[:template_opts] = (opts[:template_opts] || {}).dup
template_opts[:outvar] ||= '@_out_buf'
if RUBY_VERSION >= "1.9" && !template_opts.has_key?(:default_encoding)
template_opts[:default_encoding] = Encoding.default_external
end
+ # RODA3: Make :escape assume erubi, remove erubis support
if opts[:escape] == :erubi
require 'tilt/erubi'
template_opts[:escape] = true
elsif opts[:escape]
template_opts[:engine_class] = ErubisEscaping::Eruby
@@ -257,14 +272,13 @@
end
end
module InstanceMethods
# Render the given template. See Render for details.
- def render(template, opts = OPTS, &block)
- opts = parse_template_opts(template, opts)
- merge_render_locals(opts)
- retrieve_template(opts).render((opts[:scope]||self), (opts[:locals]||OPTS), &block)
+ def render(template, opts = RodaPlugins::OPTS, &block)
+ opts = render_template_opts(template, opts)
+ retrieve_template(opts).render((opts[:scope]||self), (opts[:locals]||RodaPlugins::OPTS), &block)
end
# Return the render options for the instance's class. While this
# is not currently frozen, it may be frozen in a future version,
# so you should not attempt to modify it.
@@ -273,11 +287,11 @@
end
# Render the given template. If there is a default layout
# for the class, take the result of the template rendering
# and render it inside the layout. See Render for details.
- def view(template, opts=OPTS)
+ def view(template, opts=RodaPlugins::OPTS)
opts = parse_template_opts(template, opts)
content = opts[:content] || render_template(opts)
if layout_opts = view_layout_opts(opts)
content = render_template(layout_opts){content}
@@ -286,10 +300,20 @@
content
end
private
+ # Convert template options to single hash when rendering templates using render.
+ def render_template_opts(template, opts)
+ opts = parse_template_opts(template, opts)
+
+ # RODA3: Remove
+ merge_render_locals(opts) if render_plugin_handle_locals?
+
+ opts
+ end
+
# Private alias for render. Should be used by other plugins when they want to render a template
# without a layout, as plugins can override render to use a layout.
alias render_template render
# If caching templates, attempt to retrieve the template from the cache. Otherwise, just yield
@@ -307,10 +331,13 @@
# Given the template name and options, set the template class, template path/content,
# template block, and locals to use for the render in the passed options.
def find_template(opts)
render_opts = render_opts()
+ if opts[:ext] && !opts[:engine]
+ RodaPlugins.warn "The :ext render plugin option is deprecated and will be removed in Roda 3. Switch to using the :engine option."
+ end
engine_override = opts[:engine] ||= opts[:ext]
engine = opts[:engine] ||= render_opts[:engine]
if content = opts[:inline]
path = opts[:path] = content
template_class = opts[:template_class] ||= ::Tilt[engine]
@@ -337,16 +364,18 @@
path
end
else
opts.delete(:cache_key)
end
+ elsif opts[:cache]
+ RodaPlugins.warn ":cache render/view method option used when caching explicitly disabled via :cache=>nil/false plugin option. Caching this template will be skipped for backwards compatibility. Starting in Roda 3, the :cache render/view method option will force caching even if the plugin defaults to not caching."
end
opts
end
- # Merge any :locals specified in the render_opts into the :locals option given.
+ # RODA3: Remove
def merge_render_locals(opts)
if !opts[:_is_layout] && (r_locals = render_opts[:locals])
opts[:locals] = if locals = opts[:locals]
Hash[r_locals].merge!(locals)
else
@@ -396,48 +425,68 @@
end
# The template path for the given options.
def template_path(opts)
path = "#{opts[:views]}/#{template_name(opts)}.#{opts[:engine]}"
+ full_path = self.class.expand_path(path)
if opts.fetch(:check_paths){render_opts[:check_paths]}
- full_path = self.class.expand_path(path)
unless render_opts[:allowed_paths].any?{|f| full_path.start_with?(f)}
- raise RodaError, "attempt to render path not in allowed_paths: #{path} (allowed: #{render_opts[:allowed_paths].join(', ')})"
+ raise RodaError, "attempt to render path not in allowed_paths: #{full_path} (allowed: #{render_opts[:allowed_paths].join(', ')})"
end
+ elsif !opts.has_key?(:check_paths) && !render_opts.has_key?(:check_paths)
+ unless render_opts[:allowed_paths].any?{|f| full_path.start_with?(f)}
+ RodaPlugins.warn "The :check_paths render/view method option and :check_paths render plugin option were not specified, and the path used for the template (#{full_path.inspect}) is not in the allowed paths (#{render_opts[:allowed_paths].inspect}). Allowing the template render anyway for backwards compatibility, but an error will be raised starting in Roda 3. Specify the :allowed_paths render plugin option to include the path, or use the :check_paths=>false render plugin option to explicitly disable path checking."
+ end
end
path
end
+ # RODA3: Remove
+ def render_plugin_handle_locals?
+ true
+ end
+
# If a layout should be used, return a hash of options for
# rendering the layout template. If a layout should not be
# used, return nil.
def view_layout_opts(opts)
if layout = opts.fetch(:layout, render_opts[:layout])
-
layout_opts = render_layout_opts
+
+ # RODA3: Remove
merge_locals = layout_opts[:merge_locals]
- if method_layout_opts = opts[:layout_opts]
- method_layout_locals = method_layout_opts[:locals]
- merge_locals = method_layout_opts[:merge_locals] if method_layout_opts.has_key?(:merge_locals)
- end
+ method_layout_opts = opts[:layout_opts]
- locals = {}
- if merge_locals && (plugin_locals = render_opts[:locals])
- locals.merge!(plugin_locals)
+ # RODA3: Remove
+ if render_plugin_handle_locals?
+ if method_layout_opts
+ method_layout_locals = method_layout_opts[:locals]
+ if method_layout_opts.has_key?(:merge_locals)
+ RodaPlugins.warn "The :layout_opts=>:merge_locals view option is deprecated and will be removed in Roda 3. You can use the render_locals plugin for merging locals."
+ merge_locals = method_layout_opts[:merge_locals]
+ end
+ end
+
+ locals = {}
+ if merge_locals && (plugin_locals = render_opts[:locals])
+ locals.merge!(plugin_locals)
+ end
+ if layout_locals = layout_opts[:locals]
+ locals.merge!(layout_locals)
+ end
+ if merge_locals && (method_locals = opts[:locals])
+ locals.merge!(method_locals)
+ end
+ if method_layout_locals
+ locals.merge!(method_layout_locals)
+ end
end
- if layout_locals = layout_opts[:locals]
- locals.merge!(layout_locals)
- end
- if merge_locals && (method_locals = opts[:locals])
- locals.merge!(method_locals)
- end
- if method_layout_locals
- locals.merge!(method_layout_locals)
- end
layout_opts.merge!(method_layout_opts) if method_layout_opts
- layout_opts[:locals] = locals unless locals.empty?
+
+ # RODA3: Remove
+ layout_opts[:locals] = locals if render_plugin_handle_locals? && !locals.empty?
case layout
when Hash
layout_opts.merge!(layout)
when true