lib/roda/plugins/render.rb in roda-3.20.0 vs lib/roda/plugins/render.rb in roda-3.21.0

- old
+ new

@@ -46,12 +46,15 @@ # # The following plugin options are supported: # # :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 :: nil/false to explicitly disable premanent template caching. By default, permanent + # template caching is disabled by default if RACK_ENV is development. When permanent + # template caching is disabled, for templates with paths in the file system, the + # modification time of the file will be checked on every render, and if it has changed, + # a new template will be created for the current content of the file. # :cache_class :: A class to use as the template cache instead of the default. # :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 Erubi as the ERB template engine, and enable escaping by default, @@ -81,11 +84,11 @@ # There are additional options to +view+ and +render+ that are # available at runtime: # # :cache :: Set to false to not cache this template, even when # caching is on by default. Set to true to force caching for - # this template, even when the default is to not cache (e.g. + # this template, even when the default is to not permantently cache (e.g. # when using the :template_block option). # :cache_key :: Explicitly set the hash key to use when caching. # :content :: Only respected by +view+, provides the content to render # inside the layout, instead of rendering a template to get # the content. @@ -150,15 +153,15 @@ 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) - unless opts.has_key?(:explicit_cache) - opts[:explicit_cache] = if opts.fetch(:cache, true) - ENV['RACK_ENV'] == 'development' - else + unless opts.has_key?(:check_template_mtime) + opts[:check_template_mtime] = if opts[:cache] == false || opts[:explicit_cache] true + else + ENV['RACK_ENV'] == 'development' end end opts[:cache] = orig_cache || (opts[:cache_class] || RodaCache).new @@ -209,10 +212,38 @@ template_opts.freeze engine_opts.freeze opts.freeze end + # Wrapper object for the Tilt template, that checks the modified + # time of the template file, and rebuilds the template if the + # template file has been modified. + class TemplateMtimeWrapper + def initialize(template_class, path, *template_args) + @template_class = template_class + @path = path + @template_args = template_args + + @mtime = (File.mtime(path) if File.file?(path)) + @template = template_class.new(path, *template_args) + end + + # If the template file exists and the modification time has + # changed, rebuild the template file, then call render on it. + def render(*args, &block) + if File.file?(path = @path) + mtime = File.mtime(path) + if mtime != @mtime + @mtime = mtime + @template = @template_class.new(path, *@template_args) + end + end + + @template.render(*args, &block) + end + end + module ClassMethods # Copy the rendering options into the subclass, duping # them as necessary to prevent changes in the subclass # affecting the parent class. def inherited(subclass) @@ -266,11 +297,11 @@ 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]) && (key = opts[:cache_key]) + if key = opts[:cache_key] cache = render_opts[:cache] unless template = cache[key] template = cache[key] = yield end template @@ -333,11 +364,12 @@ Hash[render_opts[:layout_opts]] end # Retrieve the Tilt::Template object for the given template and opts. def retrieve_template(opts) - unless opts[:cache_key] && opts[:cache] != false + cache = opts[:cache] + if !opts[:cache_key] || cache == false found_template_opts = opts = find_template(opts) end cached_template(opts) do opts = found_template_opts || find_template(opts) template_opts = render_opts[:template_opts] @@ -345,10 +377,15 @@ template_opts = template_opts.merge(engine_opts) end if current_template_opts = opts[:template_opts] template_opts = template_opts.merge(current_template_opts) end - opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block]) + + if render_opts[:check_template_mtime] && !opts[:template_block] && !cache + TemplateMtimeWrapper.new(opts[:template_class], opts[:path], 1, template_opts) + else + opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block]) + end end end # The name to use for the template. By default, just converts the :template option to a string. def template_name(opts)