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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +77 -15
- data/lib/fulfil/client.rb +34 -19
- data/lib/fulfil/error.rb +29 -0
- data/lib/fulfil/interactive_report.rb +12 -5
- data/lib/fulfil/rate_limit.rb +28 -0
- data/lib/fulfil/rate_limit_headers.rb +48 -0
- data/lib/fulfil/response_handler.rb +61 -0
- data/lib/fulfil/response_parser.rb +2 -3
- data/lib/fulfil/version.rb +1 -1
- data/lib/fulfil.rb +11 -1
- metadata +50 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c58e4104ae9106550bca7c000cbf3f576f551c9e4512cee93dc74dd0aa5604f
|
4
|
+
data.tar.gz: ee0644f88360b5356efa034833772a54d207ce4be7e81040219e8d66019ff301
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d697a2153dcbcd379621b59bc7ef8af428c4f6ecc2445d454afc38eddb34247430279136f758fe52e538abcda923c386dbc4d7f2af00c27e9e41c26f71a4c5e2
|
7
|
+
data.tar.gz: e6e891f839dd472f24f1dc89ce1189cb80b9218ac09c35c4141c0dd0b575097ecb0d238d47de8e688bc69c3298da0f4e1b2478ebfed1010d139c3fb4087f0ccf
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,36 +1,40 @@
|
|
1
|
-
|
1
|
+
[](https://github.com/knowndecimal/fulfil/actions/workflows/tests.yml)
|
2
2
|
|
3
|
-
|
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
|
-
|
17
|
+
```shell
|
18
|
+
$ bundle install
|
19
|
+
```
|
18
20
|
|
19
21
|
Or install it yourself as:
|
20
22
|
|
21
|
-
|
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
|
28
|
-
-
|
29
|
-
- FULFIL_API_KEY
|
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
|
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
|
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`.
|
133
|
-
|
134
|
-
|
135
|
-
|
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:
|
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
|
-
|
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
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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
|
data/lib/fulfil/error.rb
ADDED
@@ -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(
|
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
|
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
|
data/lib/fulfil/version.rb
CHANGED
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
|
-
|
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
|
+
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:
|
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.
|
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.
|
182
|
+
rubygems_version: 3.3.7
|
139
183
|
signing_key:
|
140
184
|
specification_version: 4
|
141
185
|
summary: Interact with the Fulfil.io API
|