Skip to content

Instantly share code, notes, and snippets.

@rpbaptist
Last active May 14, 2018 09:31
Show Gist options
  • Save rpbaptist/985646184fcdf1083acd1ccbb15061f7 to your computer and use it in GitHub Desktop.
Save rpbaptist/985646184fcdf1083acd1ccbb15061f7 to your computer and use it in GitHub Desktop.
A cache wrapper implementation with simple interface
# spec/support/shared/examples/cachable.rb
# frozen_string_literal: true
# Provide a simple interface for caching methods
# Usage examle:
#
# class Foo
# include Cachable
# cache :bar
#
# def bar
# # some database query method
# end
# end
module Cachable
extend ActiveSupport::Concern
CACHE_OPTIONS = {
expires_in: 1.day
}.freeze
class_methods do
def cache(*method_names, options: CACHE_OPTIONS)
cacher.module_eval do
Array(method_names).each do |method_name|
define_method(method_name) do |*args|
cached(method_name, args, options) { super(*args) }
end
end
end
prepend cacher
end
def cacher
@cacher ||= Module.new
end
end
private
def cached(method_name, args, options = CACHE_OPTIONS)
Rails.cache.fetch([self.class, method_name, args], options) do
yield
end
end
end
# spec/support/shared/examples/cachable.rb
# frozen_string_literal: true
RSpec.shared_examples "a cachable model" do
let(:rails_cache) { instance_double("ActiveSupport::Cache::NullStore") }
let(:cached_methods) { described_class.public_instance_methods(false) }
let(:model) { subject }
it "implements the .cache method" do
expect(described_class).to respond_to(:cache)
end
context "cache key" do
before do
allow(Rails).to receive(:cache).and_return(rails_cache)
allow(rails_cache).to receive(:fetch)
end
it "is generated based on object" do
expect(rails_cache).to receive(:fetch).with(
array_including(described_class),
described_class::CACHE_OPTIONS
)
model.public_send(cached_methods.first)
end
it "is generated based on method" do
cached_methods.each do |method_name|
expect(rails_cache).to receive(:fetch).with(
array_including(described_class, method_name),
described_class::CACHE_OPTIONS
)
model.public_send(method_name)
end
end
it "is generated based on arguments" do
described_class.class_eval do
define_method(:test_argument_cache_key) do |arg|
arg
end
cache :test_argument_cache_key
end
expect(rails_cache).to receive(:fetch).with(
[described_class, :test_argument_cache_key, [{ foo: "bar" }]],
described_class::CACHE_OPTIONS
)
model.test_argument_cache_key(foo: "bar")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment