lib/roadie/cached_provider.rb
# frozen_string_literal: true
module Roadie
# @api public
# The {CachedProvider} wraps another provider (or {ProviderList}) and caches
# the response from it.
#
# The default cache store is a instance-specific hash that lives for the
# entire duration of the instance. If you want to share hash between
# instances, pass your own hash-like object. Just remember to not allow this
# cache to grow without bounds, which a shared hash would do.
#
# Not found assets are not cached currently, but it's possible to extend this
# class in the future if there is a need for it. Remember this if you have
# providers with very slow failures.
#
# The cache store must accept {Roadie::Stylesheet} instances, and return such
# instances when fetched. It must respond to `#[name]` and `#[name]=` to
# retrieve and set entries, respectively. The `#[name]=` method also needs to
# return the instance again.
#
# @example Global cache
# Application.asset_cache = Hash.new
# slow_provider = MyDatabaseProvider.new(Application)
# provider = Roadie::CachedProvider.new(slow_provider, Application.asset_cache)
#
# @example Custom cache store
# class MyRoadieMemcacheStore
# def initialize(memcache)
# @memcache = memcache
# end
#
# def [](path)
# css = memcache.read("assets/#{path}/css")
# if css
# name = memcache.read("assets/#{path}/name") || "cached #{path}"
# Roadie::Stylesheet.new(name, css)
# end
# end
#
# def []=(path, stylesheet)
# memcache.write("assets/#{path}/css", stylesheet.to_s)
# memcache.write("assets/#{path}/name", stylesheet.name)
# stylesheet # You need to return the set Stylesheet
# end
# end
#
class CachedProvider
# The cache store used by this instance.
attr_reader :cache
# @param upstream [an asset provider] The wrapped asset provider
# @param cache [#[], #[]=] The cache store to use.
def initialize(upstream, cache = {})
@upstream = upstream
@cache = cache
end
def find_stylesheet(name)
cache_fetch(name) do
@upstream.find_stylesheet(name)
end
end
def find_stylesheet!(name)
cache_fetch(name) do
@upstream.find_stylesheet!(name)
end
end
private
def cache_fetch(name)
cache[name] || cache[name] = yield
rescue CssNotFound
cache[name] = nil
raise
end
end
end