diff --git a/Rakefile b/Rakefile index b56c17b..a1819e1 100644 --- a/Rakefile +++ b/Rakefile @@ -2,6 +2,16 @@ require 'bundler/gem_tasks' require 'rspec/core/rake_task' +require 'rubocop' +require 'rubocop-rspec' +require 'rubocop/rake_task' + +RuboCop::RakeTask.new(:rubocop) do |t| + config_path = File.expand_path(File.join('.rubocop.yml'), __dir__) + + t.options = ['--config', config_path] + t.requires << 'rubocop-rspec' +end RSpec::Core::RakeTask.new(:rspec) diff --git a/lib/any_cache.rb b/lib/any_cache.rb index e1f1400..2a200d2 100644 --- a/lib/any_cache.rb +++ b/lib/any_cache.rb @@ -8,6 +8,7 @@ # @since 0.1.0 class AnyCache require_relative 'any_cache/version' + require_relative 'any_cache/error' require_relative 'any_cache/drivers' require_relative 'any_cache/adapters' diff --git a/lib/any_cache/adapters.rb b/lib/any_cache/adapters.rb index e54090d..4acdbd5 100644 --- a/lib/any_cache/adapters.rb +++ b/lib/any_cache/adapters.rb @@ -18,7 +18,7 @@ class << self # @param driver [Object] # @return [AnyCache::Adapters::Basic] # - # @raise [AnyCache::UnsupportedCacheDriverError] + # @raise [AnyCache::UnsupportedDriverError] # # @api private # @since 0.1.0 @@ -34,7 +34,7 @@ def build(driver) when ActiveSupportMemCacheStore.supported_driver?(driver) then ActiveSupportMemCacheStore.new(driver) when Delegator.supported_driver?(driver) then Delegator.new(driver) else - raise AnyCache::UnsupportedCacheDriverError + raise AnyCache::UnsupportedDriverError end end # rubocop:enable Metrics/LineLength diff --git a/spec/features/custom_cache_clients_spec.rb b/spec/features/custom_cache_clients_spec.rb new file mode 100644 index 0000000..b230484 --- /dev/null +++ b/spec/features/custom_cache_clients_spec.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +describe 'Custom cache clients' do + context 'when custom cache clinet supports all required methods' do + let(:custom_client) do + Class.new do + # rubocop:disable Layout/EmptyLineBetweenDefs + def read(key, **); end + def write(key, value, **); end + def delete(key, **); end + def increment(key, value, **); end + def decrement(key, value, **); end + def expire(key, **); end + def persist(key, **); end + def clear(key, **); end + def exist?(key, **); end + # rubocop:enable Layout/EmptyLineBetweenDefs + end.new + end + + let(:dumb_client) do + # rubocop:disable Layout/EmptyLineBetweenDefs + Class.new do + def read; end + def write; end + def delete; end + def increment; end + def decrement; end + def expire; end + def persist; end + def clear; end + def exist?; end + end.new + # rubocop:enable Layout/EmptyLineBetweenDefs + end + + specify 'returns AnyCache instance' do + expect(AnyCache.build(custom_client)).to be_a(AnyCache) + end + + specify 'requires only a delegation' do + expect(AnyCache.build(dumb_client)).to be_a(AnyCache) + end + + %i[ + read + delete + expire + persist + clear + exist? + ].each do |operation| + specify "AnyCache instance delegates :#{operation} operation to the custom client" do + cache_store = AnyCache.build(custom_client) + + entry_key = SecureRandom.hex + method_options = { SecureRandom.hex.to_sym => SecureRandom.hex } + + expect(custom_client).to receive(operation).with(entry_key, method_options) + cache_store.send(operation, entry_key, **method_options) + end + end + + %i[ + write + increment + decrement + ].each do |operation| + specify "AnyCache instance delegates :#{operation} operation to the custom client" do + cache_store = AnyCache.build(custom_client) + + entry_key = SecureRandom.hex + method_value = SecureRandom.hex + method_options = { SecureRandom.hex.to_sym => SecureRandom.hex } + + expect(custom_client).to receive(operation).with(entry_key, method_value, method_options) + cache_store.send(operation, entry_key, method_value, **method_options) + end + end + end + + context 'when custom cache client supports a part of required methods' do + let(:required_methods) do + %i[ + read + write + delete + increment + decrement + expire + persist + clear + exist? + ] + end + + specify 'fails due to instantiation' do + while required_methods.shift + incomplete_cache_client = Class.new.tap do |klass| + required_methods.each do |required_method| + klass.define_method(required_method) {} + end + end.new + + expect do + AnyCache.build(incomplete_cache_client) + end.to raise_error(AnyCache::UnsupportedDriverError) + end + end + end +end