lib/roda/plugins/render.rb in roda-2.29.0 vs lib/roda/plugins/render.rb in roda-3.0.0
- old
+ new
@@ -22,65 +22,59 @@
#
# The +render+ and +view+ methods just return strings, they do not have
# side effects (unless the templates themselves have side effects).
# As Roda uses the routing block return value as the body of the response,
# in most cases you will call these methods as the last expression in a
- # routing block # to have the response body be the result of the template
+ # routing block to have the response body be the result of the template
# rendering.
#
# Because +render+ and +view+ just return strings, you can call them inside
# templates (i.e. for subtemplates/partials), or multiple times in the
# same route and combine the results together:
#
# route do |r|
# r.is 'foo-bars' do
- # @bars = Bar.where(:foo).map{|b| render(:bar, :locals=>{:bar=>b})}.join
+ # @bars = Bar.where(:foo).map{|b| render(:bar, locals: {bar: b})}.join
# view('foo')
# end
# end
#
# You can provide options to the plugin method:
#
- # plugin :render, :engine=>'haml', :views=>'admin_views'
+ # plugin :render, engine: 'haml', views: 'admin_views'
#
# = Plugin Options
#
# The following plugin options are supported:
#
- # :allowed_paths :: Set the template paths to allow if +:check_paths+ is true.
- # Defaults to the +:views+ directory.
- # :cache :: nil/false to disallow template caching completely.
+ # :allowed_paths :: Set the template paths to allow. Attempts to render paths outside
+ # of this directory will raise an error. Defaults to the +:views+ directory.
+ # :cache :: nil/false to disable template caching by default. By default, caching
+ # is disabled by default if RACK_ENV is development.
# :cache_class :: A class to use as the template cache instead of the default.
- # :check_paths :: Check template paths start with one of the entries in +:allowed_paths+,
- # and raise a RodaError if the path doesn't.
+ # :check_paths :: Can be set to false to turn off template path checking.
# :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.
- # :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.
+ # :escape :: Use Erubi as the ERB template engine, and enable escaping by default,
+ # which makes <tt><%= %></tt> escape output and <tt><%== %></tt> not escape output.
# :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.
# :template_opts :: The tilt options used when rendering all templates. defaults to:
- # <tt>{:outvar=>'@_out_buf', :default_encoding=>Encoding.default_external}</tt>.
+ # <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
# application's :root option (the process's working directory by default).
#
# = Render/View Method Options
#
# Most of these options can be overridden at runtime by passing options
# to the +view+ or +render+ methods:
#
- # view('foo', :engine=>'html.erb')
- # render('foo', :views=>'admin_views')
+ # view('foo', engine: 'html.erb')
+ # render('foo', views: 'admin_views')
#
# There are additional options to +view+ and +render+ that are
# available at runtime:
#
# :cache :: Set to false to not cache this template, even when
@@ -106,14 +100,14 @@
# ignored when using :inline. Disables caching of the
# template by default.
# :template_class :: Provides the template class to use, inside of using
# Tilt or <tt>Tilt[:engine]</tt>.
#
- # Here's how those options are used:
+ # Here's an example of using these options:
#
- # view(:inline=>'<%= @foo %>')
- # render(:path=>'/path/to/template.erb')
+ # view(inline: '<%= @foo %>')
+ # render(path: '/path/to/template.erb')
#
# If you pass a hash as the first argument to +view+ or +render+, it should
# have either +:template+, +:inline+, +:path+, or +:content+ (for +view+) as
# one of the keys.
#
@@ -126,84 +120,52 @@
#
# If your application uses a unique template per path, in that the same
# path never uses more than one template, you can use the +view_options+ plugin
# and do:
#
- # set_view_options :cache_key=>r.path_info
+ # set_view_options cache_key: r.path_info
#
# at the top of your route block. You can even do this if you do have paths
# that use more than one template, as long as you specify +:cache_key+
# specifically when rendering in those paths.
#
# 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)
-
- # 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=RodaPlugins::OPTS)
+ def self.configure(app, opts=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[:engine] = (opts[:engine] || "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
+ opts[:check_paths] = true unless opts.has_key?(:check_paths)
- if opts.fetch(:cache, true)
- if orig_cache
- opts[:cache] = orig_cache
- elsif cache_class = opts[:cache_class]
- opts[:cache] = cache_class.new
+ unless opts.has_key?(:explicit_cache)
+ opts[:explicit_cache] = if opts.fetch(:cache, true)
+ ENV['RACK_ENV'] == 'development'
else
- opts[:cache] = app.thread_safe_cache
+ true
end
end
- opts[:explicit_cache] = ENV['RACK_ENV'] == 'development' unless opts.has_key?(:explicit_cache)
+ opts[:cache] = orig_cache || (opts[:cache_class] || RodaCache).new
opts[:layout_opts] = (opts[:layout_opts] || {}).dup
+ opts[:layout_opts][:_is_layout] = true
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)
opts[:layout] = true unless opts.has_key?(:layout)
case layout
when Hash
@@ -216,25 +178,17 @@
end
opts[:layout_opts].freeze
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)
+ unless 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
+
+ if opts[:escape]
require 'tilt/erubi'
template_opts[:escape] = true
- elsif opts[:escape]
- template_opts[:engine_class] = ErubisEscaping::Eruby
-
- opts[:escaper] ||= if opts[:escape_safe_classes]
- ErubisEscaping::UnsafeClassEscaper.new(opts[:escape_safe_classes])
- else
- ::Erubis::XmlHelper
- end
end
template_opts.freeze
engine_opts = opts[:engine_opts] = (opts[:engine_opts] || {}).dup
engine_opts.to_a.each do |k,v|
@@ -250,21 +204,11 @@
# them as necessary to prevent changes in the subclass
# affecting the parent class.
def inherited(subclass)
super
opts = subclass.opts[:render] = subclass.opts[:render].dup
-
- if opts[:cache]
- opts[:cache] = if opts[:inherit_cache]
- opts[:cache] = opts[:cache].dup
- elsif cache_class = opts[:cache_class]
- opts[:cache] = cache_class.new
- else
- opts[:cache] = thread_safe_cache
- end
- end
-
+ opts[:cache] = opts[:cache].dup
opts.freeze
end
# Return the render options for this class.
def render_opts
@@ -272,26 +216,24 @@
end
end
module InstanceMethods
# Render the given template. See Render for details.
- def render(template, opts = RodaPlugins::OPTS, &block)
+ def render(template, opts = OPTS, &block)
opts = render_template_opts(template, opts)
- retrieve_template(opts).render((opts[:scope]||self), (opts[:locals]||RodaPlugins::OPTS), &block)
+ retrieve_template(opts).render((opts[:scope]||self), (opts[:locals]||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.
+ # Return the render options for the instance's class.
def render_opts
self.class.render_opts
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=RodaPlugins::OPTS)
+ def view(template, opts=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}
@@ -302,26 +244,22 @@
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
+ parse_template_opts(template, 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
# to get the template.
def cached_template(opts, &block)
- if (!render_opts[:explicit_cache] || opts[:cache]) && (cache = render_opts[:cache]) && (key = opts[:cache_key])
+ if (!render_opts[:explicit_cache] || opts[:cache]) && (key = opts[:cache_key])
+ cache = render_opts[:cache]
unless template = cache[key]
template = cache[key] = yield
end
template
else
@@ -331,14 +269,11 @@
# 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_override = opts[:engine]
engine = opts[:engine] ||= render_opts[:engine]
if content = opts[:inline]
path = opts[:path] = content
template_class = opts[:template_class] ||= ::Tilt[engine]
opts[:template_block] = Proc.new{content}
@@ -347,45 +282,30 @@
path = opts[:path] ||= template_path(opts)
template_class = opts[:template_class]
opts[:template_class] ||= ::Tilt
end
- if render_opts[:cache]
- if (cache = opts[:cache]).nil?
- cache = content || !opts[:template_block]
- end
+ if (cache = opts[:cache]).nil?
+ cache = content || !opts[:template_block]
+ end
- if cache
- template_block = opts[:template_block] unless content
- template_opts = opts[:template_opts]
+ if cache
+ template_block = opts[:template_block] unless content
+ template_opts = opts[:template_opts]
- opts[:cache_key] ||= if template_class || engine_override || template_opts || template_block
- [path, template_class, engine_override, template_opts, template_block]
- else
- path
- end
+ opts[:cache_key] ||= if template_class || engine_override || template_opts || template_block
+ [path, template_class, engine_override, template_opts, template_block]
else
- opts.delete(:cache_key)
+ path
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."
+ else
+ opts.delete(:cache_key)
end
opts
end
- # 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
- r_locals
- end
- end
- end
-
# Return a single hash combining the template and opts arguments.
def parse_template_opts(template, opts)
opts = Hash[opts]
if template.is_a?(Hash)
opts.merge!(template)
@@ -425,68 +345,27 @@
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: #{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]
-
method_layout_opts = opts[:layout_opts]
-
- # 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
-
layout_opts.merge!(method_layout_opts) if method_layout_opts
-
- # RODA3: Remove
- layout_opts[:locals] = locals if render_plugin_handle_locals? && !locals.empty?
case layout
when Hash
layout_opts.merge!(layout)
when true