Updated README.rdoc again
[feedcatcher.git] / vendor / rails / actionpack / lib / action_view / reloadable_template.rb
1 module ActionView #:nodoc:
2 class ReloadableTemplate < Template
3
4 class TemplateDeleted < ActionView::ActionViewError
5 end
6
7 class ReloadablePath < Template::Path
8
9 def initialize(path)
10 super
11 @paths = {}
12 new_request!
13 end
14
15 def new_request!
16 @disk_cache = {}
17 end
18 alias_method :load!, :new_request!
19
20 def [](path)
21 if found_template = @paths[path]
22 begin
23 found_template.reset_cache_if_stale!
24 rescue TemplateDeleted
25 unregister_template(found_template)
26 self[path]
27 end
28 else
29 load_all_templates_from_dir(templates_dir_from_path(path))
30 # don't ever hand out a template without running a stale check
31 (new_template = @paths[path]) && new_template.reset_cache_if_stale!
32 end
33 end
34
35 private
36 def register_template_from_file(template_full_file_path)
37 if !@paths[relative_path = relative_path_for_template_file(template_full_file_path)] && File.file?(template_full_file_path)
38 register_template(ReloadableTemplate.new(relative_path, self))
39 end
40 end
41
42 def register_template(template)
43 template.accessible_paths.each do |path|
44 @paths[path] = template
45 end
46 end
47
48 # remove (probably deleted) template from cache
49 def unregister_template(template)
50 template.accessible_paths.each do |template_path|
51 @paths.delete(template_path) if @paths[template_path] == template
52 end
53 # fill in any newly created gaps
54 @paths.values.uniq.each do |template|
55 template.accessible_paths.each {|path| @paths[path] ||= template}
56 end
57 end
58
59 # load all templates from the directory of the requested template
60 def load_all_templates_from_dir(dir)
61 # hit disk only once per template-dir/request
62 @disk_cache[dir] ||= template_files_from_dir(dir).each {|template_file| register_template_from_file(template_file)}
63 end
64
65 def templates_dir_from_path(path)
66 dirname = File.dirname(path)
67 File.join(@path, dirname == '.' ? '' : dirname)
68 end
69
70 # get all the template filenames from the dir
71 def template_files_from_dir(dir)
72 Dir.glob(File.join(dir, '*'))
73 end
74 end
75
76 module Unfreezable
77 def freeze; self; end
78 end
79
80 def initialize(*args)
81 super
82
83 # we don't ever want to get frozen
84 extend Unfreezable
85 end
86
87 def mtime
88 File.mtime(filename)
89 end
90
91 attr_accessor :previously_last_modified
92
93 def stale?
94 previously_last_modified.nil? || previously_last_modified < mtime
95 rescue Errno::ENOENT => e
96 undef_my_compiled_methods!
97 raise TemplateDeleted
98 end
99
100 def reset_cache_if_stale!
101 if stale?
102 flush_cache 'source', 'compiled_source'
103 undef_my_compiled_methods!
104 @previously_last_modified = mtime
105 end
106 self
107 end
108
109 # remove any compiled methods that look like they might belong to me
110 def undef_my_compiled_methods!
111 ActionView::Base::CompiledTemplates.public_instance_methods.grep(/#{Regexp.escape(method_name_without_locals)}(?:_locals_)?/).each do |m|
112 ActionView::Base::CompiledTemplates.send(:remove_method, m)
113 end
114 end
115
116 end
117 end