httparty-cache 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ff16750de74919a4428091908be24f05775deded7885af69960c38265ee1679b
4
+ data.tar.gz: 12ccabffc3f4d24dfeef6327a3ac5649560b275051840826f31c3482e2075b2d
5
+ SHA512:
6
+ metadata.gz: f2d9b8a53ed1ef26b0ab22dc64108ea69cecfc76c13505b4d184e2df0823ddb78857ccf815152bc1adf202a94a0b1a3010af4c7714012842f675ee3428c6109e
7
+ data.tar.gz: 5b33148ca9f3d650218f66ca59964c04c91e87dfa730f8cd997aaad87fe36d19decdf1833463512ecc3f457cbe1bb8b5fbe7c5f4527325fe686cde1718b335e7
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # HTTParty cache
2
+
3
+ Implements [HTTP caching][] support to [HTTParty][] requests by following
4
+ servers' headers such as [Cache-Control][], specifically the `max-age`,
5
+ `must-revalidate` and`no-cache` directives, [Vary][], [ETag][],
6
+ [Last-Modified][] to perform response [validation][].
7
+
8
+ [HTTP caching]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
9
+ [Cache-Control]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/cache-control
10
+ [Vary]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/vary
11
+ [ETag]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/etag
12
+ [Last-Modified]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/last-modified
13
+ [validation]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#validation
14
+ [HTTParty]: https://github.com/jnunemaker/httparty
15
+
16
+ ## Use
17
+
18
+ Add this gem to your `Gemfile` and install dependencies.
19
+
20
+ Configure your `HTTParty` client to use a cache store and perform
21
+ caching:
22
+
23
+ ```ruby
24
+ require 'httparty'
25
+ require 'httparty/cache'
26
+
27
+ class Client
28
+ include HTTParty
29
+ include HTTParty::Cache
30
+
31
+ caching true
32
+ cache_store :memory
33
+ end
34
+ ```
35
+
36
+ ### Cache stores
37
+
38
+ #### Redis
39
+
40
+ If you want to use Redis as a cache store:
41
+
42
+ 1. Add `redis-client` and optionally `hiredis-client` gems to your
43
+ `Gemfile`.
44
+
45
+ 2. Set the environment variable `REDIS_URL` with the server URL, or
46
+ initialize the cache store with a custom URL.
47
+
48
+ ```ruby
49
+ require 'httparty'
50
+ require 'httparty/cache'
51
+ require 'httparty/cache/store/redis'
52
+
53
+ class Client
54
+ include HTTParty
55
+ include HTTParty::Cache
56
+
57
+ caching true
58
+ cache_store :redis
59
+ # or
60
+ cache_store HTTParty::Cache::Store::Redis.new(redis_url: 'redis://redis.provider:6379')
61
+ end
62
+ ```
63
+
64
+ #### Jekyll
65
+
66
+ If you want to use Jekyll as a cache store, for instance while writing
67
+ a plugin using HTTParty:
68
+
69
+ ```ruby
70
+ require 'httparty'
71
+ require 'httparty/cache'
72
+ require 'httparty/cache/store/jekyll'
73
+
74
+ class Client
75
+ include HTTParty
76
+ include HTTParty::Cache
77
+
78
+ caching true
79
+ cache_store :jekyll
80
+ # or
81
+ cache_store HTTParty::Cache::Store::Jekyll.new(name: 'My::Jekyll::Cache')
82
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTParty
4
+ module Cache
5
+ # Extends HTTParty::Request with caching methods
6
+ #
7
+ # @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching}
8
+ module Request
9
+ CACHE_REVALIDATION_HEADERS = {
10
+ 'ETag' => 'If-None-Match',
11
+ 'Last-Modified' => 'If-Modified-Since'
12
+ }.freeze
13
+
14
+ # Calculates a cache key from URI + query string + headers
15
+ #
16
+ # @return [String]
17
+ def cache_key
18
+ @cache_key ||= "request:#{uri}##{URI.encode_www_form(options[:headers] || {})}"
19
+ end
20
+
21
+ def validate
22
+ super
23
+
24
+ raise ArgumentError, 'Caching is enabled but store was not provided' if caching? && cache_store.nil?
25
+ end
26
+
27
+ # Patch HTTParty::Request#perform to provide caching for GET
28
+ # requests
29
+ #
30
+ # @return [HTTParty::Response]
31
+ def perform(&block)
32
+ return super(&block) unless caching? && http_method == Net::HTTP::Get
33
+
34
+ if cached?
35
+ handle_revalidation
36
+ else
37
+ super(&block).tap do |response|
38
+ # Point current request to cached response
39
+ cache_store.set(response.cache_key, response)
40
+ cache_store.set(cache_key, response.cache_key)
41
+ end
42
+ end
43
+ end
44
+
45
+ # When the request is performed for the first time or has been
46
+ # evicted from cache or is corrupted
47
+ #
48
+ # @return [Bool]
49
+ def cached?
50
+ cache_store.key?(cache_key) &&
51
+ cache_store.key?(cache_store.get(cache_key)) &&
52
+ cache_store.get(cache_store.get(cache_key)).is_a?(HTTParty::Response)
53
+ end
54
+
55
+ def caching?
56
+ !!options[:caching]
57
+ end
58
+
59
+ private
60
+
61
+ # Revalidates request
62
+ #
63
+ # @return [HTTParty::Response]
64
+ def handle_revalidation
65
+ cached_response = cache_store.get(cache_store.get(cache_key))
66
+
67
+ if cached_response.revalidate? || cached_response.stale?
68
+ self.http_method = Net::HTTP::Head
69
+ options[:cached_response] = cached_response
70
+
71
+ add_cache_revalidation_headers
72
+
73
+ response = perform
74
+
75
+ if response.not_modified?
76
+ cached_response.headers['date'] = response.headers['date']
77
+ response = cached_response
78
+ else
79
+ self.http_method = Net::HTTP::Get
80
+ # Remove from cache so we can perform the request, otherwise
81
+ # we produce an infinite loop
82
+ cache_store.delete(cache_key)
83
+ response = perform
84
+ end
85
+
86
+ cache_store.set(response.cache_key, response)
87
+ response
88
+ else
89
+ cached_response
90
+ end
91
+ end
92
+
93
+ # Just a shortcut
94
+ def cache_store
95
+ options[:cache_store]
96
+ end
97
+
98
+ # Adds revalidation headers unless they're already present
99
+ #
100
+ # @return [nil]
101
+ def add_cache_revalidation_headers
102
+ options[:headers] ||= {}
103
+
104
+ CACHE_REVALIDATION_HEADERS.each_pair do |original_header, revalidation_header|
105
+ next if (value = options[:cached_response].headers[original_header]).nil?
106
+
107
+ options[:headers][revalidation_header] ||= value
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ # Patch HTTParty::Request
115
+ HTTParty::Request.class_eval do
116
+ prepend HTTParty::Cache::Request
117
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTParty
4
+ module Cache
5
+ # Extends HTTParty::Response with caching methods
6
+ #
7
+ # @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching}
8
+ module Response
9
+ # Detects if response is cached
10
+ def cached?
11
+ code == 304
12
+ end
13
+
14
+ # Parses Cache-Control headers
15
+ #
16
+ # @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/cache-control}
17
+ # @return [Hash]
18
+ def cache_control
19
+ @cache_control ||= headers['Cache-Control'].to_s.downcase.split(',').map(&:strip).map do |c|
20
+ k, v = c.split('=', 2).map(&:strip)
21
+
22
+ [k.tr('-', '_').to_sym, (v ? Integer(v) : true)]
23
+ end.to_h
24
+ end
25
+
26
+ # Returns the request date
27
+ #
28
+ # @return [Time]
29
+ def date
30
+ Time.parse(headers['date'])
31
+ rescue TypeError, ArgumentError
32
+ raise HTTParty::ResponseError, response
33
+ end
34
+
35
+ # Returns the current age of the request in seconds
36
+ #
37
+ # @return [Integer]
38
+ def age
39
+ (Time.now - date).to_i
40
+ rescue HTTParty::ResponseError
41
+ 0
42
+ end
43
+
44
+ # The response is stale when it has been cached for more than the
45
+ # allowed max age
46
+ #
47
+ # @return [Bool]
48
+ def stale?
49
+ !cache_control[:max_age].nil? && age > cache_control[:max_age]
50
+ end
51
+
52
+ # Detects if the response must be revalidated even if still fresh.
53
+ #
54
+ # @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#force_revalidation}
55
+ # @return [Bool]
56
+ def revalidate?
57
+ !!(cache_control[:no_cache] || (cache_control[:max_age]&.zero? && cache_control[:must_revalidate]))
58
+ end
59
+
60
+ # Returns the request headers that vary responses
61
+ #
62
+ # @return [Hash]
63
+ def vary
64
+ @vary ||= request.options[:headers].to_h.slice(*headers['Vary'].to_s.split(',').map(&:strip).sort)
65
+ end
66
+
67
+ # Generates a cache key
68
+ #
69
+ # @return [String]
70
+ def cache_key
71
+ @cache_key ||= "response:#{request.uri}##{URI.encode_www_form vary}"
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ # Patch HTTParty::Response
78
+ HTTParty::Response.include HTTParty::Cache::Response
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTParty
4
+ module Cache
5
+ module Store
6
+ # Cache store
7
+ class Abstract
8
+ # @return [Hash]
9
+ attr_reader :options
10
+
11
+ # @param :key [String]
12
+ # @return [Response,nil]
13
+ def get(key)
14
+ raise NotImplementedError
15
+ end
16
+
17
+ # @param :key [String]
18
+ # @param :response [Response]
19
+ # @return [Response]
20
+ def set(key, response)
21
+ raise NotImplementedError
22
+ end
23
+
24
+ # @param :key [String]
25
+ # @return nil
26
+ def delete(key)
27
+ raise NotImplementedError
28
+ end
29
+
30
+ # @param :key [String]
31
+ # @yield
32
+ def getset(key, &block)
33
+ raise NotImplementedError
34
+ end
35
+
36
+ # @param :key [String]
37
+ # @return [Boolean]
38
+ def key?(key)
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def clear
43
+ raise NotImplementedError
44
+ end
45
+
46
+ def marshal_dump
47
+ [
48
+ self.class.name,
49
+ options || {}
50
+ ]
51
+ end
52
+
53
+ def marshal_load(array)
54
+ Object.const_get(array.first).new(**array.last)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract'
4
+ require 'jekyll/cache'
5
+
6
+ module HTTParty
7
+ module Cache
8
+ module Store
9
+ class Jekyll < Abstract
10
+ extend Forwardable
11
+
12
+ def_delegators :@store, :key?, :delete, :clear, :getset
13
+
14
+ # @return [Hash]
15
+ attr_reader :options
16
+
17
+ # @param :name [String]
18
+ def initialize(name: self.class.name)
19
+ @options = {}
20
+ @options[:name] = name
21
+ @store = ::Jekyll::Cache.new(name)
22
+ end
23
+
24
+ def set(key, response)
25
+ @store[key] = response
26
+ response
27
+ end
28
+
29
+ def get(key)
30
+ @store[key]
31
+ rescue RuntimeError
32
+ nil
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract'
4
+
5
+ module HTTParty
6
+ module Cache
7
+ module Store
8
+ class Memory < Abstract
9
+ extend Forwardable
10
+
11
+ attr_reader :store
12
+
13
+ def_delegator :@store, :[], :get
14
+ def_delegator :@store, :[]=, :set
15
+
16
+ def_delegators :@store, :key?, :delete
17
+
18
+ def initialize(**)
19
+ clear
20
+ end
21
+
22
+ def getset(key)
23
+ store[key] ||= yield
24
+ end
25
+
26
+ def clear
27
+ @store = {}
28
+ nil
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'abstract'
4
+ require 'redis-client'
5
+
6
+ begin
7
+ require 'hiredis-client'
8
+ RedisClient.default_driver = :hiredis
9
+ rescue LoadError
10
+ end
11
+
12
+ module HTTParty
13
+ module Cache
14
+ module Store
15
+ class Redis < Abstract
16
+ # A Marshaled `nil` value
17
+ NIL = "\x04\b0"
18
+
19
+ # @return [Hash]
20
+ attr_reader :options
21
+
22
+ # @param :redis_url [String]
23
+ def initialize(redis_url: nil)
24
+ @options = {}
25
+ @options[:redis_url] = redis_url || ENV['REDIS_URL']
26
+ @config = RedisClient.config(url: @options[:redis_url])
27
+ @redis = @config.new_pool(size: 2)
28
+ @redis.call('PING')
29
+ end
30
+
31
+ # Retrieves a key
32
+ #
33
+ # @param :key [String]
34
+ # @return [Response,nil]
35
+ def get(key)
36
+ Marshal.load(redis('GET', key) || NIL)
37
+ end
38
+
39
+ # Stores a Marshaled value indexed by a key.
40
+ #
41
+ # @param :key [String]
42
+ # @param :response [Response]
43
+ # @return [Response]
44
+ def set(key, response)
45
+ redis('SET', key, Marshal.dump(response))
46
+ response
47
+ end
48
+
49
+ # Returns a key or set its value to a block result
50
+ #
51
+ # @param :key [String]
52
+ # @return [Response,nil]
53
+ def getset(key)
54
+ return get(key) if key?(key)
55
+
56
+ set(key, yield)
57
+ end
58
+
59
+ # Removes a key from Redis
60
+ #
61
+ # @param :key [String]
62
+ # @return [nil]
63
+ def delete(key)
64
+ redis('DEL', key)
65
+ nil
66
+ end
67
+
68
+ # Discovers if a key exists
69
+ #
70
+ # @param :key [String]
71
+ # @return [Boolean]
72
+ def key?(key)
73
+ redis('EXISTS', key).positive?
74
+ end
75
+
76
+ def clear
77
+ redis('FLUSHALL', 'SYNC')
78
+ nil
79
+ end
80
+
81
+ private
82
+
83
+ # Execs Redis commands and collects stats
84
+ def redis(*args)
85
+ @redis.call(*args)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTParty
4
+ module Cache
5
+ module Store
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTParty
4
+ # HTTParty plugin to manage cache
5
+ module Cache
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+
9
+ require_relative 'cache/response'
10
+ require_relative 'cache/request'
11
+ end
12
+
13
+ module ClassMethods
14
+ # This is both a setter and a getter...
15
+ #
16
+ # @param :cache_store [Symbol,HTTParty::Cache::Store::Abstract]
17
+ # @return [HTTParty::Cache::Store::Abstract]
18
+ def cache_store(cache_store = nil)
19
+ case cache_store
20
+ when NilClass
21
+ return default_options[:cache_store]
22
+ when Symbol
23
+ require_relative "cache/store/#{cache_store}"
24
+
25
+ class_name = cache_store.to_s.split('_').map(&:capitalize).join
26
+ cache_store = Object.const_get("HTTParty::Cache::Store::#{class_name}").new
27
+ end
28
+
29
+ default_options[:cache_store] = cache_store
30
+ end
31
+
32
+ # Toggle caching
33
+ #
34
+ # @param :caching [Bool]
35
+ # @return [Bool]
36
+ def caching(caching)
37
+ default_options[:caching] = caching
38
+ end
39
+
40
+ # Sets cache_control
41
+ def cache_control(cache_control)
42
+ default_options[:cache_control] = cache_control
43
+ end
44
+ end
45
+ end
46
+ end
metadata ADDED
@@ -0,0 +1,259 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: httparty-cache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - f
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-01-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.18'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.18'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: factory_bot
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.6'
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 3.6.0
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '3.6'
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 3.6.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec-tap-formatters
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: yard
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: hiredis-client
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: 0.14.0
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: 0.14.0
131
+ - !ruby/object:Gem::Dependency
132
+ name: redis-client
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: 0.14.0
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: 0.14.0
145
+ - !ruby/object:Gem::Dependency
146
+ name: rubocop
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ - !ruby/object:Gem::Dependency
160
+ name: timecop
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ - !ruby/object:Gem::Dependency
174
+ name: jekyll
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ - !ruby/object:Gem::Dependency
188
+ name: webmock
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: '1.24'
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: 1.24.3
197
+ type: :development
198
+ prerelease: false
199
+ version_requirements: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - "~>"
202
+ - !ruby/object:Gem::Version
203
+ version: '1.24'
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: 1.24.3
207
+ description: A cache manager for HTTParty
208
+ email:
209
+ - f@sutty.nl
210
+ executables: []
211
+ extensions: []
212
+ extra_rdoc_files:
213
+ - README.md
214
+ files:
215
+ - README.md
216
+ - lib/httparty/cache.rb
217
+ - lib/httparty/cache/request.rb
218
+ - lib/httparty/cache/response.rb
219
+ - lib/httparty/cache/store.rb
220
+ - lib/httparty/cache/store/abstract.rb
221
+ - lib/httparty/cache/store/jekyll.rb
222
+ - lib/httparty/cache/store/memory.rb
223
+ - lib/httparty/cache/store/redis.rb
224
+ homepage: https://0xacab.org/sutty/httparty-cache
225
+ licenses:
226
+ - MIT
227
+ metadata:
228
+ bug_tracker_uri: https://0xacab.org/sutty/httparty-cache/issues
229
+ homepage_uri: https://0xacab.org/sutty/httparty-cache
230
+ source_code_uri: https://0xacab.org/sutty/httparty-cache
231
+ changelog_uri: https://0xacab.org/sutty/httparty-cache/-/blob/master/CHANGELOG.md
232
+ documentation_uri: https://rubydoc.info/gems/httparty-cache
233
+ post_install_message:
234
+ rdoc_options:
235
+ - "--title"
236
+ - httparty-cache - HTTParty cache
237
+ - "--main"
238
+ - README.md
239
+ - "--line-numbers"
240
+ - "--inline-source"
241
+ - "--quiet"
242
+ require_paths:
243
+ - lib
244
+ required_ruby_version: !ruby/object:Gem::Requirement
245
+ requirements:
246
+ - - ">="
247
+ - !ruby/object:Gem::Version
248
+ version: '2.7'
249
+ required_rubygems_version: !ruby/object:Gem::Requirement
250
+ requirements:
251
+ - - ">="
252
+ - !ruby/object:Gem::Version
253
+ version: '0'
254
+ requirements: []
255
+ rubygems_version: 3.3.26
256
+ signing_key:
257
+ specification_version: 4
258
+ summary: HTTParty cache
259
+ test_files: []