caching.rb 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. module Sprockets
  2. # `Caching` is an internal mixin whose public methods are exposed on
  3. # the `Environment` and `Index` classes.
  4. module Caching
  5. protected
  6. # Cache helper method. Takes a `path` argument which maybe a
  7. # logical path or fully expanded path. The `&block` is passed
  8. # for finding and building the asset if its not in cache.
  9. def cache_asset(path)
  10. # If `cache` is not set, return fast
  11. if cache.nil?
  12. yield
  13. # Check cache for `path`
  14. elsif (asset = Asset.from_hash(self, cache_get_hash(path.to_s))) && asset.fresh?(self)
  15. asset
  16. # Otherwise yield block that slowly finds and builds the asset
  17. elsif asset = yield
  18. hash = {}
  19. asset.encode_with(hash)
  20. # Save the asset to its path
  21. cache_set_hash(path.to_s, hash)
  22. # Since path maybe a logical or full pathname, save the
  23. # asset its its full path too
  24. if path.to_s != asset.pathname.to_s
  25. cache_set_hash(asset.pathname.to_s, hash)
  26. end
  27. asset
  28. end
  29. end
  30. private
  31. # Strips `Environment#root` from key to make the key work
  32. # consisently across different servers. The key is also hashed
  33. # so it does not exceed 250 characters.
  34. def expand_cache_key(key)
  35. File.join('sprockets', digest_class.hexdigest(key.sub(root, '')))
  36. end
  37. def cache_get_hash(key)
  38. hash = cache_get(expand_cache_key(key))
  39. if hash.is_a?(Hash) && digest.hexdigest == hash['_version']
  40. hash
  41. end
  42. end
  43. def cache_set_hash(key, hash)
  44. hash['_version'] = digest.hexdigest
  45. cache_set(expand_cache_key(key), hash)
  46. hash
  47. end
  48. # Low level cache getter for `key`. Checks a number of supported
  49. # cache interfaces.
  50. def cache_get(key)
  51. # `Cache#get(key)` for Memcache
  52. if cache.respond_to?(:get)
  53. cache.get(key)
  54. # `Cache#[key]` so `Hash` can be used
  55. elsif cache.respond_to?(:[])
  56. cache[key]
  57. # `Cache#read(key)` for `ActiveSupport::Cache` support
  58. elsif cache.respond_to?(:read)
  59. cache.read(key)
  60. else
  61. nil
  62. end
  63. end
  64. # Low level cache setter for `key`. Checks a number of supported
  65. # cache interfaces.
  66. def cache_set(key, value)
  67. # `Cache#set(key, value)` for Memcache
  68. if cache.respond_to?(:set)
  69. cache.set(key, value)
  70. # `Cache#[key]=value` so `Hash` can be used
  71. elsif cache.respond_to?(:[]=)
  72. cache[key] = value
  73. # `Cache#write(key, value)` for `ActiveSupport::Cache` support
  74. elsif cache.respond_to?(:write)
  75. cache.write(key, value)
  76. end
  77. value
  78. end
  79. end
  80. end