~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/actionpack/lib/action_view/reloadable_template.rb

  • Committer: Michael Forrest
  • Date: 2010-10-15 16:28:50 UTC
  • Revision ID: michael.forrest@canonical.com-20101015162850-tj2vchanv0kr0dun
refrozeĀ gems

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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