fulfil-io 0.4.7 → 0.6.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21d5119cc38db9e9a414775dcfc9b37d53ca5fa3ff05218c4ae81bbc912d0695
4
- data.tar.gz: a4bf8e9ae17a2993c1a3644d298e39f71c78b1eddc40f6bb20d35bdb25ad1ba5
3
+ metadata.gz: 0c58e4104ae9106550bca7c000cbf3f576f551c9e4512cee93dc74dd0aa5604f
4
+ data.tar.gz: ee0644f88360b5356efa034833772a54d207ce4be7e81040219e8d66019ff301
5
5
  SHA512:
6
- metadata.gz: b1fc2fe57cb22c234b12ffe3c0182030baa3be525971eaa7a2f21470e36f5ef9f6957919ba3675574c1159c79ff3b40f28b11167927ce8f852e70fed667f01b3
7
- data.tar.gz: 1406056b1b4f566163829b91dd96822c1705286528581567f74d1c383146652a10e0788fd1b80bab81fa79088a32a65440c72483f70fc8c22ae073e9115f19fa
6
+ metadata.gz: d697a2153dcbcd379621b59bc7ef8af428c4f6ecc2445d454afc38eddb34247430279136f758fe52e538abcda923c386dbc4d7f2af00c27e9e41c26f71a4c5e2
7
+ data.tar.gz: e6e891f839dd472f24f1dc89ce1189cb80b9218ac09c35c4141c0dd0b575097ecb0d238d47de8e688bc69c3298da0f4e1b2478ebfed1010d139c3fb4087f0ccf
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.4.9
2
+
3
+ * Add client tests and stub with Webmock.
4
+
5
+ ## 0.4.8
6
+
7
+ * Feature: Allow more params with InteractiveReport.
8
+
1
9
  ## 0.4.7
2
10
 
3
11
  * Bugfix: Accidentally removed the model parameter from the URL.
data/README.md CHANGED
@@ -1,36 +1,40 @@
1
- # Fulfil.io Rubygem
1
+ [![Tests](https://github.com/knowndecimal/fulfil/actions/workflows/tests.yml/badge.svg)](https://github.com/knowndecimal/fulfil/actions/workflows/tests.yml)
2
2
 
3
- [![CircleCI](https://circleci.com/gh/knowndecimal/fulfil.svg?style=svg&circle-token=da80ea6500af15b3a795a3913efe35742bab94c1)](https://circleci.com/gh/knowndecimal/fulfil)
3
+ # Fulfil.io Rubygem
4
4
 
5
- [Fulfil.io](https://fulfil.io)
5
+ A Ruby library for the [Fulfil.io](https://fulfil.io) API.
6
6
 
7
7
  ## Installation
8
8
 
9
9
  Add this line to your application's Gemfile:
10
10
 
11
11
  ```ruby
12
- gem 'fulfil-io', require: 'fulfil'
12
+ gem 'fulfil-io', require: 'fulfil'
13
13
  ```
14
14
 
15
15
  And then execute:
16
16
 
17
- $ bundle install
17
+ ```shell
18
+ $ bundle install
19
+ ```
18
20
 
19
21
  Or install it yourself as:
20
22
 
21
- $ gem install fulfil-io
23
+ ```shell
24
+ $ gem install fulfil-io
25
+ ```
22
26
 
23
27
  ## Usage
24
28
 
25
29
  Environment variables:
26
30
 
27
- - FULFIL_SUBDOMAIN - required to be set.
28
- - FULFIL_TOKEN - required for oauth bearer authentication
29
- - FULFIL_API_KEY - required for authentication via the X-API-KEY request header
31
+ - **FULFIL_SUBDOMAIN:** - always required to use the gem.
32
+ - **FULFIL_OAUTH_TOKEN:** required for oauth bearer authentication
33
+ - **FULFIL_API_KEY:** required for authentication via the `X-API-KEY` request header
30
34
 
31
- **Note:** When FULFIL_TOKEN is present, the FULFIL_API_KEY will be ignored. So,
35
+ > **Note:** When `FULFIL_OAUTH_TOKEN` is present, the `FULFIL_API_KEY` will be ignored. So,
32
36
  if oauth doesn't work, returning an Unauthorized error, to use the
33
- FULFIL_API_KEY, the FULFIL_TOKEN shouldn't be specified.
37
+ `FULFIL_API_KEY`, the `FULFIL_OAUTH_TOKEN` shouldn't be specified.
34
38
 
35
39
  ```ruby
36
40
  require 'fulfil' # this is necessary only in case of running without bundler
@@ -123,16 +127,74 @@ report = Fulfil::Report.new(client: fulfil, report_name: 'account.tax.summary.ir
123
127
  report.execute(start_date: Date.new(2020, 12, 1), end_date: Date.new(2020, 12, 31))
124
128
  ```
125
129
 
130
+ ## Rate limits
131
+
132
+ Fulfil's API applies rate limits to the API requests that it receives. Every request is subject to throttling under the general limits. In addition, there are resource-based rate limits and throttles.
133
+
134
+ This gem exposes an API for checking your current rate limits (note: the gem only knows about the rate limit after a request to Fulfil's API has been made).
135
+
136
+ Whenever you reached the rate limit, the `Fulfil::RateLimitExceeded` exception is being raised. You can use the information on the `Fulfil.rate_limit` to find out what to do next.
137
+
138
+ ```ruby
139
+ $ Fulfil.rate_limit.requests_left?
140
+ => true
141
+
142
+ # The maximum number of requests you're permitted to make per second.
143
+ $ Fulfil.rate_limit.limit
144
+ => 9
145
+
146
+ # The time at which the current rate limit window resets in UTC epoch seconds.
147
+ $ Fulfil.rate_limit.resets_at
148
+ => #<DateTime: 2022-01-21T16:36:01-04:00 />
149
+ ```
126
150
  ## Development
127
151
 
128
152
  After checking out the repo, run `bin/setup` to install dependencies. Then, run
129
153
  `rake test` to run the tests. You can also run `bin/console` for an interactive
130
154
  prompt that will allow you to experiment.
131
155
 
132
- To install this gem onto your local machine, run `bundle exec rake install`. To
133
- release a new version, update the version number in `version.rb`, and then run
134
- `bundle exec rake release`, which will create a git tag for the version, push
135
- git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
156
+ To install this gem onto your local machine, run `bundle exec rake install`.
157
+
158
+ ### Release a new version
159
+
160
+ We're following semver for the release process of this gem. Make sure to apply the correct semver version for a new release.
161
+
162
+ To release a new version, run the `bin/release x.x.x`. That's it.
163
+
164
+ > **NOTE:** You don't have to add a v to the version you want to release. The release script will handle that for you.
165
+
166
+ ### Testing
167
+
168
+ For non-client tests, create the test class or case.
169
+
170
+ For client tests, you'll need to add a couple steps. If running against a real
171
+ backend, you'll need to provide a couple of environment variables:
172
+ `FULFIL_SUBDOMAIN` and `FULFIL_OAUTH_TOKEN`. Additionally, pass `debug: true` to the
173
+ client instance in the test. This will output the response body. Webmock will
174
+ probably complain that real requests aren't allowed at this point, offering you
175
+ the stub. We don't need most of that.
176
+
177
+ We will need to capture the response body as JSON and store it in the
178
+ `test/fixtures` directory. Formatted for readability, please. You'll also need
179
+ to make note of the path and body of the request. Once you have that, you can
180
+ generate your stub.
181
+
182
+ To stub a request, use (or create) the helper method based on the verb. For
183
+ example, to stub a `GET` request, use `stub_fulfil_get`. Here's an example:
184
+
185
+ ```ruby
186
+ def test_find_one
187
+ stub_fulfil_get('sale.sale/213112', 'sale_sale')
188
+
189
+ client = Fulfil::Client.new
190
+ response = client.find_one(model: 'sale.sale', id: 213_112)
191
+
192
+ assert_equal 213_112, response['id']
193
+ end
194
+ ```
195
+
196
+ `stub_fulfil_get` takes two arguments: the URL path (after `/api/v2/model/`)
197
+ and the fixture file name to be returned.
136
198
 
137
199
  ## Contributing
138
200
 
data/lib/fulfil/client.rb CHANGED
@@ -7,9 +7,14 @@ require 'fulfil/response_parser'
7
7
  module Fulfil
8
8
  SUBDOMAIN = ENV['FULFIL_SUBDOMAIN']
9
9
  API_KEY = ENV['FULFIL_API_KEY']
10
- OAUTH_TOKEN = ENV['FULFIL_TOKEN']
11
10
 
12
11
  class Client
12
+ class InvalidClientError < StandardError
13
+ def message
14
+ 'Client is not configured correctly.'
15
+ end
16
+ end
17
+
13
18
  class NotAuthorizedError < StandardError; end
14
19
 
15
20
  class UnknownHTTPError < StandardError; end
@@ -18,12 +23,22 @@ module Fulfil
18
23
 
19
24
  class ResponseError < StandardError; end
20
25
 
21
- def initialize(subdomain: SUBDOMAIN, token: OAUTH_TOKEN, headers: { 'X-API-KEY' => API_KEY }, debug: false)
26
+ def initialize(subdomain: SUBDOMAIN, token: oauth_token, headers: { 'X-API-KEY' => API_KEY }, debug: false)
22
27
  @subdomain = subdomain
23
28
  @token = token
24
29
  @debug = debug
25
30
  @headers = headers
26
31
  @headers.delete('X-API-KEY') if @token
32
+
33
+ raise InvalidClientError if invalid?
34
+ end
35
+
36
+ def invalid?
37
+ @subdomain.nil? || @subdomain.empty?
38
+ end
39
+
40
+ def valid?
41
+ !invalid?
27
42
  end
28
43
 
29
44
  def find(model:, ids: [], id: nil, fields: %w[id rec_name])
@@ -96,6 +111,15 @@ module Fulfil
96
111
 
97
112
  private
98
113
 
114
+ def oauth_token
115
+ if ENV['FULFIL_TOKEN']
116
+ puts "You're using an deprecated environment variable. Please update your " \
117
+ 'FULFIL_TOKEN to FULFIL_OAUTH_TOKEN.'
118
+ end
119
+
120
+ ENV['FULFIL_OAUTH_TOKEN'] || ENV['FULFIL_TOKEN']
121
+ end
122
+
99
123
  def parse(result: nil, results: [])
100
124
  if result
101
125
  parse_single(result: result)
@@ -125,19 +149,12 @@ module Fulfil
125
149
  end
126
150
 
127
151
  def request(endpoint:, verb: :get, **args)
152
+ raise InvalidClientError if invalid?
153
+
128
154
  response = client.request(verb, endpoint, args)
155
+ Fulfil::ResponseHandler.new(response).verify!
129
156
 
130
- if response.status.ok? || response.status.created?
131
- response.parse
132
- elsif response.code == 204
133
- []
134
- elsif response.code == 401
135
- error = response.parse
136
- raise NotAuthorizedError, "Not authorized: #{error['error']}: #{error['error_description']}"
137
- else
138
- puts response.body.to_s
139
- raise Error, 'Error encountered while processing response:'
140
- end
157
+ response.parse
141
158
  rescue HTTP::Error => e
142
159
  puts e
143
160
  raise UnknownHTTPError, 'Unhandled HTTP error encountered'
@@ -150,12 +167,10 @@ module Fulfil
150
167
  end
151
168
 
152
169
  def client
153
- return @client if defined?(@client)
154
-
155
- @client = HTTP.persistent(base_url).use(logging: @debug ? { logger: Logger.new(STDOUT) } : {})
156
- @client = @client.auth("Bearer #{@token}") if @token
157
- @client = @client.headers(@headers)
158
- @client
170
+ client = HTTP.use(logging: @debug ? { logger: Logger.new(STDOUT) } : {})
171
+ client = client.auth("Bearer #{@token}") if @token
172
+ client = client.headers(@headers)
173
+ client
159
174
  end
160
175
  end
161
176
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fulfil
4
+ class Error < StandardError; end
5
+
6
+ class RateLimitExceeded < Error; end
7
+
8
+ # The `Fulfil::HttpError` is raised whenever an API request returns a 400+ HTTP status code.
9
+ # See `Fulfil::ResponseHandler` for more information.
10
+ class HttpError < Error
11
+ attr_reader :metadata
12
+
13
+ def initialize(message, metadata = {})
14
+ @metadata = metadata
15
+ super(message)
16
+ end
17
+
18
+ class BadRequest < HttpError; end
19
+ class AuthorizationRequired < HttpError; end
20
+ class PaymentRequired < HttpError; end
21
+ class Forbidden < HttpError; end
22
+ class NotFound < HttpError; end
23
+ class MethodNotAllowed < HttpError; end
24
+ class NotAccepted < HttpError; end
25
+ class UnprocessableEntity < HttpError; end
26
+ class TooManyRequests < HttpError; end
27
+ class InternalServerError < HttpError; end
28
+ end
29
+ end
@@ -5,13 +5,20 @@ module Fulfil
5
5
  @report = report
6
6
  end
7
7
 
8
- def execute(start_date:, end_date:)
8
+ def execute(**params)
9
+ body = {}
10
+
11
+ params.each do |key, value|
12
+ body[key] = if value.is_a?(Date)
13
+ serialize_date(value)
14
+ else
15
+ value
16
+ end
17
+ end
18
+
9
19
  @client.interactive_report(
10
20
  endpoint: report_url,
11
- body: [{
12
- start_date: serialize_date(start_date),
13
- end_date: serialize_date(end_date)
14
- }]
21
+ body: [body]
15
22
  )
16
23
  end
17
24
 
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fulfil
4
+ # The `Fulfil::RateLimit` allows clients to keep track of their API usage and
5
+ # to analyze Fulfil's response HTTP headers.
6
+ class RateLimit
7
+ attr_accessor :limit, :requests_left, :resets_at
8
+
9
+ # Analyses the rate limit based on the response headers from Fulfil.
10
+ # @param headers [HTTP::Headers] The HTTP response headers from Fulfil.
11
+ # @return [Fulfil::RateLimit]
12
+ def analyse!(headers)
13
+ rate_limit_headers = RateLimitHeaders.new(headers)
14
+
15
+ self.limit = rate_limit_headers.limit
16
+ self.requests_left = rate_limit_headers.requests_left
17
+ self.resets_at = rate_limit_headers.resets_at
18
+
19
+ raise Fulfil::RateLimitExceeded unless requests_left?
20
+ end
21
+
22
+ # Returns whether there are any requests left in the current rate limit window.
23
+ # @return [Boolean]
24
+ def requests_left?
25
+ requests_left&.positive?
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fulfil
4
+ # The `Fulfil::RateLimitHeaders` parses Fulfil HTTP rate limit headers and
5
+ # formats them to a more usable format.
6
+ class RateLimitHeaders
7
+ # Test suites might mock (or at least should mock) the requests to Fulfil.
8
+ # However, most of these test suites will not mock the response headers.
9
+ # To make sure those test suites don't break, we're setting some defaults for them.
10
+ DEFAULT_REQUEST_LIMIT = 10
11
+ DEFAULT_REQUESTS_LEFT = 9
12
+ DEFAULT_RESETS_AT = nil
13
+
14
+ attr_reader :limit, :requests_left, :resets_at
15
+
16
+ def initialize(headers = {})
17
+ self.limit = headers['X-RateLimit-Limit'] || DEFAULT_REQUEST_LIMIT
18
+ self.requests_left = headers['X-RateLimit-Remaining'] || DEFAULT_REQUESTS_LEFT
19
+ self.resets_at = headers['X-RateLimit-Reset'] || DEFAULT_RESETS_AT
20
+ end
21
+
22
+ # Sets the maximum number of requests you're permitted to make per second.
23
+ # @param value [String] The maximum number of requests per second.
24
+ # @return [Integer] The maximum number of requests per second.
25
+ def limit=(value)
26
+ @limit = value.to_i
27
+ end
28
+
29
+ # Sets number of requests remaining in the current rate limit window.
30
+ # @param value [String] The remaining number of requests for the current time window.
31
+ # @return [Integer] The remaining number of requests for the current time window.
32
+ def requests_left=(value)
33
+ @requests_left = value.to_i
34
+ end
35
+
36
+ # Sets the time at which the current rate limit window resets in UTC epoch seconds.
37
+ # @param value [Integer|nil] Time as an integer in UTC epoch seconds.
38
+ # @return [DataTime|nil] The moment the rate limit resets.
39
+ def resets_at=(value)
40
+ @resets_at =
41
+ if value.nil?
42
+ nil
43
+ else
44
+ Time.at(value.to_i).utc.to_datetime
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fulfil
4
+ # The `Fulfil::ResponseHandler` is parses the HTTP response from Fulfil. If it
5
+ # encounters an HTTP status code that indicates an error, it will raise an internal
6
+ # exception that the consumer can catch.
7
+ #
8
+ # @example
9
+ # Fulfil::ResponseHandler.new(@response).verify!
10
+ # => true
11
+ #
12
+ # Fulfil::ResponseHandler.new(@response).verify!
13
+ # => Fulfil::Error::BadRequest
14
+ class ResponseHandler
15
+ HTTP_ERROR_CODES = {
16
+ 400 => Fulfil::HttpError::BadRequest,
17
+ 401 => Fulfil::HttpError::AuthorizationRequired,
18
+ 402 => Fulfil::HttpError::PaymentRequired,
19
+ 403 => Fulfil::HttpError::Forbidden,
20
+ 404 => Fulfil::HttpError::NotFound,
21
+ 405 => Fulfil::HttpError::MethodNotAllowed,
22
+ 406 => Fulfil::HttpError::NotAccepted,
23
+ 422 => Fulfil::HttpError::UnprocessableEntity,
24
+ 429 => Fulfil::HttpError::TooManyRequests,
25
+ 500 => Fulfil::HttpError::InternalServerError
26
+ }.freeze
27
+
28
+ def initialize(response)
29
+ @response = response
30
+ @status_code = response.code
31
+ end
32
+
33
+ def verify!
34
+ verify_rate_limits!
35
+ verify_http_status_code!
36
+ end
37
+
38
+ private
39
+
40
+ def verify_rate_limits!
41
+ Fulfil.rate_limit.analyse!(@response.headers)
42
+ end
43
+
44
+ def verify_http_status_code!
45
+ return true unless @status_code >= 400
46
+
47
+ raise HTTP_ERROR_CODES.fetch(@status_code, Fulfil::HttpError).new(
48
+ response_body['error_description'],
49
+ {
50
+ body: @response.body,
51
+ headers: @response.headers,
52
+ status: @response.status
53
+ }
54
+ )
55
+ end
56
+
57
+ def response_body
58
+ @response_body ||= @response.parse
59
+ end
60
+ end
61
+ end
@@ -41,7 +41,7 @@ module Fulfil
41
41
  def self.group(key_value_tuples)
42
42
  key_value_tuples
43
43
  .group_by { |kv_tuple| kv_tuple[0][0] }
44
- .map { |group_key, kv_tuples|
44
+ .map do |group_key, kv_tuples|
45
45
  if kv_tuples.length == 1
46
46
  [group_key, mapped_value_field(value: kv_tuples[0][1])]
47
47
  else
@@ -49,7 +49,7 @@ module Fulfil
49
49
  attrs = kv_tuples[1..-1].map { |tuple| [tuple[0][1..-1], tuple[1]] }
50
50
  [group_key, [['id', id[1]]].concat(group(attrs)).to_h]
51
51
  end
52
- }
52
+ end
53
53
  end
54
54
 
55
55
  def self.parse(item:)
@@ -57,5 +57,4 @@ module Fulfil
57
57
  group(key_value_tuples).to_h
58
58
  end
59
59
  end
60
-
61
60
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fulfil
4
- VERSION = '0.4.7'
4
+ VERSION = "0.6.0"
5
5
  end
data/lib/fulfil.rb CHANGED
@@ -1,9 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fulfil/version'
4
+ require 'fulfil/error'
2
5
  require 'fulfil/client'
3
6
  require 'fulfil/model'
4
7
  require 'fulfil/interactive_report'
8
+ require 'fulfil/response_handler'
5
9
  require 'fulfil/response_parser'
6
10
 
11
+ # Rate limiting
12
+ require 'fulfil/rate_limit'
13
+ require 'fulfil/rate_limit_headers'
14
+
7
15
  module Fulfil
8
- class Error < StandardError; end
16
+ def self.rate_limit
17
+ @rate_limit ||= RateLimit.new
18
+ end
9
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fulfil-io
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.7
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Moore
@@ -9,22 +9,28 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-11-30 00:00:00.000000000 Z
12
+ date: 2022-03-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: http
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: 4.4.1
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: 5.1.0
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
25
- - - "~>"
28
+ - - ">="
26
29
  - !ruby/object:Gem::Version
27
30
  version: 4.4.1
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: 5.1.0
28
34
  - !ruby/object:Gem::Dependency
29
35
  name: bundler
30
36
  requirement: !ruby/object:Gem::Requirement
@@ -95,6 +101,40 @@ dependencies:
95
101
  - - ">="
96
102
  - !ruby/object:Gem::Version
97
103
  version: '0'
104
+ - !ruby/object:Gem::Dependency
105
+ name: webmock
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ - !ruby/object:Gem::Dependency
119
+ name: dotenv
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.7'
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: 2.7.6
128
+ type: :development
129
+ prerelease: false
130
+ version_requirements: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - "~>"
133
+ - !ruby/object:Gem::Version
134
+ version: '2.7'
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: 2.7.6
98
138
  description:
99
139
  email:
100
140
  - chris@knowndecimal.com
@@ -111,9 +151,13 @@ files:
111
151
  - Rakefile
112
152
  - lib/fulfil.rb
113
153
  - lib/fulfil/client.rb
154
+ - lib/fulfil/error.rb
114
155
  - lib/fulfil/interactive_report.rb
115
156
  - lib/fulfil/model.rb
116
157
  - lib/fulfil/query.rb
158
+ - lib/fulfil/rate_limit.rb
159
+ - lib/fulfil/rate_limit_headers.rb
160
+ - lib/fulfil/response_handler.rb
117
161
  - lib/fulfil/response_parser.rb
118
162
  - lib/fulfil/version.rb
119
163
  homepage: https://github.com/knowndecimal/fulfil
@@ -128,14 +172,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
128
172
  requirements:
129
173
  - - ">="
130
174
  - !ruby/object:Gem::Version
131
- version: 2.3.0
175
+ version: '2.4'
132
176
  required_rubygems_version: !ruby/object:Gem::Requirement
133
177
  requirements:
134
178
  - - ">="
135
179
  - !ruby/object:Gem::Version
136
180
  version: '0'
137
181
  requirements: []
138
- rubygems_version: 3.1.6
182
+ rubygems_version: 3.3.7
139
183
  signing_key:
140
184
  specification_version: 4
141
185
  summary: Interact with the Fulfil.io API