diff --git a/README.md b/README.md index 65adf926..c5de4aac 100644 --- a/README.md +++ b/README.md @@ -226,27 +226,63 @@ Typhoeus includes built in support for caching. In the following example, if the ```ruby class Cache - attr_accessor :memory - def initialize @memory = {} end def get(request) - memory[request] + @memory[request] end def set(request, response) - memory[request] = response + @memory[request] = response end end Typhoeus::Config.cache = Cache.new -Typhoeus.get("www.example.com") == Typhoeus.get("www.example.com") +Typhoeus.get("www.example.com").cached? +#=> false +Typhoeus.get("www.example.com").cached? #=> true ``` +For use with [Dalli](https://github.com/mperham/dalli): + +```ruby +class Cache + def initialize + @client = Dalli::Client.new + end + + def get(request) + @client.get(request.cache_key) + end + + def set(request, response) + @client.set(request.cache_key, response) + end +end + +Typhoeus::Config.cache = Cache.new +``` + +For use with Rails: + +```ruby +class Cache + def get(request) + Rails.cache.read(request) + end + + def set(request, response) + Rails.cache.write(request, response) + end +end + +Typhoeus::Config.cache = Cache.new +``` + ### Direct Stubbing Hydra allows you to stub out specific urls and patterns to avoid hitting diff --git a/lib/typhoeus/request.rb b/lib/typhoeus/request.rb index 43ee4f9c..321974ff 100644 --- a/lib/typhoeus/request.rb +++ b/lib/typhoeus/request.rb @@ -154,7 +154,15 @@ def eql?(other) # # @api private def hash - Zlib.crc32 "#{self.class.name}#{base_url}#{options}" + Zlib.crc32 cache_key + end + + # Returns a cache key for use with caching methods that required a string + # for a key. Will get used by ActiveSupport::Cache stores automatically. + # + # @return [ String ] The cache key. + def cache_key + "#{self.class.name}#{base_url}#{hashable_string_for(options)}" end # Mimics libcurls POST body generation. This is not accurate, but good @@ -187,6 +195,17 @@ def fuzzy_hash_eql?(left, right) end end + def hashable_string_for(obj) + case obj + when Hash + hashable_string_for(obj.sort_by {|sub_obj| sub_obj.first.to_s}) + when Array + obj.map {|sub_obj| hashable_string_for(sub_obj)}.to_s + else + obj.to_s + end + end + # Sets default header and verbose when turned on. def set_defaults if @options[:headers] diff --git a/spec/typhoeus/request_spec.rb b/spec/typhoeus/request_spec.rb index 38fb295b..1a39f861 100644 --- a/spec/typhoeus/request_spec.rb +++ b/spec/typhoeus/request_spec.rb @@ -143,15 +143,37 @@ describe "#hash" do context "when request.eql?(other)" do - let(:other) { Typhoeus::Request.new(base_url, options) } + context "when different order" do + let(:other_options) { + {:headers => { 'User-Agent' => "Fubar" }, :verbose => true } + } + let(:other) { Typhoeus::Request.new(base_url, other_options)} + + it "has same hashes" do + expect(request.hash).to eq(other.hash) + end + end - it "has same hashes" do - expect(request.hash).to eq(other.hash) + context "when same order" do + let(:other) { Typhoeus::Request.new(base_url, options) } + + it "has same hashes" do + expect(request.hash).to eq(other.hash) + end + end + + context "when hashes with different orders are contained in arrays" do + let(:request) { Typhoeus::Request.new(base_url, :params => [{:b => 2, :a => 1}]) } + let(:other) { Typhoeus::Request.new(base_url, :params => [{:a => 1, :b => 2}]) } + it "has different hashes" do + expect(request.hash).to eq(other.hash) + end end end context "when not request.eql?(other)" do - let(:other) { Typhoeus::Request.new("base_url", {}) } + let(:request) { Typhoeus::Request.new(base_url, :params => {:foo => 'bar'}) } + let(:other) { Typhoeus::Request.new(base_url, :params => {:foo => 'baz'}) } it "has different hashes" do expect(request.hash).to_not eq(other.hash)