lib/roda/plugins/render_each.rb in roda-3.23.0 vs lib/roda/plugins/render_each.rb in roda-3.24.0

- old
+ new

@@ -1,7 +1,9 @@ # frozen-string-literal: true +require_relative 'render' + # class Roda module RodaPlugins # The render_each plugin allows you to render a template for each # value in an enumerable, returning the concatention of all of the @@ -30,22 +32,58 @@ # calls the render method. def self.load_dependencies(app) app.plugin :render end + COMPILED_METHOD_SUPPORT = Render::COMPILED_METHOD_SUPPORT + NO_CACHE = {:cache=>false}.freeze + ALLOWED_KEYS = [:locals, :local].freeze + module InstanceMethods # For each value in enum, render the given template using the # given opts. The template and options hash are passed to +render+. # Additional options supported: # :local :: The local variable to use for the current enum value # inside the template. An explicit +nil+ value does not # set a local variable. If not set, uses the template name. - def render_each(enum, template, opts=OPTS) - if as = opts.has_key?(:local) + def render_each(enum, template, opts=(no_opts = true; optimized_template = _cached_render_each_template_method(template); OPTS)) + if optimized_template + as = template.to_s.to_sym + return enum.map{|v| send(optimized_template, as=>v)}.join + elsif opts.has_key?(:local) as = opts[:local] else as = template.to_s.to_sym + + if COMPILED_METHOD_SUPPORT && + no_opts && + optimized_template.nil? && + (method_cache = render_opts[:template_method_cache]) && + (method_cache_key = _cached_template_method_key([:_render_each, template])) + + template_obj = retrieve_template(render_template_opts(template, NO_CACHE)) + method_name = :"_roda_render_each_#{self.class.object_id}_#{method_cache_key}" + + case template_obj + when Render::TemplateMtimeWrapper + optimized_template = method_cache[method_cache_key] = template_obj.define_compiled_method(self.class, method_name, [as]) + else + begin + unbound_method = template_obj.send(:compiled_method, [as]) + rescue ::NotImplementedError + method_cache[method_cache_key] = false + else + self.class::RodaCompiledTemplates.send(:define_method, method_name, unbound_method) + self.class::RodaCompiledTemplates.send(:private, method_name) + optimized_template = method_cache[method_cache_key] = method_name + end + end + + if optimized_template + return enum.map{|v| send(optimized_template, as=>v)}.join + end + end end if as opts = opts.dup if locals = opts[:locals] @@ -53,13 +91,92 @@ else locals = opts[:locals] = {} end end + if COMPILED_METHOD_SUPPORT && + !no_opts && + as && + (opts.keys - ALLOWED_KEYS).empty? && + (method_cache = render_opts[:template_method_cache]) + + locals_keys = (locals.keys << as).sort + key = [:_render_each, template, locals_keys] + + optimized_template = case template + when String, Symbol + _cached_template_method_lookup(method_cache, key) + else + false + end + + case optimized_template + when Symbol + return enum.map do |v| + locals[as] = v + send(optimized_template, locals) + end.join + when false + # nothing + else + if method_cache_key = _cached_template_method_key(key) + template_obj = retrieve_template(render_template_opts(template, NO_CACHE)) + method_name = :"_roda_render_each_#{self.class.object_id}_#{method_cache_key}" + + case template_obj + when Render::TemplateMtimeWrapper + optimized_template = method_cache[method_cache_key] = template_obj.define_compiled_method(self.class, method_name, locals_keys) + else + begin + unbound_method = template_obj.send(:compiled_method, locals_keys) + rescue ::NotImplementedError + method_cache[method_cache_key] = false + else + self.class::RodaCompiledTemplates.send(:define_method, method_name, unbound_method) + self.class::RodaCompiledTemplates.send(:private, method_name) + optimized_template = method_cache[method_cache_key] = method_name + end + end + + if optimized_template + return enum.map do |v| + locals[as] = v + send(optimized_template, locals) + end.join + end + end + end + end + enum.map do |v| locals[as] = v if as render_template(template, opts) end.join + end + + private + + if COMPILED_METHOD_SUPPORT + # If compiled method support is enabled in the render plugin, return the + # method name to call to render the template. Return false if not given + # a string or symbol, or if compiled method support for this template has + # been explicitly disabled. Otherwise return nil. + def _cached_render_each_template_method(template) + case template + when String, Symbol + if (method_cache = render_opts[:template_method_cache]) + _cached_template_method_lookup(method_cache, [:_render_each, template]) + end + else + false + end + end + else + # :nocov: + def _cached_render_each_template_method(template) + nil + end + # :nocov: end end end register_plugin(:render_each, RenderEach)