1require 'digest/sha1' |
|
2require 'ostruct' |
|
4module CacheHelper |
|
5 class CacheKey |
|
6 class Dependencies |
|
7 attr_reader :fragments |
|
9 def initialize(fragments) |
|
10 @fragments = fragments |
|
11 end |
|
13 def for(name) |
|
14 dependencies_for(name).map{ |d| [d, dependencies_for(d)] }.flatten.uniq
|
|
15 end |
|
17 private
|
|
19 def dependencies_for(name) |
|
20 fragments.fetch(name).fetch(:dependencies, []) |
|
21 end |
|
22 end |
|
24 class Keys |
|
25 attr_reader :template |
|
27 delegate :assigns, :params, to: :template |
|
28 delegate :archived_petition_page?, to: :template |
|
29 delegate :create_petition_page?, to: :template |
|
30 delegate :open_petition_page?, to: :template |
|
31 delegate :home_page?, to: :template |
|
32 delegate :last_signature_at, to: :template |
|
33 delegate :last_government_response_updated_at, to: :template |
|
34 delegate :last_debate_outcome_updated_at, to: :template |
|
35 delegate :petition_page?, to: :template |
|
36 delegate :page_title, to: :template |
|
37 delegate :request, to: :template |
|
39 def initialize(template) |
|
40 @template = template |
|
41 end |
|
43 def archived_petition_page |
|
44 archived_petition_page?
|
|
45 end |
|
47 def constituency |
|
48 assigns['constituency'] |
|
49 end |
|
51 def create_petition_page |
|
52 create_petition_page?
|
|
53 end |
|
55 def open_petition_page |
|
56 open_petition_page?
|
|
57 end |
|
59 def home_page |
|
60 home_page?
|
|
61 end |
|
63 def last_petition_created_at |
|
64 Site.last_petition_created_at |
|
65 end |
|
67 def petition |
|
68 assigns['petition'] if petition_page? || archived_petition_page? |
|
69 end |
|
71 def petition_page |
|
72 petition_page?
|
|
73 end |
|
75 def reveal_response |
|
76 params[:reveal_response] == 'yes' |
|
77 end |
|
79 def site_updated_at |
|
80 Site.updated_at |
|
81 end |
|
83 def url |
|
84 request.original_url.force_encoding('utf-8') |
|
85 end |
|
87 def for(keys) |
|
88 keys.map{ |key| [key, value_for(key)] }.uniq
|
|
89 end |
|
91 def method_missing(name, *args, &block) |
|
92 if assigns.key?(name.to_s) |
|
93 assigns[name.to_s]
|
|
94 else |
|
95 super |
|
96 end |
|
97 end |
|
99 private
|
|
101 def value_for(key) |
|
102 cache_key_for(public_send(key))
|
|
103 end |
|
105 def cache_key_for(value) |
|
106 if value.respond_to?(:cache_key) |
|
107 value.cache_key
|
|
108 elsif Array === value |
|
109 value.map{ |v| cache_key_for(v) }.to_param
|
|
110 elsif Time === value |
|
111 value.to_s(:nsec) |
|
112 else |
|
113 value.to_param
|
|
114 end |
|
115 end |
|
116 end |
|
118 class Fragment |
|
119 attr_reader :keys, :dependencies, :version, :options |
|
121 def initialize(fragment) |
|
122 @keys = fragment.fetch(:keys, []) |
|
123 @dependencies = fragment.fetch(:dependencies, []) |
|
124 @version = fragment.fetch(:version, 1) |
|
125 @options = fragment.fetch(:options, {}) |
|
126 end |
|
127 end |
|
129 attr_reader :template, :name, :fragment |
|
130 delegate :options, to: :fragment |
|
132 class << self |
|
133 def build(template, args) |
|
134 new(template, args).build
|
|
135 end |
|
137 def fragments |
|
138 @fragments ||= load_yaml.deep_symbolize_keys |
|
139 end |
|
141 def reset_fragments |
|
142 @fragments = nil |
|
143 end |
|
145 private
|
|
147 def load_yaml |
|
148 YAML.load_file(Rails.root.join('config', 'fragments.yml')) |
|
149 end |
|
150 end |
|
152 def initialize(template, name) |
|
153 @template, @name = template, name |
|
154 @fragment = Fragment.new(fragments.fetch(name)) |
|
155 end |
|
157 def build |
|
158 [cache_key, options]
|
|
159 end |
|
161 private
|
|
163 def cache_key |
|
164 ["#{name}-#{version(name)}", digest].to_param |
|
165 end |
|
167 def digest |
|
168 Digest::SHA1.hexdigest(Hash[digest_keys].to_param) |
|
169 end |
|
171 def digest_keys |
|
172 keys.for(fragment.keys) + dependency_keys
|
|
173 end |
|
175 def dependencies |
|
176 @dependencies ||= Dependencies.new(fragments) |
|
177 end |
|
179 def dependency_keys |
|
180 dependencies.for(name).map{ |d| [d, version(d) ] }
|
|
181 end |
|
183 def keys |
|
184 @keys ||= Keys.new(template) |
|
185 end |
|
187 def fragment_keys |
|
188 fragment.fetch(:keys, []) |
|
189 end |
|
191 def fragments |
|
192 self.class.fragments |
|
193 end |
|
195 def version(dependency) |
|
196 fragments.fetch(dependency).fetch(:version, 1) |
|
197 end |
|
198 end |
|
200 def cache_for(name, &block) |
|
201 cache(*(CacheKey.build(self, name)), &block) |
|
202 end |
|
204 def last_signature_at |
|
205 @_last_signature_at ||= Petition.maximum(:last_signed_at) |
|
206 end |
|
208 def last_government_response_updated_at |
|
209 @_last_government_response_updated_at ||= GovernmentResponse.maximum(:updated_at) |
|
210 end |
|
212 def last_debate_outcome_updated_at |
|
213 @_last_debate_outcome_updated_at ||= DebateOutcome.maximum(:updated_at) |
|
214 end |
|
|
216 def csv_cache(name, options = nil, &block) |
217 if controller.respond_to?(:perform_caching) && controller.perform_caching |
|
218 key = ActiveSupport::Cache.expand_cache_key(name, :csv) |
|
219 Rails.cache.fetch(key, options, &block) |
|
220 else |
|
221 yield |
|
222 end |
|
223 end |
|
224end |