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