booqable 1.0.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.
@@ -0,0 +1,68 @@
1
+ module Booqable
2
+ # Resource-related methods for {Booqable::Client}
3
+ #
4
+ # This module dynamically defines methods for each resource listed in the
5
+ # `resources.json` file. Each resource method returns a {ResourceProxy} that
6
+ # provides standard CRUD operations for that resource type.
7
+ #
8
+ # The resources.json file can contain either simple strings or hash mappings
9
+ # for aliases. For example:
10
+ #
11
+ # @example resources.json structure
12
+ # [
13
+ # "orders",
14
+ # "customers",
15
+ # { "order_status_transitions": "transitions" }
16
+ # ]
17
+ #
18
+ # This would define the following methods on {Booqable::Client}:
19
+ # - `orders` - returns ResourceProxy for orders
20
+ # - `customers` - returns ResourceProxy for customers
21
+ # - `order_status_transitions` - returns ResourceProxy for order_status_transitions
22
+ # - `transitions` - alias for order_status_transitions
23
+ #
24
+ # @example Using resource methods
25
+ # client = Booqable::Client.new
26
+ #
27
+ # # Access orders resource
28
+ # orders = client.orders
29
+ # all_orders = orders.list
30
+ #
31
+ # # Access customers resource
32
+ # customers = client.customers
33
+ # customer = customers.find("123")
34
+ #
35
+ # # Access order status transitions directly
36
+ # order_status_transitions = client.order_status_transitions
37
+ #
38
+ # # Access order status transitions with alias
39
+ # transitions = client.transitions
40
+ #
41
+ # @see ResourceProxy
42
+ module Resources
43
+ # Path to the resources definition file
44
+ RESOURCES_FILE_PATH = File.join(File.dirname(__FILE__), "resources.json")
45
+
46
+ # All resources loaded from the resources.json file
47
+ ALL_RESOURCES = JSON.parse(File.read(RESOURCES_FILE_PATH))
48
+
49
+ ALL_RESOURCES.each do |resource|
50
+ resource_name = resource.is_a?(Hash) ? resource.keys.first : resource
51
+ resource_alias = resource.is_a?(Hash) ? resource.values.first : nil
52
+
53
+ # Dynamically define resource method
54
+ # @return [ResourceProxy] Resource proxy for the specified resource
55
+ define_method(resource_name) do
56
+ ResourceProxy.new(self, resource_name)
57
+ end
58
+
59
+ next unless resource_alias
60
+
61
+ # Dynamically define resource alias method
62
+ # @return [ResourceProxy] Resource proxy for the specified resource
63
+ define_method(resource_alias) do
64
+ ResourceProxy.new(self, resource_name)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Booqable
4
+ VERSION = "1.0.0"
5
+ end
data/lib/booqable.rb ADDED
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Dependencies
4
+ require "faraday"
5
+ require "faraday/retry"
6
+ require "json"
7
+ require "sawyer"
8
+ require "sawyer/link_parsers/simple"
9
+
10
+ # Internal
11
+ require_relative "booqable/version"
12
+ require_relative "booqable/rate_limit"
13
+ require_relative "booqable/error"
14
+ require_relative "booqable/oauth_client"
15
+ require_relative "booqable/middleware/base"
16
+ require_relative "booqable/middleware/raise_error"
17
+ require_relative "booqable/middleware/auth/oauth"
18
+ require_relative "booqable/middleware/auth/api_key"
19
+ require_relative "booqable/middleware/auth/single_use"
20
+ require_relative "booqable/resource_proxy"
21
+ require_relative "booqable/json_api_serializer"
22
+ require_relative "booqable/default"
23
+ require_relative "booqable/configurable"
24
+ require_relative "booqable/resources"
25
+ require_relative "booqable/auth"
26
+ require_relative "booqable/http"
27
+ require_relative "booqable/client"
28
+
29
+ # Main Booqable module providing access to the Booqable API
30
+ #
31
+ # @example Basic usage
32
+ # Booqable.configure do |config|
33
+ # config.api_key = "your_api_key"
34
+ # config.company_id = "your_company"
35
+ # end
36
+ #
37
+ # orders = Booqable.orders.list(include: "customer,items")
38
+ # orders.each do |order|
39
+ # order.items.each do |item|
40
+ # # Process each item in the order
41
+ # end
42
+ # end
43
+ #
44
+ module Booqable
45
+ class << self
46
+ include Booqable::Configurable
47
+
48
+ # API client based on configured options {Configurable}
49
+ #
50
+ # @return [Booqable::Client] API wrapper
51
+ def client
52
+ return @client if defined?(@client) && @client.same_options?(options)
53
+
54
+ @client = Booqable::Client.new(options)
55
+ end
56
+
57
+ private
58
+
59
+ # Delegates respond_to? calls to the client
60
+ #
61
+ # @param method_name [Symbol] the method name to check
62
+ # @param include_private [Boolean] whether to include private methods
63
+ # @return [Boolean] true if the client responds to the method
64
+ def respond_to_missing?(method_name, include_private = false)
65
+ client.respond_to?(method_name, include_private)
66
+ end
67
+
68
+ # Delegates method calls to the client when the client responds to them
69
+ #
70
+ # @param method_name [Symbol] the method name being called
71
+ # @param args [Array] arguments passed to the method
72
+ # @param block [Proc] block passed to the method
73
+ # @return [Object] the result of calling the method on the client
74
+ # @raise [NoMethodError] when neither the module nor client respond to the method
75
+ def method_missing(method_name, *args, &block)
76
+ if client.respond_to?(method_name)
77
+ return client.send(method_name, *args, &block)
78
+ end
79
+
80
+ super
81
+ end
82
+ end
83
+ end
84
+
85
+ Booqable.setup
data/sig/booqable.rbs ADDED
@@ -0,0 +1,324 @@
1
+ module Booqable
2
+ VERSION: String
3
+
4
+ # Configuration options for {Client}
5
+ module Configurable
6
+ @api_domain: String?
7
+ @api_endpoint: String?
8
+ @api_key: String?
9
+ @api_version: String | Integer?
10
+ @auto_paginate: bool?
11
+ @client_id: String?
12
+ @client_secret: String?
13
+ @company_id: String?
14
+ @connection_options: Hash[Symbol, untyped]?
15
+ @debug: bool?
16
+ @default_media_type: String?
17
+ @middleware: Faraday::RackBuilder?
18
+ @no_retries: bool?
19
+ @per_page: Integer?
20
+ @proxy: String?
21
+ @read_token: Proc?
22
+ @redirect_uri: String?
23
+ @single_use_token: String?
24
+ @single_use_token_algorithm: String?
25
+ @single_use_token_company_id: String?
26
+ @single_use_token_expiration_period: Integer?
27
+ @single_use_token_private_key: String?
28
+ @single_use_token_secret: String?
29
+ @single_use_token_user_id: String?
30
+ @ssl_verify_mode: Integer?
31
+ @user_agent: String?
32
+ @write_token: Proc?
33
+
34
+ attr_accessor api_domain: String?
35
+ attr_accessor api_endpoint: String?
36
+ attr_accessor api_key: String?
37
+ attr_accessor api_version: String | Integer?
38
+ attr_accessor auto_paginate: bool?
39
+ attr_accessor client_id: String?
40
+ attr_accessor client_secret: String?
41
+ attr_accessor company_id: String?
42
+ attr_accessor connection_options: Hash[Symbol, untyped]?
43
+ attr_accessor debug: bool?
44
+ attr_accessor default_media_type: String?
45
+ attr_accessor middleware: Faraday::RackBuilder?
46
+ attr_accessor no_retries: bool?
47
+ attr_accessor per_page: Integer?
48
+ attr_accessor proxy: String?
49
+ attr_accessor read_token: Proc?
50
+ attr_accessor redirect_uri: String?
51
+ attr_accessor single_use_token: String?
52
+ attr_accessor single_use_token_algorithm: String?
53
+ attr_accessor single_use_token_company_id: String?
54
+ attr_accessor single_use_token_expiration_period: Integer?
55
+ attr_accessor single_use_token_private_key: String?
56
+ attr_accessor single_use_token_secret: String?
57
+ attr_accessor single_use_token_user_id: String?
58
+ attr_accessor ssl_verify_mode: Integer?
59
+ attr_accessor user_agent: String?
60
+ attr_accessor write_token: Proc?
61
+
62
+ module ConfigurableClass
63
+ def keys: () -> Array[Symbol]
64
+ end
65
+
66
+ extend ConfigurableClass
67
+
68
+ def configure: () { (self) -> void } -> void
69
+ def reset!: () -> self
70
+ alias setup reset!
71
+ def same_options?: (Hash[Symbol, untyped] opts) -> bool
72
+ def debug?: () -> bool
73
+
74
+ private
75
+
76
+ def api_protocol: () -> String
77
+ def options: () -> Hash[Symbol, untyped]
78
+ end
79
+
80
+ # Resource-related methods for {Booqable::Client}
81
+ module Resources
82
+ RESOURCES_FILE_PATH: String
83
+ ALL_RESOURCES: Array[String | Hash[String, String]]
84
+
85
+ def method_missing: (Symbol method_name, *untyped args) -> ResourceProxy
86
+ end
87
+
88
+ # Authentication methods for {Booqable::Client}
89
+ module Auth
90
+ def authenticate_with_code: (String code) -> void
91
+ def inject_auth_middleware: (Faraday::Builder builder) -> void
92
+ def oauth_client: () -> OAuthClient?
93
+ def oauth_authenticated?: () -> bool
94
+ def api_key_authenticated?: () -> bool
95
+ def single_use_token_authenticated?: () -> bool
96
+ end
97
+
98
+ # HTTP request methods for {Booqable::Client}
99
+ module HTTP
100
+ CONVENIENCE_HEADERS: Set[Symbol]
101
+
102
+ @last_response: Sawyer::Response?
103
+ @faraday: Faraday::Connection?
104
+ @faraday_builder: Faraday::RackBuilder?
105
+ @agent: Sawyer::Agent?
106
+ @logger: Logger?
107
+
108
+ def get: (String url, ?Hash[Symbol, untyped] options) -> Sawyer::Resource
109
+ def post: (String url, ?Hash[Symbol, untyped] options) -> Sawyer::Resource
110
+ def put: (String url, ?Hash[Symbol, untyped] options) -> Sawyer::Resource
111
+ def patch: (String url, ?Hash[Symbol, untyped] options) -> Sawyer::Resource
112
+ def delete: (String url, ?Hash[Symbol, untyped] options) -> Sawyer::Resource
113
+ def head: (String url, ?Hash[Symbol, untyped] options) -> Sawyer::Resource
114
+ def request: (Symbol method, String path, untyped data, ?Hash[Symbol, untyped] options) -> Sawyer::Resource
115
+ def normalized_path: (String path) -> String
116
+ def last_response: () -> Sawyer::Response?
117
+ def paginate: (String url, ?Hash[Symbol, untyped] options) -> Array[untyped]
118
+ def rate_limit: () -> RateLimit
119
+ def faraday: () -> Faraday::Connection
120
+ def default_headers: () -> Hash[Symbol, String]
121
+ def faraday_options: () -> Hash[Symbol, untyped]
122
+ def faraday_builder: () -> Faraday::RackBuilder
123
+ def agent: () -> Sawyer::Agent
124
+ def logger: () -> Logger?
125
+ def sawyer_options: () -> Hash[Symbol, untyped]
126
+ def sawyer_serializer: () -> JsonApiSerializer
127
+ def last_response_body: () -> Hash[Symbol, untyped]?
128
+ def parse_options_with_convenience_headers: (Hash[Symbol, untyped] options) -> Hash[Symbol, untyped]
129
+ def response_data_with_correct_encoding: (Sawyer::Response response) -> untyped
130
+ def api_endpoint: () -> String
131
+ end
132
+
133
+ # Client for the Booqable API
134
+ class Client
135
+ include Configurable
136
+ include Resources
137
+ include Auth
138
+ include HTTP
139
+
140
+ SECRETS: Array[String]
141
+
142
+ def initialize: (?Hash[Symbol, untyped] options) -> void
143
+ def inspect: () -> String
144
+ end
145
+
146
+ # Generic resource proxy for API collections
147
+ class ResourceProxy
148
+ @client: Client
149
+ @resource: String
150
+
151
+ def initialize: (Client client, String | Symbol resource_name) -> void
152
+ def list: (?Hash[Symbol, untyped] params) -> Array[untyped]
153
+ def find: (String | Integer id, ?Hash[Symbol, untyped] params) -> Hash[Symbol, untyped]
154
+ def create: (?Hash[Symbol, untyped] attrs) -> Hash[Symbol, untyped]
155
+ def update: (String | Integer id, ?Hash[Symbol, untyped] attrs) -> Hash[Symbol, untyped]
156
+
157
+ private
158
+
159
+ attr_reader client: Client
160
+
161
+ def request: (*untyped args) -> untyped
162
+ def paginate: (*untyped args) -> untyped
163
+ end
164
+
165
+ # OAuth2 client for Booqable API authentication
166
+ class OAuthClient
167
+ TOKEN_ENDPOINT: String
168
+
169
+ @client: OAuth2::Client
170
+ @redirect_uri: String
171
+
172
+ def initialize: (base_url: String, client_id: String, client_secret: String, redirect_uri: String) -> void
173
+ def get_token_from_code: (String code, ?scope: String) -> OAuth2::AccessToken
174
+ end
175
+
176
+ # Rate limit information from API responses
177
+ class RateLimit < Struct[Integer?]
178
+ attr_accessor limit: Integer?
179
+ attr_accessor remaining: Integer?
180
+ attr_accessor resets_in: Integer?
181
+
182
+ def self.from_response: (untyped response) -> RateLimit
183
+ end
184
+
185
+ # Custom error class for rescuing from all Booqable errors
186
+ class Error < StandardError
187
+ attr_reader context: RateLimit?
188
+
189
+ @response: Hash[Symbol, untyped]?
190
+ @data: untyped
191
+
192
+ def self.from_response: (Hash[Symbol, untyped] response) -> nil
193
+ def self.error_class_from_response: (Hash[Symbol, untyped] response) -> Error?
194
+ def self.error_for_400: (String body) -> singleton(Error)
195
+ def self.error_for_402: (String body) -> singleton(Error)
196
+ def self.error_for_404: (String body) -> singleton(Error)
197
+ def self.error_for_422: (String body) -> singleton(Error)
198
+ def self.error_for_503: (String body) -> singleton(Error)
199
+
200
+ def initialize: (?Hash[Symbol, untyped]? response) -> void
201
+ def build_error_context: () -> void
202
+ def errors: () -> Array[Hash[Symbol, untyped]]
203
+ def response_status: () -> Integer
204
+ def response_headers: () -> Hash[Symbol, untyped]
205
+ def response_body: () -> String
206
+
207
+ private
208
+
209
+ def data: () -> untyped
210
+ def response_message: () -> String?
211
+ def response_error: () -> String?
212
+ def response_error_summary: () -> String?
213
+ def build_error_message: () -> String?
214
+ def redact_url: (String url_string) -> String
215
+ end
216
+
217
+ # Error classes
218
+ class ClientError < Error; end
219
+ class BadRequest < ClientError; end
220
+ class ReadOnlyAttribute < ClientError; end
221
+ class UnknownAttribute < ClientError; end
222
+ class FieldsInWrongFormat < ClientError; end
223
+ class ExtraFieldsInWrongFormat < ClientError; end
224
+ class PageShouldBeAnObject < ClientError; end
225
+ class FailedTypecasting < ClientError; end
226
+ class InvalidFilter < ClientError; end
227
+ class RequiredFilter < ClientError; end
228
+ class Unauthorized < ClientError; end
229
+ class PaymentRequired < ClientError; end
230
+ class FeatureNotEnabled < PaymentRequired; end
231
+ class TrialExpired < PaymentRequired; end
232
+ class Forbidden < ClientError; end
233
+ class TooManyRequests < Forbidden; end
234
+ class NotFound < ClientError; end
235
+ class CompanyNotFound < NotFound; end
236
+ class MethodNotAllowed < ClientError; end
237
+ class NotAcceptable < ClientError; end
238
+ class Conflict < ClientError; end
239
+ class Deprecated < ClientError; end
240
+ class UnsupportedMediaType < ClientError; end
241
+ class Locked < ClientError; end
242
+ class UnprocessableEntity < ClientError; end
243
+ class InvalidDateTimeFormat < UnprocessableEntity; end
244
+ class InvalidDateFormat < UnprocessableEntity; end
245
+ class ServerError < Error; end
246
+ class InternalServerError < ServerError; end
247
+ class NotImplemented < ServerError; end
248
+ class BadGateway < ServerError; end
249
+ class ServiceUnavailable < ServerError; end
250
+ class ReadOnlyMode < ServerError; end
251
+ class ConfigArgumentError < ArgumentError; end
252
+ class CompanyRequired < ArgumentError; end
253
+ class SingleUseTokenCompanyIdRequired < ArgumentError; end
254
+ class SingleUseTokenUserIdRequired < ArgumentError; end
255
+ class SingleUseTokenAlgorithmRequired < ConfigArgumentError; end
256
+ class PrivateKeyOrSecretRequired < ConfigArgumentError; end
257
+ class UnsupportedAPIVersion < ConfigArgumentError; end
258
+ class RequiredAuthParamMissing < ArgumentError; end
259
+
260
+ RATE_LIMITED_ERRORS: Array[singleton(Error)]
261
+
262
+ # JSON API serializer
263
+ class JsonApiSerializer
264
+ def self.any_json: () -> JsonApiSerializer
265
+ def decode: (String body) -> Hash[Symbol, untyped]
266
+ def encode: (Hash[Symbol, untyped] data) -> String
267
+ end
268
+
269
+ # Default configuration options
270
+ module Default
271
+ USER_AGENT: String
272
+ MEDIA_TYPE: String
273
+ RETRY_OPTIONS: Hash[Symbol, untyped]
274
+ MIDDLEWARE: Faraday::RackBuilder
275
+
276
+ module DefaultClass
277
+ def options: () -> Hash[Symbol, untyped]
278
+ def api_domain: () -> String
279
+ def api_version: () -> Integer
280
+ def api_endpoint: () -> String?
281
+ def auto_paginate: () -> String?
282
+ def client_id: () -> String?
283
+ def client_secret: () -> String?
284
+ def company_id: () -> String?
285
+ def redirect_uri: () -> String?
286
+ def connection_options: () -> Hash[Symbol, untyped]?
287
+ def default_media_type: () -> String
288
+ def middleware: () -> Faraday::RackBuilder
289
+ def per_page: () -> Integer?
290
+ def proxy: () -> String?
291
+ def ssl_verify_mode: () -> Integer
292
+ def user_agent: () -> String
293
+ def read_token: () -> Proc
294
+ def write_token: () -> Proc
295
+ def api_key: () -> String?
296
+ def single_use_token: () -> String?
297
+ def single_use_token_algorithm: () -> String?
298
+ def single_use_token_secret: () -> String?
299
+ def single_use_token_private_key: () -> String?
300
+ def single_use_token_expiration_period: () -> Integer
301
+ def single_use_token_company_id: () -> String?
302
+ def single_use_token_user_id: () -> String?
303
+ def debug: () -> bool
304
+ def no_retries: () -> bool
305
+ end
306
+
307
+ extend DefaultClass
308
+ end
309
+
310
+ # Module methods
311
+ def self.client: () -> Client
312
+ def self.configure: () { (self) -> void } -> void
313
+ def self.reset!: () -> self
314
+ alias self.setup self.reset!
315
+ def self.same_options?: (Hash[Symbol, untyped] opts) -> bool
316
+ def self.debug?: () -> bool
317
+
318
+ private
319
+
320
+ def self.respond_to_missing?: (Symbol method_name, ?bool include_private) -> bool
321
+ def self.method_missing: (Symbol method_name, *untyped args) ?{ (*untyped) -> untyped } -> untyped
322
+
323
+ include Configurable
324
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: booqable
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Hrvoje Šimić
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-10-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.13'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday-retry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sawyer
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: multi_json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.15'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.15'
69
+ - !ruby/object:Gem::Dependency
70
+ name: addressable
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.8'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: oauth2
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: jwt
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.1'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.1'
111
+ description: Ruby toolkit for the Booqable API. Provides a simple interface to interact
112
+ with all Booqable API endpoints including orders, customers, products, and more.
113
+ email:
114
+ - services@booqable.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".rspec"
120
+ - ".rubocop.yml"
121
+ - CHANGELOG.md
122
+ - CODE_OF_CONDUCT.md
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - lib/booqable.rb
127
+ - lib/booqable/auth.rb
128
+ - lib/booqable/client.rb
129
+ - lib/booqable/configurable.rb
130
+ - lib/booqable/default.rb
131
+ - lib/booqable/error.rb
132
+ - lib/booqable/http.rb
133
+ - lib/booqable/json_api_serializer.rb
134
+ - lib/booqable/middleware/auth/api_key.rb
135
+ - lib/booqable/middleware/auth/oauth.rb
136
+ - lib/booqable/middleware/auth/single_use.rb
137
+ - lib/booqable/middleware/base.rb
138
+ - lib/booqable/middleware/raise_error.rb
139
+ - lib/booqable/oauth_client.rb
140
+ - lib/booqable/rate_limit.rb
141
+ - lib/booqable/resource_proxy.rb
142
+ - lib/booqable/resources.json
143
+ - lib/booqable/resources.rb
144
+ - lib/booqable/version.rb
145
+ - sig/booqable.rbs
146
+ homepage: https://github.com/booqable/booqable.rb
147
+ licenses:
148
+ - MIT
149
+ metadata:
150
+ homepage_uri: https://github.com/booqable/booqable.rb
151
+ source_code_uri: https://github.com/booqable/booqable.rb
152
+ changelog_uri: https://github.com/booqable/booqable.rb/blob/master/CHANGELOG.md
153
+ documentation_uri: https://developers.booqable.com/
154
+ bug_tracker_uri: https://github.com/booqable/booqable.rb/issues
155
+ post_install_message:
156
+ rdoc_options: []
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: 3.2.0
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ requirements: []
170
+ rubygems_version: 3.5.22
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: Official Booqable API client for Ruby.
174
+ test_files: []