booqable 1.0.0 → 1.1.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 +11 -1
- data/README.md +78 -18
- data/lib/booqable/client.rb +17 -0
- data/lib/booqable/error.rb +51 -4
- data/lib/booqable/middleware/auth/oauth.rb +1 -1
- data/lib/booqable/resource_parser.rb +81 -0
- data/lib/booqable/resource_proxy.rb +7 -0
- data/lib/booqable/version.rb +1 -1
- data/lib/booqable.rb +1 -0
- metadata +5 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 13ee5f72ca221d2613d8691dd8c04fa189a38fbed8276b60878d2cce4c7f4f23
|
|
4
|
+
data.tar.gz: 54028d30a657d3651ad0d49fab923efba00e09fa9f0d2e36906e8cf068975abd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 51cb9ed5b66956cee3e429c51057e12884574fe3c8b3b907d6998caa1b037b5ca861c929ea7b26e8364369bf424b3686feff274149fa6a169da09d8048118390
|
|
7
|
+
data.tar.gz: d6389d7f934088b0447dba290054456f10380578f5b38622275d6e846c99872a5060c21b192b8524aa7d867fe1b58917c9ad03eebfacef716b83eca28dab8549
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [1.1.0] - 2026-03-11
|
|
4
|
+
|
|
5
|
+
- Add `parse_resource` method (aliased as `deserialize_resource`) for parsing
|
|
6
|
+
JSON:API payloads into Sawyer::Resource objects with dot-notation access.
|
|
7
|
+
Useful for parsing webhook payloads or raw API responses.
|
|
8
|
+
- Add Booqable::RefreshTokenRevoked and Booqable::InvalidGrant error types for
|
|
9
|
+
invalid grant OAuth response scenarios
|
|
10
|
+
- Add "all" as an alias for "list" method on all resources.
|
|
11
|
+
You can now use `Booqable.orders.all` as an alternative to `Booqable.orders.list`.
|
|
12
|
+
|
|
13
|
+
## [1.0.0] - 2025-10-23
|
|
4
14
|
|
|
5
15
|
- Initial release
|
data/README.md
CHANGED
|
@@ -5,6 +5,7 @@ Ruby toolkit for the [Booqable API](https://developers.booqable.com/).
|
|
|
5
5
|
[Booqable](https://booqable.com) is a rental management platform that helps businesses manage their rental inventory, customers, and orders. This gem provides a Ruby interface to interact with all Booqable API endpoints.
|
|
6
6
|
|
|
7
7
|
## Table of Contents
|
|
8
|
+
|
|
8
9
|
- [Installation](#installation)
|
|
9
10
|
- [Making requests](#making-requests)
|
|
10
11
|
- [Authentication](#authentication)
|
|
@@ -12,6 +13,7 @@ Ruby toolkit for the [Booqable API](https://developers.booqable.com/).
|
|
|
12
13
|
- [Pagination](#pagination)
|
|
13
14
|
- [Rate limiting](#rate-limiting)
|
|
14
15
|
- [Resources](#resources)
|
|
16
|
+
- [Parsing JSON:API payloads](#parsing-jsonapi-payloads)
|
|
15
17
|
- [Advanced usage](#advanced-usage)
|
|
16
18
|
- [Development](#development)
|
|
17
19
|
|
|
@@ -89,11 +91,11 @@ client = Booqable::Client.new(
|
|
|
89
91
|
client_id: 'your_oauth_client_id',
|
|
90
92
|
client_secret: 'your_oauth_client_secret',
|
|
91
93
|
company_id: 'your_company_id',
|
|
92
|
-
read_token: -> {
|
|
94
|
+
read_token: -> {
|
|
93
95
|
# Return stored token hash
|
|
94
96
|
JSON.parse(File.read('token.json'))
|
|
95
97
|
},
|
|
96
|
-
write_token: ->(token) {
|
|
98
|
+
write_token: ->(token) {
|
|
97
99
|
# Store token hash
|
|
98
100
|
File.write('token.json', token.to_json)
|
|
99
101
|
}
|
|
@@ -159,7 +161,7 @@ client = Booqable::Client.new(
|
|
|
159
161
|
|
|
160
162
|
## Pagination
|
|
161
163
|
|
|
162
|
-
|
|
164
|
+
Booqable provides several ways to handle paginated responses:
|
|
163
165
|
|
|
164
166
|
### Manual pagination
|
|
165
167
|
|
|
@@ -222,6 +224,13 @@ orders = Booqable.orders.list(
|
|
|
222
224
|
sort: '-created_at'
|
|
223
225
|
)
|
|
224
226
|
|
|
227
|
+
# `all` is an alias for `list`
|
|
228
|
+
orders = Booqable.orders.all(
|
|
229
|
+
include: 'customer,items',
|
|
230
|
+
filter: { status: 'reserved' },
|
|
231
|
+
sort: '-created_at'
|
|
232
|
+
)
|
|
233
|
+
|
|
225
234
|
# Find specific order
|
|
226
235
|
order = Booqable.orders.find('order_id', include: 'customer,items')
|
|
227
236
|
order.items.count
|
|
@@ -236,7 +245,7 @@ new_order = Booqable.orders.create(
|
|
|
236
245
|
new_order.status # => 'draft'
|
|
237
246
|
|
|
238
247
|
# Update order
|
|
239
|
-
updated_order = Booqable.orders.update('order_id',
|
|
248
|
+
updated_order = Booqable.orders.update('order_id', stops_at: '2024-01-03T00:00:00Z')
|
|
240
249
|
updated_order.status # => 'reserved'
|
|
241
250
|
|
|
242
251
|
# Delete order
|
|
@@ -296,20 +305,83 @@ deleted_product.id # => 'product_id'
|
|
|
296
305
|
Booqable provides access to all Booqable API resources:
|
|
297
306
|
|
|
298
307
|
**Core Resources:**
|
|
308
|
+
|
|
299
309
|
- `orders`, `customers`, `products`, `items`
|
|
300
310
|
- `employees`, `companies`, `locations`
|
|
301
311
|
- `payments`, `invoices`, `documents`
|
|
302
312
|
|
|
303
313
|
**Inventory Management:**
|
|
314
|
+
|
|
304
315
|
- `inventory_levels`, `stock_items`, `stock_adjustments`
|
|
305
316
|
- `transfers`, `plannings`, `clusters`
|
|
306
317
|
|
|
307
318
|
**Configuration:**
|
|
319
|
+
|
|
308
320
|
- `settings`, `properties`, `tax_rates`
|
|
309
321
|
- `payment_methods`, `email_templates`
|
|
310
322
|
|
|
311
323
|
**And many more...** See the [full resource list](lib/booqable/resources.json) for all available endpoints.
|
|
312
324
|
|
|
325
|
+
## Parsing JSON:API payloads
|
|
326
|
+
|
|
327
|
+
Booqable provides a convenient way to parse JSON:API formatted data (such as webhook payloads or raw API responses) into Ruby objects with dot-notation access:
|
|
328
|
+
|
|
329
|
+
```ruby
|
|
330
|
+
# Parse a webhook payload
|
|
331
|
+
payload = {
|
|
332
|
+
"data" => {
|
|
333
|
+
"id" => "abc-123",
|
|
334
|
+
"type" => "customers",
|
|
335
|
+
"attributes" => {
|
|
336
|
+
"name" => "John Doe",
|
|
337
|
+
"email" => "john@example.com",
|
|
338
|
+
"created_at" => "2024-01-15T10:30:00Z"
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
customer = Booqable.parse_resource(payload)
|
|
344
|
+
customer.id # => "abc-123"
|
|
345
|
+
customer.name # => "John Doe"
|
|
346
|
+
customer.email # => "john@example.com"
|
|
347
|
+
customer.created_at # => 2024-01-15 10:30:00 UTC (Time object)
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### With nested relationships
|
|
351
|
+
|
|
352
|
+
```ruby
|
|
353
|
+
payload = {
|
|
354
|
+
"data" => {
|
|
355
|
+
"id" => "order-123",
|
|
356
|
+
"type" => "orders",
|
|
357
|
+
"attributes" => { "status" => "reserved" },
|
|
358
|
+
"relationships" => {
|
|
359
|
+
"customer" => { "data" => { "id" => "customer-456", "type" => "customers" } }
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
"included" => [
|
|
363
|
+
{
|
|
364
|
+
"id" => "customer-456",
|
|
365
|
+
"type" => "customers",
|
|
366
|
+
"attributes" => { "name" => "Jane Smith" }
|
|
367
|
+
}
|
|
368
|
+
]
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
order = Booqable.parse_resource(payload)
|
|
372
|
+
order.status # => "reserved"
|
|
373
|
+
order.customer.name # => "Jane Smith"
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Using with a client instance
|
|
377
|
+
|
|
378
|
+
```ruby
|
|
379
|
+
# If you already have a client instance
|
|
380
|
+
customer = client.parse_resource(payload)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
`deserialize_resource` is available as an alias for `parse_resource`.
|
|
384
|
+
|
|
313
385
|
## Advanced usage
|
|
314
386
|
|
|
315
387
|
### Custom middleware
|
|
@@ -346,18 +418,6 @@ Booqable.configure do |c|
|
|
|
346
418
|
end
|
|
347
419
|
```
|
|
348
420
|
|
|
349
|
-
### Custom serialization
|
|
350
|
-
|
|
351
|
-
```ruby
|
|
352
|
-
# Access raw response data
|
|
353
|
-
response = Booqable.orders.list
|
|
354
|
-
puts response.class # => Sawyer::Resource
|
|
355
|
-
|
|
356
|
-
# Get response metadata
|
|
357
|
-
puts Booqable.last_response.status
|
|
358
|
-
puts Booqable.last_response.headers
|
|
359
|
-
```
|
|
360
|
-
|
|
361
421
|
## Development
|
|
362
422
|
|
|
363
423
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
@@ -376,7 +436,7 @@ bundle exec rspec spec/booqable/client_spec.rb
|
|
|
376
436
|
|
|
377
437
|
### Contributing
|
|
378
438
|
|
|
379
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/booqable/booqable.rb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/booqable/booqable.rb/blob/
|
|
439
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/booqable/booqable.rb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/booqable/booqable.rb/blob/main/CODE_OF_CONDUCT.md).
|
|
380
440
|
|
|
381
441
|
## Versioning
|
|
382
442
|
|
|
@@ -396,7 +456,7 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
396
456
|
|
|
397
457
|
## Code of Conduct
|
|
398
458
|
|
|
399
|
-
Everyone interacting in the Booqable project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/booqable/booqable.rb/blob/
|
|
459
|
+
Everyone interacting in the Booqable project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/booqable/booqable.rb/blob/main/CODE_OF_CONDUCT.md).
|
|
400
460
|
|
|
401
461
|
---
|
|
402
462
|
|
data/lib/booqable/client.rb
CHANGED
|
@@ -56,6 +56,23 @@ module Booqable
|
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
# Parse a JSON:API payload into a Sawyer::Resource
|
|
60
|
+
#
|
|
61
|
+
# Converts JSON:API formatted data (from webhooks or API responses) into
|
|
62
|
+
# Ruby objects with dot-notation access for convenient attribute access.
|
|
63
|
+
#
|
|
64
|
+
# @param payload [String, Hash] JSON:API payload (string or parsed hash)
|
|
65
|
+
# @return [Sawyer::Resource, nil] Parsed resource object, or nil for empty input
|
|
66
|
+
#
|
|
67
|
+
# @example
|
|
68
|
+
# customer = client.parse_resource(webhook_payload)
|
|
69
|
+
# customer.name # => "John"
|
|
70
|
+
#
|
|
71
|
+
def parse_resource(payload)
|
|
72
|
+
Booqable::ResourceParser.parse(payload)
|
|
73
|
+
end
|
|
74
|
+
alias_method :deserialize_resource, :parse_resource
|
|
75
|
+
|
|
59
76
|
# String representation of the client with sensitive information masked
|
|
60
77
|
#
|
|
61
78
|
# Overrides the default inspect method to hide sensitive configuration
|
data/lib/booqable/error.rb
CHANGED
|
@@ -42,8 +42,8 @@ module Booqable
|
|
|
42
42
|
# headers = response[:response_headers]
|
|
43
43
|
|
|
44
44
|
if klass = case status
|
|
45
|
-
when 400 then error_for_400(
|
|
46
|
-
when 401 then
|
|
45
|
+
when 400 then error_for_400(response)
|
|
46
|
+
when 401 then error_for_401(response)
|
|
47
47
|
when 402 then error_for_402(body)
|
|
48
48
|
when 403 then Booqable::Forbidden
|
|
49
49
|
when 404 then error_for_404(body)
|
|
@@ -85,8 +85,8 @@ module Booqable
|
|
|
85
85
|
# Return most appropriate error for 400 HTTP status code
|
|
86
86
|
# @private
|
|
87
87
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
88
|
-
def self.error_for_400(
|
|
89
|
-
case body
|
|
88
|
+
def self.error_for_400(response)
|
|
89
|
+
case response.body
|
|
90
90
|
when /unwrittable_attribute/i
|
|
91
91
|
Booqable::ReadOnlyAttribute
|
|
92
92
|
when /unknown_attribute/i
|
|
@@ -103,12 +103,25 @@ module Booqable
|
|
|
103
103
|
Booqable::InvalidFilter
|
|
104
104
|
when /required filter/i
|
|
105
105
|
Booqable::RequiredFilter
|
|
106
|
+
when /invalid_grant/i
|
|
107
|
+
error_for_invalid_grant(response)
|
|
106
108
|
else
|
|
107
109
|
Booqable::BadRequest
|
|
108
110
|
end
|
|
109
111
|
end
|
|
110
112
|
# rubocop:enable Metrics/CyclomaticComplexity
|
|
111
113
|
|
|
114
|
+
# Return most appropriate error for 401 HTTP status code
|
|
115
|
+
# @private
|
|
116
|
+
def self.error_for_401(response)
|
|
117
|
+
case response.body
|
|
118
|
+
when /token is invalid \(revoked\)/i
|
|
119
|
+
Booqable::TokenRevoked
|
|
120
|
+
else
|
|
121
|
+
Booqable::Unauthorized
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
112
125
|
# Return most appropriate error for 402 HTTP status code
|
|
113
126
|
# @private
|
|
114
127
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
@@ -163,6 +176,26 @@ module Booqable
|
|
|
163
176
|
end
|
|
164
177
|
end
|
|
165
178
|
|
|
179
|
+
# Return most appropriate error for invalid_grant OAuth error
|
|
180
|
+
#
|
|
181
|
+
# Determines whether the invalid_grant error is due to a revoked refresh token
|
|
182
|
+
# or a different OAuth grant error by examining the grant_type parameter
|
|
183
|
+
# in the request body.
|
|
184
|
+
#
|
|
185
|
+
# @param response [Hash] HTTP response containing the request body
|
|
186
|
+
# @return [Class] RefreshTokenRevoked if grant_type is refresh_token, InvalidGrant otherwise
|
|
187
|
+
# @private
|
|
188
|
+
def self.error_for_invalid_grant(response)
|
|
189
|
+
grant_type = CGI.parse(response.request_body).dig("grant_type", 0)
|
|
190
|
+
|
|
191
|
+
case grant_type
|
|
192
|
+
when /refresh_token/i
|
|
193
|
+
Booqable::RefreshTokenRevoked
|
|
194
|
+
else
|
|
195
|
+
Booqable::InvalidGrant
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
166
199
|
# Array of validation errors
|
|
167
200
|
# @return [Array<Hash>] Error info
|
|
168
201
|
def errors
|
|
@@ -300,6 +333,20 @@ module Booqable
|
|
|
300
333
|
# and body matches 'required filter'
|
|
301
334
|
class RequiredFilter < ClientError; end
|
|
302
335
|
|
|
336
|
+
# Raised when Booqable returns a 401 HTTP status code
|
|
337
|
+
# and body matches 'token is invalid (revoked)'
|
|
338
|
+
class TokenRevoked < ClientError; end
|
|
339
|
+
|
|
340
|
+
# Raised when Booqable returns a 400 HTTP status code
|
|
341
|
+
# and body matches 'invalid_grant' and
|
|
342
|
+
# the grant type is refresh token (OAuth error)
|
|
343
|
+
class RefreshTokenRevoked < TokenRevoked; end
|
|
344
|
+
|
|
345
|
+
# Raised when Booqable returns a 400 HTTP status code
|
|
346
|
+
# and body matches 'invalid_grant' and
|
|
347
|
+
# grant type is not refresh token (OAuth error)
|
|
348
|
+
class InvalidGrant < ClientError; end
|
|
349
|
+
|
|
303
350
|
# Raised when Booqable returns a 401 HTTP status code
|
|
304
351
|
class Unauthorized < ClientError; end
|
|
305
352
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booqable
|
|
4
|
+
# Parses JSON:API payloads into Sawyer::Resource objects
|
|
5
|
+
#
|
|
6
|
+
# JSON:API formatted data (from webhooks or API responses) is converted
|
|
7
|
+
# into Ruby objects with dot-notation access for convenient attribute access.
|
|
8
|
+
#
|
|
9
|
+
# @example Parse a JSON:API payload
|
|
10
|
+
# payload = '{"data":{"id":"123","type":"customers","attributes":{"name":"John"}}}'
|
|
11
|
+
# customer = Booqable::ResourceParser.parse(payload)
|
|
12
|
+
# customer.id # => "123"
|
|
13
|
+
# customer.name # => "John"
|
|
14
|
+
#
|
|
15
|
+
# @example Parse with nested relationships
|
|
16
|
+
# payload = {
|
|
17
|
+
# "data" => {
|
|
18
|
+
# "id" => "123",
|
|
19
|
+
# "type" => "orders",
|
|
20
|
+
# "attributes" => { "status" => "reserved" },
|
|
21
|
+
# "relationships" => {
|
|
22
|
+
# "customer" => { "data" => { "id" => "456", "type" => "customers" } }
|
|
23
|
+
# }
|
|
24
|
+
# },
|
|
25
|
+
# "included" => [
|
|
26
|
+
# { "id" => "456", "type" => "customers", "attributes" => { "name" => "John" } }
|
|
27
|
+
# ]
|
|
28
|
+
# }
|
|
29
|
+
# order = Booqable::ResourceParser.parse(payload)
|
|
30
|
+
# order.customer.name # => "John"
|
|
31
|
+
#
|
|
32
|
+
class ResourceParser
|
|
33
|
+
# Parse a JSON:API payload into a Sawyer::Resource
|
|
34
|
+
#
|
|
35
|
+
# @param payload [String, Hash] JSON:API payload (string or parsed hash)
|
|
36
|
+
# @return [Sawyer::Resource, nil] Parsed resource object with dot-notation access,
|
|
37
|
+
# or nil for empty/nil input
|
|
38
|
+
def self.parse(payload)
|
|
39
|
+
new(payload).parse
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Initialize a new ResourceParser
|
|
43
|
+
#
|
|
44
|
+
# @param payload [String, Hash] JSON:API payload
|
|
45
|
+
def initialize(payload)
|
|
46
|
+
@payload = payload
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Parse the payload into a Sawyer::Resource
|
|
50
|
+
#
|
|
51
|
+
# @return [Sawyer::Resource, nil] Parsed resource or nil for empty input
|
|
52
|
+
def parse
|
|
53
|
+
return nil if @payload.nil?
|
|
54
|
+
|
|
55
|
+
json_string = @payload.is_a?(String) ? @payload : @payload.to_json
|
|
56
|
+
return nil if json_string.strip.empty?
|
|
57
|
+
|
|
58
|
+
serializer = JsonApiSerializer.any_json
|
|
59
|
+
decoded = serializer.decode(json_string)
|
|
60
|
+
|
|
61
|
+
return nil unless decoded && decoded[:data]
|
|
62
|
+
|
|
63
|
+
Sawyer::Resource.new(sawyer_agent, decoded[:data])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
# Create a minimal Sawyer agent for wrapping resources
|
|
69
|
+
#
|
|
70
|
+
# The agent URL is a placeholder - we don't make any HTTP requests.
|
|
71
|
+
# We just need the agent to create Sawyer::Resource objects that
|
|
72
|
+
# provide dot-notation attribute access.
|
|
73
|
+
#
|
|
74
|
+
# @return [Sawyer::Agent]
|
|
75
|
+
def sawyer_agent
|
|
76
|
+
@sawyer_agent ||= Sawyer::Agent.new("https://example.com") do |http|
|
|
77
|
+
http.headers[:content_type] = "application/json"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
data/lib/booqable/version.rb
CHANGED
data/lib/booqable.rb
CHANGED
|
@@ -25,6 +25,7 @@ require_relative "booqable/resources"
|
|
|
25
25
|
require_relative "booqable/auth"
|
|
26
26
|
require_relative "booqable/http"
|
|
27
27
|
require_relative "booqable/client"
|
|
28
|
+
require_relative "booqable/resource_parser"
|
|
28
29
|
|
|
29
30
|
# Main Booqable module providing access to the Booqable API
|
|
30
31
|
#
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: booqable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hrvoje Šimić
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: faraday
|
|
@@ -138,6 +137,7 @@ files:
|
|
|
138
137
|
- lib/booqable/middleware/raise_error.rb
|
|
139
138
|
- lib/booqable/oauth_client.rb
|
|
140
139
|
- lib/booqable/rate_limit.rb
|
|
140
|
+
- lib/booqable/resource_parser.rb
|
|
141
141
|
- lib/booqable/resource_proxy.rb
|
|
142
142
|
- lib/booqable/resources.json
|
|
143
143
|
- lib/booqable/resources.rb
|
|
@@ -149,10 +149,9 @@ licenses:
|
|
|
149
149
|
metadata:
|
|
150
150
|
homepage_uri: https://github.com/booqable/booqable.rb
|
|
151
151
|
source_code_uri: https://github.com/booqable/booqable.rb
|
|
152
|
-
changelog_uri: https://github.com/booqable/booqable.rb/blob/
|
|
152
|
+
changelog_uri: https://github.com/booqable/booqable.rb/blob/main/CHANGELOG.md
|
|
153
153
|
documentation_uri: https://developers.booqable.com/
|
|
154
154
|
bug_tracker_uri: https://github.com/booqable/booqable.rb/issues
|
|
155
|
-
post_install_message:
|
|
156
155
|
rdoc_options: []
|
|
157
156
|
require_paths:
|
|
158
157
|
- lib
|
|
@@ -167,8 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
167
166
|
- !ruby/object:Gem::Version
|
|
168
167
|
version: '0'
|
|
169
168
|
requirements: []
|
|
170
|
-
rubygems_version: 3.
|
|
171
|
-
signing_key:
|
|
169
|
+
rubygems_version: 3.6.9
|
|
172
170
|
specification_version: 4
|
|
173
171
|
summary: Official Booqable API client for Ruby.
|
|
174
172
|
test_files: []
|