public
Description: Merb More: The Full Stack. Take what you need; leave what you don't.
Homepage: http://www.merbivore.com
Clone URL: git://github.com/wycats/merb-more.git
merb-more / merb-cache / lib / merb-cache / cache-page.rb
100644 103 lines (92 sloc) 2.772 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
class Merb::Cache
  cattr_accessor :cached_pages
  self.cached_pages = {}
end
 
module Merb::Cache::ControllerClassMethods
  def cache_page(action, from_now = nil)
    cache_pages([action, from_now])
  end
 
  def cache_pages(*pages)
    if pages.any? && Merb::Cache.cached_pages.empty?
      before(:cache_page_before)
      after(:cache_page_after)
    end
    pages.each do |action, from_now|
      _pages = Merb::Cache.cached_pages[controller_name] ||= {}
      _pages[action] = [from_now, 0]
    end
    true
  end
end
 
module Merb::Cache::ControllerInstanceMethods
  def cached_page?(o)
    key = Merb::Controller._cache.key_for(o, controller_name, true)
    File.file?(Merb::Controller._cache.config[:cache_html_directory] / "#{key}.html")
  end
 
  def expire_page(o)
    config_dir = Merb::Controller._cache.config[:cache_html_directory]
    Merb::Controller._cache.expire_key_for(o, controller_name, true) do |key, match|
      if match
        files = Dir.glob(config_dir / "#{key}*")
      else
        files = config_dir / "#{key}.html"
      end
      FileUtils.rm_rf(files)
    end
    true
  end
 
  def expire_all_pages
    FileUtils.rm_rf(Dir.glob(Merb::Controller._cache.config[:cache_html_directory] / "*"))
  end
 
  private
 
  def _cache_page(data = nil)
    controller = controller_name
    action = action_name.to_sym
    pages = Merb::Controller._cache.cached_pages[controller]
    return unless pages && pages.key?(action)
    path = request.path
    path.chop! if path[-1] == "/"
    path = "index" if path.empty?
    cache_file = Merb::Controller._cache.config[:cache_html_directory] / "#{path}.html"
    if data
      cache_directory = File.dirname(cache_file)
      FileUtils.mkdir_p(cache_directory)
      _expire_in = pages[action][0]
      pages[action][1] = _expire_in.minutes.from_now unless _expire_in.nil?
      cache_write_page(cache_file, data)
    else
      @capture_page = false
      if File.file?(cache_file)
        _data = cache_read_page(cache_file)
        _expire_in, _expire_at = pages[action]
        throw(:halt, _data) if _expire_in.nil? || Time.now < _expire_at
        FileUtils.rm_f(cache_file)
      end
      @capture_page = true
    end
    true
  end
 
  def cache_read_page(cache_file)
    _data = nil
    File.open(cache_file, "r") do |cache_data|
      cache_data.flock(File::LOCK_EX)
      _data = cache_data.read
      cache_data.flock(File::LOCK_UN)
    end
    _data
  end
 
  def cache_write_page(cache_file, data)
    File.open(cache_file, "w+") do |cache_data|
      cache_data.flock(File::LOCK_EX)
      cache_data.write(data)
      cache_data.flock(File::LOCK_UN)
    end
    true
  end
 
  def cache_page_before
    _cache_page
  end
  def cache_page_after
    _cache_page(body) if @capture_page
  end
end