X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=vendor%2Frails%2Factionpack%2Flib%2Faction_view%2Freloadable_template.rb;fp=vendor%2Frails%2Factionpack%2Flib%2Faction_view%2Freloadable_template.rb;h=5ef833d75ce14d66207706a0613dd98074f1b9f8;hb=437aa336c44c74a30aeea16a06743c32747ed661;hp=0000000000000000000000000000000000000000;hpb=97a0772b06264134cfe38e7494f9427efe0840a0;p=feedcatcher.git diff --git a/vendor/rails/actionpack/lib/action_view/reloadable_template.rb b/vendor/rails/actionpack/lib/action_view/reloadable_template.rb new file mode 100644 index 0000000..5ef833d --- /dev/null +++ b/vendor/rails/actionpack/lib/action_view/reloadable_template.rb @@ -0,0 +1,117 @@ +module ActionView #:nodoc: + class ReloadableTemplate < Template + + class TemplateDeleted < ActionView::ActionViewError + end + + class ReloadablePath < Template::Path + + def initialize(path) + super + @paths = {} + new_request! + end + + def new_request! + @disk_cache = {} + end + alias_method :load!, :new_request! + + def [](path) + if found_template = @paths[path] + begin + found_template.reset_cache_if_stale! + rescue TemplateDeleted + unregister_template(found_template) + self[path] + end + else + load_all_templates_from_dir(templates_dir_from_path(path)) + # don't ever hand out a template without running a stale check + (new_template = @paths[path]) && new_template.reset_cache_if_stale! + end + end + + private + def register_template_from_file(template_full_file_path) + if !@paths[relative_path = relative_path_for_template_file(template_full_file_path)] && File.file?(template_full_file_path) + register_template(ReloadableTemplate.new(relative_path, self)) + end + end + + def register_template(template) + template.accessible_paths.each do |path| + @paths[path] = template + end + end + + # remove (probably deleted) template from cache + def unregister_template(template) + template.accessible_paths.each do |template_path| + @paths.delete(template_path) if @paths[template_path] == template + end + # fill in any newly created gaps + @paths.values.uniq.each do |template| + template.accessible_paths.each {|path| @paths[path] ||= template} + end + end + + # load all templates from the directory of the requested template + def load_all_templates_from_dir(dir) + # hit disk only once per template-dir/request + @disk_cache[dir] ||= template_files_from_dir(dir).each {|template_file| register_template_from_file(template_file)} + end + + def templates_dir_from_path(path) + dirname = File.dirname(path) + File.join(@path, dirname == '.' ? '' : dirname) + end + + # get all the template filenames from the dir + def template_files_from_dir(dir) + Dir.glob(File.join(dir, '*')) + end + end + + module Unfreezable + def freeze; self; end + end + + def initialize(*args) + super + + # we don't ever want to get frozen + extend Unfreezable + end + + def mtime + File.mtime(filename) + end + + attr_accessor :previously_last_modified + + def stale? + previously_last_modified.nil? || previously_last_modified < mtime + rescue Errno::ENOENT => e + undef_my_compiled_methods! + raise TemplateDeleted + end + + def reset_cache_if_stale! + if stale? + flush_cache 'source', 'compiled_source' + undef_my_compiled_methods! + @previously_last_modified = mtime + end + self + end + + # remove any compiled methods that look like they might belong to me + def undef_my_compiled_methods! + ActionView::Base::CompiledTemplates.public_instance_methods.grep(/#{Regexp.escape(method_name_without_locals)}(?:_locals_)?/).each do |m| + ActionView::Base::CompiledTemplates.send(:remove_method, m) + end + end + + end +end