This repository has been archived by the owner on Jun 10, 2018. It is now read-only.
forked from rails/sprockets
-
Notifications
You must be signed in to change notification settings - Fork 24
/
caching.rb
127 lines (108 loc) · 3.51 KB
/
caching.rb
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
require 'sprockets/bundled_asset'
require 'sprockets/static_asset'
module Sprockets
# `Caching` is an internal mixin whose public methods are exposed on
# the `Environment` and `Index` classes.
module Caching
# Return `Asset` instance for serialized `Hash`.
def asset_from_hash(hash)
return unless hash.is_a?(Hash)
case hash['class']
when 'BundledAsset'
BundledAsset.from_hash(self, hash)
when 'StaticAsset'
StaticAsset.from_hash(self, hash)
else
nil
end
rescue Exception => e
logger.debug "Cache for Asset (#{hash['logical_path']}) is stale"
logger.debug e
nil
end
def cache_hash(key, version)
if cache.nil?
yield
elsif hash = cache_get_hash(key, version)
hash
elsif hash = yield
cache_set_hash(key, version, hash)
hash
end
end
protected
# Cache helper method. Takes a `path` argument which maybe a
# logical path or fully expanded path. The `&block` is passed
# for finding and building the asset if its not in cache.
def cache_asset(path)
# If `cache` is not set, return fast
if cache.nil?
yield
# Check cache for `path`
elsif (asset = asset_from_hash(cache_get_hash(path.to_s, digest.hexdigest))) && asset.fresh?
asset
# Otherwise yield block that slowly finds and builds the asset
elsif asset = yield
hash = {}
asset.encode_with(hash)
# Save the asset to its path
cache_set_hash(path.to_s, digest.hexdigest, hash)
# Since path maybe a logical or full pathname, save the
# asset its its full path too
if path.to_s != asset.pathname.to_s
cache_set_hash(asset.pathname.to_s, digest.hexdigest, hash)
end
asset
end
end
private
# Strips `Environment#root` from key to make the key work
# consisently across different servers. The key is also hashed
# so it does not exceed 250 characters.
def cache_key_for(key)
File.join('sprockets', digest.hexdigest(key.sub(root, '')))
end
def cache_get_hash(key, version)
hash = cache_get(cache_key_for(key))
if hash.is_a?(Hash) && version == hash['_version']
hash
end
end
def cache_set_hash(key, version, hash)
hash['_version'] = version
cache_set(cache_key_for(key), hash)
hash
end
# Low level cache getter for `key`. Checks a number of supported
# cache interfaces.
def cache_get(key)
# `Cache#get(key)` for Memcache
if cache.respond_to?(:get)
cache.get(key)
# `Cache#[key]` so `Hash` can be used
elsif cache.respond_to?(:[])
cache[key]
# `Cache#read(key)` for `ActiveSupport::Cache` support
elsif cache.respond_to?(:read)
cache.read(key)
else
nil
end
end
# Low level cache setter for `key`. Checks a number of supported
# cache interfaces.
def cache_set(key, value)
# `Cache#set(key, value)` for Memcache
if cache.respond_to?(:set)
cache.set(key, value)
# `Cache#[key]=value` so `Hash` can be used
elsif cache.respond_to?(:[]=)
cache[key] = value
# `Cache#write(key, value)` for `ActiveSupport::Cache` support
elsif cache.respond_to?(:write)
cache.write(key, value)
end
value
end
end
end