pylon-api 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c5b1f37ba1c9f84dbf0f1f0dd9064e85a5b64a0fe327ad3013e40dadb069d8c
4
- data.tar.gz: 7800d67a2bcc68f30e73a1d1558296c69e2f51e45b5a19ab6316d8b9b2ce1807
3
+ metadata.gz: 6d98b4389f4182e2f3d62261c2a60d9f4a325c18a5376c09668cc17e1594219c
4
+ data.tar.gz: ea1c690a74e4e8d2890098211d58909ae551af8deecaf757d3463e5de37f3cdc
5
5
  SHA512:
6
- metadata.gz: ba0a41a8d95c55dc0f02b1a7e165a28f2cca04dac895d9923ccd9edeb0226ca7d67429d4dfd5f0ae7e124462fc028679b311340769d2d18f559897412b06846a
7
- data.tar.gz: f3da4554aba19d6eca7058b075a1e40746e05fe3207dd1cd6257eba4a08f99b548341e1aeac594b95bfc5a87252c79d810d10be1c4331bb1a45737474a16efea
6
+ metadata.gz: b3a1dcd703454b3efc5818292f01a00366a50ddfa5f06d6dbbdbfc865907b907b05ea35d0ca591e0eb93d5ffbec26e4ad90b85e47379aa029f61346b766e81f1
7
+ data.tar.gz: aa703a9d4f20da2243ce49b31627548afd719835a3a591fab2ffafd5480ab84cbce02b3c88a54b25979a8138641b584c9e32054ae673f548ca4936daa2531e53
data/CHANGELOG.md CHANGED
@@ -1,40 +1,25 @@
1
1
  # Changelog
2
- All notable changes to this project will be documented in this file.
3
2
 
4
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
3
+ ## [1.0.0] - 2024-03-21
4
+
5
+ ### Changed
6
+ - Downgraded Faraday dependency from 2.12.2 to 1.10.4 for better compatibility with existing applications
7
+ - Updated Faraday multipart and retry dependencies to match Faraday 1.x compatibility
6
8
 
7
9
  ## [0.2.0] - 2024-03-21
8
10
 
9
11
  ### Added
10
- - Added `snooze_issue` method to support the new issue snooze endpoint
12
+ - Added support for file uploads via multipart/form-data
13
+ - Added retry mechanism for failed requests
14
+ - Added comprehensive error handling and logging
11
15
 
12
- ## [0.1.0] - 2024-03-21
16
+ ### Changed
17
+ - Improved request/response logging
18
+ - Enhanced error messages and documentation
13
19
 
14
- ### Added
15
- - Initial release of the Pylon API Ruby client
16
- - Comprehensive client implementation with support for all major API endpoints:
17
- - Accounts management
18
- - Attachments handling
19
- - Contacts management
20
- - Custom fields
21
- - Issues tracking
22
- - Knowledge base articles
23
- - Tags management
24
- - Teams management
25
- - Ticket forms
26
- - User roles
27
- - Users management
28
- - Robust error handling with specific error classes:
29
- - `Pylon::AuthenticationError`
30
- - `Pylon::ResourceNotFoundError`
31
- - `Pylon::ValidationError`
32
- - `Pylon::ApiError`
33
- - Pagination support for list endpoints
34
- - Debug mode for request/response logging
35
- - Comprehensive test suite with RSpec
36
- - YARD documentation for all methods
37
- - MIT License
20
+ ## [0.1.0] - 2024-03-20
38
21
 
39
- [0.2.0]: https://github.com/benjodo/pylon-api/compare/v0.1.0...v0.2.0
40
- [0.1.0]: https://github.com/benjodo/pylon-api/releases/tag/v0.1.0
22
+ ### Added
23
+ - Initial release
24
+ - Basic API client functionality
25
+ - Support for core API endpoints
data/lib/pylon/client.rb CHANGED
@@ -6,6 +6,7 @@ module Pylon
6
6
  # @example
7
7
  # client = Pylon::Client.new(api_key: 'your_api_key')
8
8
  # issues = client.list_issues(start_time: '2024-03-01T00:00:00Z', end_time: '2024-03-31T23:59:59Z')
9
+ # issues.each { |issue| puts issue.title }
9
10
  class Client
10
11
  # Base URL for the Pylon API
11
12
  BASE_URL = "https://api.usepylon.com"
@@ -28,76 +29,78 @@ module Pylon
28
29
  #
29
30
  # @param page [Integer] Page number for pagination
30
31
  # @param per_page [Integer] Number of items per page
31
- # @return [Array<Hash>] List of accounts
32
+ # @return [Models::Collection<Models::Account>] Collection of account objects
32
33
  def list_accounts(page: 1, per_page: 20)
33
- get("/accounts", query: { page: page, per_page: per_page })
34
+ get("/accounts", query: { page: page, per_page: per_page },
35
+ model_class: Models::Account, collection: true)
34
36
  end
35
37
 
36
38
  # Get details for a specific account
37
39
  #
38
40
  # @param account_id [String] The ID of the account to retrieve
39
- # @return [Hash] Account details
41
+ # @return [Models::Account] Account object
40
42
  def get_account(account_id)
41
- get("/accounts/#{account_id}")
43
+ get("/accounts/#{account_id}", model_class: Models::Account)
42
44
  end
43
45
 
44
46
  # Create a new attachment
45
47
  #
46
48
  # @param file [String] The file content to upload
47
- # @return [Hash] Created attachment details
49
+ # @return [Models::Attachment] Created attachment object
48
50
  def create_attachment(file)
49
- post("/attachments", body: { file: file })
51
+ post("/attachments", body: { file: file }, model_class: Models::Attachment)
50
52
  end
51
53
 
52
54
  # Get details for a specific attachment
53
55
  #
54
56
  # @param attachment_id [String] The ID of the attachment to retrieve
55
- # @return [Hash] Attachment details
57
+ # @return [Models::Attachment] Attachment object
56
58
  def get_attachment(attachment_id)
57
- get("/attachments/#{attachment_id}")
59
+ get("/attachments/#{attachment_id}", model_class: Models::Attachment)
58
60
  end
59
61
 
60
62
  # List all contacts with pagination
61
63
  #
62
64
  # @param page [Integer] Page number for pagination
63
65
  # @param per_page [Integer] Number of items per page
64
- # @return [Array<Hash>] List of contacts
66
+ # @return [Models::Collection<Models::Contact>] Collection of contact objects
65
67
  def list_contacts(page: 1, per_page: 20)
66
- get("/contacts", query: { page: page, per_page: per_page })
68
+ get("/contacts", query: { page: page, per_page: per_page },
69
+ model_class: Models::Contact, collection: true)
67
70
  end
68
71
 
69
72
  # Create a new contact
70
73
  #
71
74
  # @param params [Hash] Contact parameters
72
- # @return [Hash] Created contact details
75
+ # @return [Models::Contact] Created contact object
73
76
  def create_contact(params)
74
- post("/contacts", body: params)
77
+ post("/contacts", body: params, model_class: Models::Contact)
75
78
  end
76
79
 
77
80
  # Get details for a specific contact
78
81
  #
79
82
  # @param contact_id [String] The ID of the contact to retrieve
80
- # @return [Hash] Contact details
83
+ # @return [Models::Contact] Contact object
81
84
  def get_contact(contact_id)
82
- get("/contacts/#{contact_id}")
85
+ get("/contacts/#{contact_id}", model_class: Models::Contact)
83
86
  end
84
87
 
85
88
  # Update an existing contact
86
89
  #
87
90
  # @param contact_id [String] The ID of the contact to update
88
91
  # @param params [Hash] Updated contact parameters
89
- # @return [Hash] Updated contact details
92
+ # @return [Models::Contact] Updated contact object
90
93
  def update_contact(contact_id, params)
91
- patch("/contacts/#{contact_id}", body: params)
94
+ patch("/contacts/#{contact_id}", body: params, model_class: Models::Contact)
92
95
  end
93
96
 
94
97
  # List all custom fields with pagination
95
98
  #
96
99
  # @param page [Integer] Page number for pagination
97
100
  # @param per_page [Integer] Number of items per page
98
- # @return [Array<Hash>] List of custom fields
101
+ # @return [Models::Collection] Collection of custom fields
99
102
  def list_custom_fields(page: 1, per_page: 20)
100
- get("/custom_fields", query: { page: page, per_page: per_page })
103
+ get("/custom_fields", query: { page: page, per_page: per_page }, collection: true)
101
104
  end
102
105
 
103
106
  # Create a new custom field
@@ -115,7 +118,7 @@ module Pylon
115
118
  # @param page [Integer] Page number for pagination
116
119
  # @param per_page [Integer] Number of items per page
117
120
  # @param filters [Hash] Additional filters to apply
118
- # @return [Array<Hash>] List of issues
121
+ # @return [Models::Collection<Models::Issue>] Collection of issue objects
119
122
  # @raise [ArgumentError] If start_time or end_time is missing
120
123
  def list_issues(start_time:, end_time:, page: 1, per_page: 20, **filters)
121
124
  raise ArgumentError, "start_time is required" unless start_time
@@ -126,135 +129,140 @@ module Pylon
126
129
  end_time: end_time,
127
130
  page: page,
128
131
  per_page: per_page
129
- ))
132
+ ), model_class: Models::Issue, collection: true)
130
133
  end
131
134
 
132
135
  # Create a new issue
133
136
  #
134
137
  # @param params [Hash] Issue parameters
135
- # @return [Hash] Created issue details
138
+ # @return [Models::Issue] Created issue object
136
139
  def create_issue(params)
137
- post("/issues", body: params)
140
+ post("/issues", body: params, model_class: Models::Issue)
138
141
  end
139
142
 
140
143
  # Get details for a specific issue
141
144
  #
142
145
  # @param issue_id [String] The ID of the issue to retrieve
143
- # @return [Hash] Issue details
146
+ # @return [Models::Issue] Issue object
144
147
  def get_issue(issue_id)
145
- get("/issues/#{issue_id}")
148
+ get("/issues/#{issue_id}", model_class: Models::Issue)
146
149
  end
147
150
 
148
151
  # Update an existing issue
149
152
  #
150
153
  # @param issue_id [String] The ID of the issue to update
151
154
  # @param params [Hash] Updated issue parameters
152
- # @return [Hash] Updated issue details
155
+ # @return [Models::Issue] Updated issue object
153
156
  def update_issue(issue_id, params)
154
- patch("/issues/#{issue_id}", body: params)
157
+ patch("/issues/#{issue_id}", body: params, model_class: Models::Issue)
155
158
  end
156
159
 
157
160
  # Snooze an issue until a specified time
158
161
  #
159
162
  # @param issue_id [String] The ID or number of the issue to snooze
160
163
  # @param snooze_until [String] The date and time to snooze the issue until (RFC3339 format)
161
- # @return [Hash] Updated issue details
164
+ # @return [Models::Issue] Updated issue object
162
165
  def snooze_issue(issue_id, snooze_until:)
163
- post("/issues/#{issue_id}/snooze", body: { snooze_until: snooze_until })
166
+ post("/issues/#{issue_id}/snooze", body: { snooze_until: snooze_until },
167
+ model_class: Models::Issue)
164
168
  end
165
169
 
166
170
  # List all knowledge base articles with pagination
167
171
  #
168
172
  # @param page [Integer] Page number for pagination
169
173
  # @param per_page [Integer] Number of items per page
170
- # @return [Array<Hash>] List of articles
174
+ # @return [Models::Collection<Models::Article>] Collection of article objects
171
175
  def list_articles(page: 1, per_page: 20)
172
- get("/knowledge_base/articles", query: { page: page, per_page: per_page })
176
+ get("/knowledge_base/articles", query: { page: page, per_page: per_page },
177
+ model_class: Models::Article, collection: true)
173
178
  end
174
179
 
175
180
  # Get details for a specific article
176
181
  #
177
182
  # @param article_id [String] The ID of the article to retrieve
178
- # @return [Hash] Article details
183
+ # @return [Models::Article] Article object
179
184
  def get_article(article_id)
180
- get("/knowledge_base/articles/#{article_id}")
185
+ get("/knowledge_base/articles/#{article_id}", model_class: Models::Article)
181
186
  end
182
187
 
183
188
  # Get details for the current user
184
189
  #
185
- # @return [Hash] Current user details
190
+ # @return [Models::User] Current user object
186
191
  def get_current_user
187
- get("/me")
192
+ get("/me", model_class: Models::User)
188
193
  end
189
194
 
190
195
  # List all tags with pagination
191
196
  #
192
197
  # @param page [Integer] Page number for pagination
193
198
  # @param per_page [Integer] Number of items per page
194
- # @return [Array<Hash>] List of tags
199
+ # @return [Models::Collection<Models::Tag>] Collection of tag objects
195
200
  def list_tags(page: 1, per_page: 20)
196
- get("/tags", query: { page: page, per_page: per_page })
201
+ get("/tags", query: { page: page, per_page: per_page },
202
+ model_class: Models::Tag, collection: true)
197
203
  end
198
204
 
199
205
  # Create a new tag
200
206
  #
201
207
  # @param name [String] The name of the tag
202
208
  # @param color [String] Optional hex color code for the tag
203
- # @return [Hash] Created tag details
209
+ # @return [Models::Tag] Created tag object
204
210
  def create_tag(name:, color: nil)
205
- post("/tags", body: { name: name, color: color }.compact)
211
+ post("/tags", body: { name: name, color: color }.compact, model_class: Models::Tag)
206
212
  end
207
213
 
208
214
  # List all teams with pagination
209
215
  #
210
216
  # @param page [Integer] Page number for pagination
211
217
  # @param per_page [Integer] Number of items per page
212
- # @return [Array<Hash>] List of teams
218
+ # @return [Models::Collection<Models::Team>] Collection of team objects
213
219
  def list_teams(page: 1, per_page: 20)
214
- get("/teams", query: { page: page, per_page: per_page })
220
+ get("/teams", query: { page: page, per_page: per_page },
221
+ model_class: Models::Team, collection: true)
215
222
  end
216
223
 
217
224
  # Create a new team
218
225
  #
219
226
  # @param params [Hash] Team parameters
220
- # @return [Hash] Created team details
227
+ # @return [Models::Team] Created team object
221
228
  def create_team(params)
222
- post("/teams", body: params)
229
+ post("/teams", body: params, model_class: Models::Team)
223
230
  end
224
231
 
225
232
  # Get details for a specific team
226
233
  #
227
234
  # @param team_id [String] The ID of the team to retrieve
228
- # @return [Hash] Team details
235
+ # @return [Models::Team] Team object
229
236
  def get_team(team_id)
230
- get("/teams/#{team_id}")
237
+ get("/teams/#{team_id}", model_class: Models::Team)
231
238
  end
232
239
 
233
240
  # List all ticket forms with pagination
234
241
  #
235
242
  # @param page [Integer] Page number for pagination
236
243
  # @param per_page [Integer] Number of items per page
237
- # @return [Array<Hash>] List of ticket forms
244
+ # @return [Models::Collection<Models::TicketForm>] Collection of ticket form objects
238
245
  def list_ticket_forms(page: 1, per_page: 20)
239
- get("/ticket-forms", query: { page: page, per_page: per_page })
246
+ get("/ticket-forms", query: { page: page, per_page: per_page },
247
+ model_class: Models::TicketForm, collection: true)
240
248
  end
241
249
 
242
250
  # Create a new ticket form
243
251
  #
244
252
  # @param name [String] The name of the form
245
253
  # @param fields [Array<Hash>] Array of form field definitions
246
- # @return [Hash] Created ticket form details
254
+ # @return [Models::TicketForm] Created ticket form object
247
255
  def create_ticket_form(name:, fields: [])
248
- post("/ticket-forms", body: { name: name, fields: fields })
256
+ post("/ticket-forms", body: { name: name, fields: fields }, model_class: Models::TicketForm)
249
257
  end
250
258
 
251
259
  # List all user roles with pagination
252
260
  #
253
261
  # @param page [Integer] Page number for pagination
254
262
  # @param per_page [Integer] Number of items per page
255
- # @return [Array<Hash>] List of user roles
263
+ # @return [Models::Collection] Collection of user role objects
256
264
  def list_user_roles(page: 1, per_page: 20)
257
- get("/user_roles", query: { page: page, per_page: per_page })
265
+ get("/user_roles", query: { page: page, per_page: per_page }, collection: true)
258
266
  end
259
267
 
260
268
  # Get details for a specific user role
@@ -269,34 +277,35 @@ module Pylon
269
277
  #
270
278
  # @param page [Integer] Page number for pagination
271
279
  # @param per_page [Integer] Number of items per page
272
- # @return [Array<Hash>] List of users
280
+ # @return [Models::Collection<Models::User>] Collection of user objects
273
281
  def list_users(page: 1, per_page: 20)
274
- get("/users", query: { page: page, per_page: per_page })
282
+ get("/users", query: { page: page, per_page: per_page },
283
+ model_class: Models::User, collection: true)
275
284
  end
276
285
 
277
286
  # Create a new user
278
287
  #
279
288
  # @param params [Hash] User parameters
280
- # @return [Hash] Created user details
289
+ # @return [Models::User] Created user object
281
290
  def create_user(params)
282
- post("/users", body: params)
291
+ post("/users", body: params, model_class: Models::User)
283
292
  end
284
293
 
285
294
  # Get details for a specific user
286
295
  #
287
296
  # @param user_id [String] The ID of the user to retrieve
288
- # @return [Hash] User details
297
+ # @return [Models::User] User object
289
298
  def get_user(user_id)
290
- get("/users/#{user_id}")
299
+ get("/users/#{user_id}", model_class: Models::User)
291
300
  end
292
301
 
293
302
  # Update an existing user
294
303
  #
295
304
  # @param user_id [String] The ID of the user to update
296
305
  # @param params [Hash] Updated user parameters
297
- # @return [Hash] Updated user details
306
+ # @return [Models::User] Updated user object
298
307
  def update_user(user_id, params)
299
- patch("/users/#{user_id}", body: params)
308
+ patch("/users/#{user_id}", body: params, model_class: Models::User)
300
309
  end
301
310
 
302
311
  private
@@ -306,7 +315,7 @@ module Pylon
306
315
  @connection ||= Faraday.new(@base_url) do |f|
307
316
  f.request :json
308
317
  f.request :multipart
309
- f.response :json
318
+ f.response :json, content_type: /\bjson$/
310
319
  f.response :logger if @debug
311
320
  f.adapter Faraday.default_adapter
312
321
  f.headers["Authorization"] = "Bearer #{api_key}"
@@ -318,31 +327,67 @@ module Pylon
318
327
  # Handle API response and raise appropriate errors
319
328
  #
320
329
  # @param response [Faraday::Response] The API response
321
- # @return [Array] Array containing response data and response object
330
+ # @param model_class [Class] The model class to use for wrapping the response
331
+ # @param collection [Boolean] Whether the response is a collection of items
332
+ # @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
322
333
  # @raise [AuthenticationError] If authentication fails
323
334
  # @raise [ResourceNotFoundError] If resource is not found
324
335
  # @raise [ValidationError] If request parameters are invalid
325
336
  # @raise [ApiError] For other API errors
326
- def handle_response(response)
337
+ def handle_response(response, model_class = nil, collection = false)
327
338
  if @debug
328
339
  puts "Request URL: #{response.env.url}"
329
340
  puts "Response status: #{response.status}"
330
341
  puts "Response body: #{response.body.inspect}"
331
342
  end
332
343
 
333
- case response.status
334
- when 200..299
335
- data = response.body
336
- data = data["data"] if data.is_a?(Hash) && data.key?("data")
344
+ if response.status.between?(200, 299)
345
+ return handle_successful_response(response, model_class, collection)
346
+ else
347
+ handle_error_response(response)
348
+ end
349
+ end
350
+
351
+ # Handle successful API response
352
+ #
353
+ # @param response [Faraday::Response] The API response
354
+ # @param model_class [Class] The model class to use for wrapping the response
355
+ # @param collection [Boolean] Whether the response is a collection of items
356
+ # @return [Models::Base, Models::Collection, Array] Wrapped response data
357
+ def handle_successful_response(response, model_class, collection)
358
+ data = response.body
359
+ data = data["data"] if data.is_a?(Hash) && data.key?("data")
360
+
361
+ if model_class
362
+ if collection
363
+ Models::Collection.new(data, model_class, response)
364
+ else
365
+ model_class.new(data, response)
366
+ end
367
+ else
337
368
  [data, response]
369
+ end
370
+ end
371
+
372
+ # Handle error API response
373
+ #
374
+ # @param response [Faraday::Response] The API response
375
+ # @raise [AuthenticationError] If authentication fails
376
+ # @raise [ResourceNotFoundError] If resource is not found
377
+ # @raise [ValidationError] If request parameters are invalid
378
+ # @raise [ApiError] For other API errors
379
+ def handle_error_response(response)
380
+ case response.status
338
381
  when 401
339
- raise AuthenticationError, parse_error_message(response)
382
+ raise AuthenticationError, parse_error_message(response) || "Invalid API key"
340
383
  when 404
341
- raise ResourceNotFoundError, parse_error_message(response)
384
+ raise ResourceNotFoundError, parse_error_message(response) || "Resource not found"
342
385
  when 422
343
- raise ValidationError, parse_error_message(response)
386
+ raise ValidationError, parse_error_message(response) || "Validation error"
387
+ when 429
388
+ raise ApiError, parse_error_message(response) || "Rate limit exceeded"
344
389
  else
345
- raise ApiError.new(parse_error_message(response), response)
390
+ raise ApiError.new(parse_error_message(response) || "Internal server error", response)
346
391
  end
347
392
  end
348
393
 
@@ -351,10 +396,12 @@ module Pylon
351
396
  # @param response [Faraday::Response] The API response
352
397
  # @return [String] Error message
353
398
  def parse_error_message(response)
354
- if response.body.is_a?(Hash)
355
- response.body["errors"]&.first || response.body["error"] || "HTTP #{response.status}"
356
- else
357
- "HTTP #{response.status}"
399
+ return nil unless response.body.is_a?(Hash)
400
+
401
+ if response.body["errors"].is_a?(Array) && !response.body["errors"].empty?
402
+ response.body["errors"].first
403
+ elsif response.body["error"].is_a?(String)
404
+ response.body["error"]
358
405
  end
359
406
  end
360
407
 
@@ -362,35 +409,43 @@ module Pylon
362
409
  #
363
410
  # @param path [String] The API endpoint path
364
411
  # @param query [Hash] Query parameters
365
- # @return [Array] Array containing response data and response object
366
- def get(path, query: {})
367
- handle_response(connection.get(path, query))
412
+ # @param model_class [Class] The model class to use for wrapping the response
413
+ # @param collection [Boolean] Whether the response is a collection of items
414
+ # @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
415
+ def get(path, query: {}, model_class: nil, collection: false)
416
+ handle_response(connection.get(path, query), model_class, collection)
368
417
  end
369
418
 
370
419
  # Make a POST request
371
420
  #
372
421
  # @param path [String] The API endpoint path
373
422
  # @param body [Hash] Request body
374
- # @return [Array] Array containing response data and response object
375
- def post(path, body: {})
376
- handle_response(connection.post(path, body.to_json))
423
+ # @param model_class [Class] The model class to use for wrapping the response
424
+ # @param collection [Boolean] Whether the response is a collection of items
425
+ # @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
426
+ def post(path, body: {}, model_class: nil, collection: false)
427
+ handle_response(connection.post(path, body.to_json), model_class, collection)
377
428
  end
378
429
 
379
430
  # Make a PATCH request
380
431
  #
381
432
  # @param path [String] The API endpoint path
382
433
  # @param body [Hash] Request body
383
- # @return [Array] Array containing response data and response object
384
- def patch(path, body: {})
385
- handle_response(connection.patch(path, body.to_json))
434
+ # @param model_class [Class] The model class to use for wrapping the response
435
+ # @param collection [Boolean] Whether the response is a collection of items
436
+ # @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
437
+ def patch(path, body: {}, model_class: nil, collection: false)
438
+ handle_response(connection.patch(path, body.to_json), model_class, collection)
386
439
  end
387
440
 
388
441
  # Make a DELETE request
389
442
  #
390
443
  # @param path [String] The API endpoint path
391
- # @return [Array] Array containing response data and response object
392
- def delete(path)
393
- handle_response(connection.delete(path))
444
+ # @param model_class [Class] The model class to use for wrapping the response
445
+ # @param collection [Boolean] Whether the response is a collection of items
446
+ # @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
447
+ def delete(path, model_class: nil, collection: false)
448
+ handle_response(connection.delete(path), model_class, collection)
394
449
  end
395
450
  end
396
- end
451
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class Account < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class Article < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class Attachment < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class Base
6
+ attr_reader :attributes, :_response
7
+
8
+ def initialize(attributes = {}, response = nil)
9
+ @attributes = attributes || {}
10
+ @_response = response
11
+ end
12
+
13
+ def method_missing(method_name, *args, &block)
14
+ key = method_name.to_s
15
+ if @attributes.key?(key)
16
+ @attributes[key]
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def respond_to_missing?(method_name, include_private = false)
23
+ @attributes.key?(method_name.to_s) || super
24
+ end
25
+
26
+ def [](key)
27
+ @attributes[key.to_s]
28
+ end
29
+
30
+ def to_h
31
+ @attributes
32
+ end
33
+ alias to_hash to_h
34
+
35
+ def inspect
36
+ "#<#{self.class.name} #{@attributes.inspect}>"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class Collection
6
+ include Enumerable
7
+
8
+ attr_reader :items, :_response
9
+
10
+ def initialize(items = [], model_class = nil, response = nil)
11
+ @items = items.map do |item|
12
+ model_class ? model_class.new(item) : item
13
+ end
14
+ @_response = response
15
+ end
16
+
17
+ def each(&block)
18
+ @items.each(&block)
19
+ end
20
+
21
+ def [](index)
22
+ @items[index]
23
+ end
24
+
25
+ def size
26
+ @items.size
27
+ end
28
+ alias length size
29
+
30
+ def to_a
31
+ @items
32
+ end
33
+
34
+ def inspect
35
+ "#<#{self.class.name} items=#{@items.size}>"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class Contact < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class Issue < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class Tag < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class Team < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class TicketForm < Base
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pylon
4
+ module Models
5
+ class User < Base
6
+ end
7
+ end
8
+ end
data/lib/pylon/version.rb CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Pylon
4
4
  # Major version for breaking changes
5
- MAJOR = 0
5
+ MAJOR = 1
6
6
  # Minor version for new features
7
- MINOR = 2
7
+ MINOR = 1
8
8
  # Patch version for bug fixes
9
9
  PATCH = 0
10
10
  # Pre-release version (optional)
data/lib/pylon.rb CHANGED
@@ -5,6 +5,17 @@ require "faraday/multipart"
5
5
  require "json"
6
6
 
7
7
  require_relative "pylon/version"
8
+ require_relative "pylon/models/base"
9
+ require_relative "pylon/models/collection"
10
+ require_relative "pylon/models/user"
11
+ require_relative "pylon/models/account"
12
+ require_relative "pylon/models/issue"
13
+ require_relative "pylon/models/team"
14
+ require_relative "pylon/models/tag"
15
+ require_relative "pylon/models/attachment"
16
+ require_relative "pylon/models/contact"
17
+ require_relative "pylon/models/ticket_form"
18
+ require_relative "pylon/models/article"
8
19
  require_relative "pylon/client"
9
20
 
10
21
  module Pylon
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pylon-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Odom
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-30 00:00:00.000000000 Z
11
+ date: 2025-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.12.2
19
+ version: 1.10.4
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.12.2
26
+ version: 1.10.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: faraday-multipart
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: 1.0.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.0'
40
+ version: 1.0.4
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday-retry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.0.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.3
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -120,6 +134,17 @@ files:
120
134
  - README.md
121
135
  - lib/pylon.rb
122
136
  - lib/pylon/client.rb
137
+ - lib/pylon/models/account.rb
138
+ - lib/pylon/models/article.rb
139
+ - lib/pylon/models/attachment.rb
140
+ - lib/pylon/models/base.rb
141
+ - lib/pylon/models/collection.rb
142
+ - lib/pylon/models/contact.rb
143
+ - lib/pylon/models/issue.rb
144
+ - lib/pylon/models/tag.rb
145
+ - lib/pylon/models/team.rb
146
+ - lib/pylon/models/ticket_form.rb
147
+ - lib/pylon/models/user.rb
123
148
  - lib/pylon/version.rb
124
149
  - lib/tasks/version.rake
125
150
  homepage: https://github.com/benjodo/pylon-api