fulfil-io 0.4.7 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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