tcat 0.2.2 → 0.4.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: 85733c0ed940c2fad6b032f5fed76ddc64dfacba3b3789294d60c8937f90dfdc
4
- data.tar.gz: 37fbf765f958b1111eb19e02eb0c7e9bfd7298a74f64971505aa238fd64ead3f
3
+ metadata.gz: 5ed5fe975474cdb30f8d660719b0a59d0ea5f1813b4e86433c95cd2ee82c795e
4
+ data.tar.gz: 025bf6aa6cfc46a4437d72e1d8abc966853606c1ba58b56ea5f6334a541b063e
5
5
  SHA512:
6
- metadata.gz: 1ecf263b82fd1e236ed577d9d2be12e73b4a708b3e6e98ca3861817a82b3955c60acc2a5a389a2b8d925c298e0f46922e37f9000449718a40e5d80d2507be1c3
7
- data.tar.gz: 19bbb76b59696fe11a330d625c371383cc5e01d42dab4314182987597dccc850bd3504cd3c50891fbcb77fbc286d01d3a315794dcba0801dca4b953409c2ad27
6
+ metadata.gz: b59a640cf706df074a2daa9bac89dfed2d96b1cfa1720278afe00b66ca8991cf64c096e4fca3701b05e7f43009b71f5f2e57186c902b339000d76db6098f4b13
7
+ data.tar.gz: 4d678f18e49855e6faf85ac8f4b0969f7c3c6d7d8a176686cd31ecc875e871a36ac3452a19dc9e5c7cd02ef559fdccf4e727085984c52d0066456f1b8b27302c
data/README.md CHANGED
@@ -2,13 +2,30 @@
2
2
 
3
3
  A Ruby gem for tracking T-Cat (Taiwan Pelican Express) shipment status. Provides a simple and easy-to-use API interface.
4
4
 
5
+ ## ✨ Two Ways to Use Tcat
6
+
7
+ ### 1. Ruby Gem (This Repository)
8
+ Perfect for Ruby/Rails applications with direct integration.
9
+
10
+ ### 2. Cloudflare Worker API
11
+ Looking for a serverless solution? Check out **[worker/README.md](worker/README.md)**
12
+
13
+ Benefits of the Worker version:
14
+ - 🌍 Global edge deployment for faster queries worldwide
15
+ - 🔒 Secure secret storage in environment variables
16
+ - 🌐 HTTP API accessible from any platform (JavaScript, Python, cURL, etc.)
17
+ - 💰 Cost-effective: 100K free requests/day
18
+ - 📱 Perfect for frontend apps, mobile apps, or microservices
19
+
20
+ ---
21
+
5
22
  ## Features
6
23
 
7
- - Track shipment status
8
- - Secure encrypted requests
9
- - Simple API interface
10
- - Non-blocking HTTP requests
11
- - Comprehensive error handling
24
+ - 📦 Track shipment status
25
+ - 🔐 Secure encrypted requests
26
+ - 🌐 Simple API interface
27
+ - Non-blocking HTTP requests
28
+ - 🛡️ Comprehensive error handling
12
29
 
13
30
  ## Installation
14
31
 
@@ -30,40 +47,47 @@ Or install it yourself as:
30
47
  $ gem install tcat
31
48
  ```
32
49
 
33
- ## Configuration
50
+ ## Usage
34
51
 
35
- Configure the gem before use:
52
+ There are two ways to use this gem:
53
+
54
+ 1. **Direct API Access** - Query T-Cat API directly from your Ruby application
55
+ 2. **Cloudflare Worker** - Query through a Cloudflare Worker proxy (recommended for production)
56
+
57
+ ### Option 1: Direct API Access
58
+
59
+ Configure the gem with your T-Cat API credentials:
36
60
 
37
61
  ```ruby
38
62
  Tcat.configure do |config|
39
63
  config.secret_string = 'your_secret_string'
40
64
  config.secret_key = 'your_secret_key'
41
65
  end
42
- ```
43
-
44
- ## Usage
45
66
 
46
- ### Basic Usage
67
+ # Two equivalent shapes — pick whichever fits your code:
47
68
 
48
- ```ruby
49
- # Create a query instance
69
+ # A) tracking number bound at construction (one-shot)
50
70
  query = Tcat::Query.new('your_tracking_number')
51
-
52
- # Get shipment status
53
71
  status = query.status_code
72
+
73
+ # B) tracking number per call (reuse one client for many lookups,
74
+ # matches Tcat::WorkerClient's shape)
75
+ query = Tcat::Query.new
76
+ status = query.status_code('your_tracking_number')
54
77
  # Returns one of the following:
55
- # :done - Successfully delivered
56
- # :delivering - Out for delivery
57
- # :collected - Package collected
58
- # :in_transit - In transit
59
- # :returned - Return completed
60
- # :held - Held at post office
61
- # :rescheduled - Delivery time rescheduled
62
- # :forwarding - Being forwarded
63
- # :investigation - Under investigation
64
- # :rejected - Delivery rejected
65
- # :returning - In return process
66
- # :unknown - Unknown status
78
+ # :done - Successfully delivered
79
+ # :delivering - Out for delivery
80
+ # :collected - Package collected
81
+ # :in_transit - In transit
82
+ # :returned - Return completed
83
+ # :held - Held at post office
84
+ # :rescheduled - Delivery time rescheduled
85
+ # :forwarding - Being forwarded
86
+ # :investigation - Under investigation
87
+ # :rejected - Delivery rejected
88
+ # :returning - In return process
89
+ # :store_delivery - At convenience store for pickup
90
+ # :unknown - Unknown status
67
91
 
68
92
  # Get latest status details
69
93
  latest = query.latest_status
@@ -85,6 +109,84 @@ history.each do |item|
85
109
  end
86
110
  ```
87
111
 
112
+ ### Option 2: Via Cloudflare Worker (Recommended)
113
+
114
+ The Worker approach is recommended for production because:
115
+ - ✅ Secrets are stored securely in Cloudflare, not in your application
116
+ - ✅ Faster response times via Cloudflare's edge network
117
+ - ✅ No need to manage encryption in your Ruby app
118
+ - ✅ Can be used by any language/platform (not just Ruby)
119
+
120
+ First, deploy the Cloudflare Worker (see [worker/README.md](worker/README.md) for deployment instructions).
121
+
122
+ Then use the WorkerClient in your Ruby application. You can pass the Worker
123
+ URL (and optional Bearer token) directly, or configure them globally via
124
+ `Tcat.configure`:
125
+
126
+ ```ruby
127
+ # Option A: explicit per-instance arguments
128
+ client = Tcat::WorkerClient.new(
129
+ 'https://your-worker.workers.dev',
130
+ token: ENV['TCAT_WORKER_TOKEN'] # only needed when AUTH_TOKEN is set on the Worker
131
+ )
132
+
133
+ # Option B: global configuration, then construct without arguments
134
+ Tcat.configure do |config|
135
+ config.worker_url = 'https://your-worker.workers.dev'
136
+ config.worker_token = ENV['TCAT_WORKER_TOKEN']
137
+ end
138
+ client = Tcat::WorkerClient.new
139
+
140
+ # Explicit args always override configuration:
141
+ override = Tcat::WorkerClient.new('https://other.workers.dev', token: 'other-token')
142
+
143
+ # Get shipment status (same API as Query)
144
+ status = client.status_code('your_tracking_number')
145
+ # => :delivering
146
+
147
+ # Get latest status details
148
+ latest = client.latest_status('your_tracking_number')
149
+ if latest
150
+ puts "Status: #{latest.status}" # e.g. "配送中"
151
+ puts "Status code: #{latest.status_code}" # e.g. :delivering
152
+ puts "Time: #{latest.time}" # Time object
153
+ puts "Office: #{latest.office}" # e.g. "台北營業所"
154
+ end
155
+
156
+ # Get full shipment history
157
+ history = client.history('your_tracking_number')
158
+ history.each do |item|
159
+ puts "Status: #{item.status}"
160
+ puts "Time: #{item.time}"
161
+ puts "Office: #{item.office}"
162
+ puts "---"
163
+ end
164
+
165
+ # Check if Worker is healthy
166
+ if client.healthy?
167
+ puts "Worker is operational"
168
+ end
169
+ ```
170
+
171
+ **Custom timeout:**
172
+
173
+ ```ruby
174
+ # Default timeout is 30 seconds
175
+ client = Tcat::WorkerClient.new('https://your-worker.workers.dev', timeout: 60)
176
+ ```
177
+
178
+ **Error handling:**
179
+
180
+ ```ruby
181
+ begin
182
+ status = client.status_code('tracking_number')
183
+ rescue Tcat::WorkerClient::NetworkError => e
184
+ puts "Network error: #{e.message}"
185
+ rescue Tcat::WorkerClient::APIError => e
186
+ puts "API error: #{e.message}"
187
+ end
188
+ ```
189
+
88
190
  ### Status Code Explanation
89
191
 
90
192
  - `:done` - Successfully delivered
@@ -98,20 +200,52 @@ end
98
200
  - `:investigation` - Package is under investigation (e.g., address change, rejection)
99
201
  - `:rejected` - Delivery was rejected
100
202
  - `:returning` - Package is in return process
203
+ - `:store_delivery` - Handed over to a convenience store, awaiting recipient pickup
101
204
  - `:unknown` - Unknown status
102
205
 
103
- ## Development
206
+ ## Cloudflare Worker
104
207
 
105
- 1. Fork the project
106
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
107
- 3. Commit your changes (`git commit -am 'Add some amazing feature'`)
108
- 4. Push to the branch (`git push origin feature/amazing-feature`)
109
- 5. Create a Pull Request
208
+ This repository includes a Cloudflare Worker implementation that provides an HTTP API for T-Cat tracking.
209
+
210
+ ### Features
211
+
212
+ - 🌍 Deploy globally on Cloudflare's edge network
213
+ - 🔒 Securely store API credentials as Worker secrets
214
+ - 🚀 Fast response times from edge locations
215
+ - 🌐 CORS enabled for frontend applications
216
+ - 📱 Works with any programming language
217
+
218
+ ### Quick Start
219
+
220
+ ```bash
221
+ cd worker
222
+ npm install
223
+ npm run dev # Start local development server
224
+ ```
225
+
226
+ For full deployment instructions, see [worker/README.md](worker/README.md) and [worker/DEPLOYMENT.md](worker/DEPLOYMENT.md).
227
+
228
+ ## Comparison: Direct API vs Worker
229
+
230
+ | Feature | Direct API (`Query`) | Cloudflare Worker (`WorkerClient`) |
231
+ |---------|---------------------|-----------------------------------|
232
+ | Setup complexity | Low (just gem install) | Medium (requires Worker deployment) |
233
+ | Security | Secrets in your app | Secrets in Cloudflare |
234
+ | Performance | Direct to T-Cat API | Via Cloudflare edge |
235
+ | Multi-platform | Ruby only | Any language/platform |
236
+ | Cost | Free | Free tier available |
237
+ | Best for | Simple scripts, internal tools | Production apps, public APIs |
238
+
239
+ ## Development
110
240
 
111
241
  ### Running Tests
112
242
 
113
243
  ```bash
244
+ # Run all tests
114
245
  $ bundle exec rake spec
246
+
247
+ # Run specific test file
248
+ $ bundle exec rspec spec/tcat/worker_client_spec.rb
115
249
  ```
116
250
 
117
251
  ### Local Installation
@@ -124,12 +258,56 @@ $ bundle exec rake install
124
258
 
125
259
  Bug reports and pull requests are welcome.
126
260
 
261
+ 1. Fork the project
262
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
263
+ 3. Commit your changes (`git commit -am 'Add some amazing feature'`)
264
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
265
+ 5. Create a Pull Request
266
+
127
267
  ## License
128
268
 
129
269
  This gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
130
270
 
131
271
  ## Changelog
132
272
 
273
+ ### 0.4.0
274
+
275
+ - `Tcat::Query#status_code`, `#history`, `#latest_status` now accept an optional tracking-number argument, mirroring `Tcat::WorkerClient`'s shape
276
+ - `Tcat::Query.new` may be called without a tracking number for stateless reuse: `Tcat::Query.new.status_code('1234567890')`
277
+ - Existing one-shot construction (`Tcat::Query.new(tn).status_code`) is still supported
278
+
279
+ ### 0.3.5
280
+
281
+ - Added optional `worker_url` and `worker_token` to `Tcat.configure`; explicit `Tcat::WorkerClient.new(url, token:)` arguments still take precedence
282
+ - `Tcat::WorkerClient.new` now accepts no arguments when `worker_url` is set in configuration
283
+
284
+ ### 0.3.4
285
+
286
+ - Bundled the 0.3.3 fixes for release on RubyGems
287
+
288
+ ### 0.3.3
289
+
290
+ - Worker now subtracts the Taiwan UTC+8 offset when emitting ISO timestamps (previously every event was reported 8 hours later than reality)
291
+ - Worker forwards only the `name=value` portion of `Set-Cookie` to the upstream `Cookie:` header (RFC 6265)
292
+ - Worker rejects `/query` with HTTP 401 when `AUTH_TOKEN` is not configured (fail-closed)
293
+ - 5xx responses no longer leak `error.message`; details are written to `console.error` (visible via `wrangler tail`)
294
+
295
+ ### 0.3.2
296
+
297
+ - Added optional Bearer token auth to the Cloudflare Worker (`AUTH_TOKEN` secret)
298
+ - `Tcat::WorkerClient` accepts a `token:` keyword arg that is sent as `Authorization: Bearer <token>`
299
+ - Worker compares tokens in constant time; CORS allow-headers gain `Authorization`
300
+
301
+ ### 0.3.1
302
+
303
+ - Tightened `tcat.gemspec` so the published gem no longer bundles the `worker/` subproject or dev-only configs
304
+
305
+ ### 0.3.0
306
+
307
+ - Added `Tcat::WorkerClient` to query a Cloudflare Worker proxy instead of T-Cat directly
308
+ - Added new status mapping: `:store_delivery` for `轉交超商配達` (handed over to convenience store)
309
+ - Added the `worker/` Cloudflare Worker subproject (separate from the gem release)
310
+
133
311
  ### 0.2.2
134
312
 
135
313
  - Fixed status parsing to handle HTML tags in API responses
@@ -3,11 +3,18 @@
3
3
  module Tcat
4
4
  # Configuration class handles settings for Tcat
5
5
  class Configuration
6
+ # T-Cat API credentials (used by Tcat::Query)
6
7
  attr_accessor :secret_string, :secret_key
7
8
 
9
+ # Cloudflare Worker proxy settings (used by Tcat::WorkerClient)
10
+ # Both are optional; explicit constructor args take precedence.
11
+ attr_accessor :worker_url, :worker_token
12
+
8
13
  def initialize
9
14
  @secret_string = nil
10
15
  @secret_key = nil
16
+ @worker_url = nil
17
+ @worker_token = nil
11
18
  end
12
19
  end
13
20
  end
data/lib/tcat/query.rb CHANGED
@@ -11,7 +11,11 @@ module Tcat
11
11
  class Query
12
12
  DeliveryItem = Struct.new(:status, :status_code, :time, :office, :last_update, keyword_init: true)
13
13
 
14
- def initialize(tracking_number)
14
+ # @param tracking_number [String, nil] Default tracking number used when
15
+ # the per-call methods are invoked without an explicit argument. Pass nil
16
+ # to construct a stateless client and supply the tracking number on each
17
+ # call (matching Tcat::WorkerClient's shape).
18
+ def initialize(tracking_number = nil)
15
19
  @secret_string = Tcat.configuration.secret_string
16
20
  @secret_key = Tcat.configuration.secret_key
17
21
  validate_secrets!
@@ -25,22 +29,27 @@ module Tcat
25
29
  end
26
30
 
27
31
  # Get current delivery status code
32
+ # @param tracking_number [String, nil] Overrides the constructor value.
28
33
  # @return [Symbol] Status code (:done, :delivering, :collected, :in_transit, :unknown)
29
- def status_code
30
- response_body = @http_client.post(data)
34
+ def status_code(tracking_number = nil)
35
+ tn = resolve_tracking_number(tracking_number)
36
+ response_body = @http_client.post(data(tn))
31
37
  parse_status_code(response_body) if response_body
32
- rescue HttpClient::RequestError => e
38
+ rescue HttpClient::RequestError
33
39
  # Log error or handle it appropriately
34
40
  nil
35
41
  end
36
42
 
37
43
  # Get complete delivery history
44
+ # @param tracking_number [String, nil] Overrides the constructor value.
38
45
  # @return [Array<DeliveryItem>] Array of delivery status items, sorted by time (newest first)
39
- def history
40
- response_body = @http_client.post(data)
46
+ def history(tracking_number = nil)
47
+ tn = resolve_tracking_number(tracking_number)
48
+ response_body = @http_client.post(data(tn))
41
49
  if response_body
42
50
  result = Ox.load(response_body, mode: :hash, with_cdata: true)
43
51
  return [] if result.dig(:Result, :Status) != '0'
52
+
44
53
  extract_delivery_history(result)
45
54
  end
46
55
  rescue StandardError => e
@@ -49,10 +58,12 @@ module Tcat
49
58
  end
50
59
 
51
60
  # Get latest delivery status with details
61
+ # @param tracking_number [String, nil] Overrides the constructor value.
52
62
  # @return [DeliveryItem, nil] Latest delivery status or nil if no history
53
- def latest_status
54
- items = history
63
+ def latest_status(tracking_number = nil)
64
+ items = history(tracking_number)
55
65
  return nil if items.empty?
66
+
56
67
  items.first
57
68
  end
58
69
 
@@ -75,9 +86,16 @@ module Tcat
75
86
  warn e.backtrace.first(5).join("\n") if $DEBUG
76
87
  end
77
88
 
78
- def data
89
+ def resolve_tracking_number(arg)
90
+ tn = arg || @tracking_number
91
+ raise ArgumentError, 'tracking number required' if tn.nil? || tn.to_s.empty?
92
+
93
+ tn
94
+ end
95
+
96
+ def data(tracking_number)
79
97
  {
80
- ConsignmentNo: @tracking_number,
98
+ ConsignmentNo: tracking_number,
81
99
  f: 5,
82
100
  isForeign: 'N',
83
101
  secret: generate_secret,
@@ -193,7 +211,8 @@ module Tcat
193
211
  '搬家(調查處理中)' => :investigation,
194
212
  '拒收(調查處理中)' => :investigation,
195
213
  '拒收' => :rejected,
196
- '客樂得貨物退回中' => :returning
214
+ '客樂得貨物退回中' => :returning,
215
+ '轉交超商配達' => :store_delivery
197
216
  }.freeze
198
217
 
199
218
  def parse_status_message(statuses)
data/lib/tcat/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tcat
4
- VERSION = '0.2.2'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
6
+
7
+ module Tcat
8
+ # WorkerClient provides a simple interface to query T-Cat tracking via Cloudflare Worker
9
+ # This is an alternative to the direct Query class that goes through your deployed Worker
10
+ class WorkerClient
11
+ class WorkerError < StandardError; end
12
+ class NetworkError < WorkerError; end
13
+ class APIError < WorkerError; end
14
+
15
+ DeliveryItem = Struct.new(:status, :status_code, :time, :office, :last_update, keyword_init: true)
16
+
17
+ attr_reader :worker_url
18
+
19
+ # Initialize a new WorkerClient
20
+ # @param worker_url [String, nil] The URL of your deployed Cloudflare
21
+ # Worker. Falls back to `Tcat.configuration.worker_url` when omitted.
22
+ # @param timeout [Integer] Request timeout in seconds (default: 30)
23
+ # @param token [String, nil] Bearer token sent in the Authorization
24
+ # header when the Worker is configured with AUTH_TOKEN. Falls back to
25
+ # `Tcat.configuration.worker_token` when omitted.
26
+ def initialize(worker_url = nil, timeout: 30, token: nil)
27
+ url = worker_url || Tcat.configuration.worker_url
28
+ raise ArgumentError, 'Worker URL must be configured' if url.nil? || url.empty?
29
+
30
+ @worker_url = url.chomp('/')
31
+ @timeout = timeout
32
+ @token = token || Tcat.configuration.worker_token
33
+ validate_url!
34
+ end
35
+
36
+ # Query a tracking number through the Worker
37
+ # @param tracking_number [String] The tracking number to query
38
+ # @return [Hash] Parsed response from the Worker
39
+ def query(tracking_number)
40
+ raise ArgumentError, 'Tracking number cannot be nil or empty' if tracking_number.nil? || tracking_number.empty?
41
+
42
+ uri = URI("#{@worker_url}/query")
43
+ uri.query = URI.encode_www_form(no: tracking_number)
44
+
45
+ response = make_request(uri)
46
+ parse_response(response)
47
+ rescue SocketError, Net::HTTPError => e
48
+ raise NetworkError, "Network error: #{e.message}"
49
+ rescue JSON::ParserError => e
50
+ raise APIError, "Invalid JSON response: #{e.message}"
51
+ end
52
+
53
+ # Get the current status code for a tracking number
54
+ # @param tracking_number [String] The tracking number to query
55
+ # @return [Symbol, nil] Status code symbol or nil if error
56
+ def status_code(tracking_number)
57
+ result = query(tracking_number)
58
+ result[:status_code]&.to_sym
59
+ rescue WorkerError => e
60
+ warn "Error getting status: #{e.message}" if $DEBUG
61
+ nil
62
+ end
63
+
64
+ # Get the complete delivery history
65
+ # @param tracking_number [String] The tracking number to query
66
+ # @return [Array<DeliveryItem>] Array of delivery history items
67
+ def history(tracking_number)
68
+ result = query(tracking_number)
69
+ items = result[:items] || []
70
+ items.map { |item| parse_delivery_item(item) }
71
+ rescue WorkerError => e
72
+ warn "Error getting history: #{e.message}" if $DEBUG
73
+ []
74
+ end
75
+
76
+ # Get the latest delivery status
77
+ # @param tracking_number [String] The tracking number to query
78
+ # @return [DeliveryItem, nil] Latest delivery item or nil
79
+ def latest_status(tracking_number)
80
+ result = query(tracking_number)
81
+ return nil unless result[:latest]
82
+
83
+ parse_delivery_item(result[:latest])
84
+ rescue WorkerError => e
85
+ warn "Error getting latest status: #{e.message}" if $DEBUG
86
+ nil
87
+ end
88
+
89
+ # Check if the Worker is healthy
90
+ # @return [Boolean] true if Worker responds to health check
91
+ def healthy?
92
+ uri = URI("#{@worker_url}/health")
93
+ response = make_request(uri)
94
+ data = JSON.parse(response.body, symbolize_names: true)
95
+ data[:status] == 'ok'
96
+ rescue StandardError
97
+ false
98
+ end
99
+
100
+ private
101
+
102
+ def validate_url!
103
+ uri = URI.parse(@worker_url)
104
+ unless %w[http https].include?(uri.scheme)
105
+ raise ArgumentError, 'Invalid Worker URL: must be http or https'
106
+ end
107
+ rescue URI::InvalidURIError => e
108
+ raise ArgumentError, "Invalid Worker URL: #{e.message}"
109
+ end
110
+
111
+ def make_request(uri)
112
+ response = setup_http(uri).request(build_request(uri))
113
+ raise APIError, "HTTP #{response.code}: #{response.message}" unless response.is_a?(Net::HTTPSuccess)
114
+
115
+ response
116
+ end
117
+
118
+ def setup_http(uri)
119
+ http = Net::HTTP.new(uri.host, uri.port)
120
+ http.use_ssl = uri.scheme == 'https'
121
+ http.read_timeout = @timeout
122
+ http.open_timeout = @timeout
123
+ http
124
+ end
125
+
126
+ def build_request(uri)
127
+ request = Net::HTTP::Get.new(uri)
128
+ request['Accept'] = 'application/json'
129
+ request['Authorization'] = "Bearer #{@token}" if @token
130
+ request
131
+ end
132
+
133
+ def parse_response(response)
134
+ data = JSON.parse(response.body, symbolize_names: true)
135
+
136
+ if data[:status] == 'error'
137
+ raise APIError, data[:message] || 'Unknown error from Worker'
138
+ end
139
+
140
+ data
141
+ end
142
+
143
+ def parse_delivery_item(item)
144
+ DeliveryItem.new(
145
+ status: item[:status],
146
+ status_code: item[:status_code]&.to_sym,
147
+ time: parse_time(item[:time]),
148
+ office: item[:office],
149
+ last_update: parse_time(item[:last_update])
150
+ )
151
+ end
152
+
153
+ def parse_time(time_str)
154
+ return nil if time_str.nil? || time_str.empty?
155
+
156
+ Time.parse(time_str)
157
+ rescue ArgumentError
158
+ nil
159
+ end
160
+ end
161
+ end
data/lib/tcat.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'tcat/configuration'
4
4
  require_relative 'tcat/version'
5
5
  require_relative 'tcat/query'
6
+ require_relative 'tcat/worker_client'
6
7
 
7
8
  # Tcat module provides functionality for tracking packages
8
9
  module Tcat
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tcat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zac
@@ -60,18 +60,15 @@ executables: []
60
60
  extensions: []
61
61
  extra_rdoc_files: []
62
62
  files:
63
- - ".rspec"
64
- - ".rubocop.yml"
65
- - ".tool-versions"
66
63
  - LICENSE.txt
67
64
  - README.md
68
- - Rakefile
69
65
  - lib/tcat.rb
70
66
  - lib/tcat/configuration.rb
71
67
  - lib/tcat/encryption_service.rb
72
68
  - lib/tcat/http_client.rb
73
69
  - lib/tcat/query.rb
74
70
  - lib/tcat/version.rb
71
+ - lib/tcat/worker_client.rb
75
72
  - sig/tcat.rbs
76
73
  homepage: https://rubygems.org/gems/tcat
77
74
  licenses:
@@ -92,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
89
  - !ruby/object:Gem::Version
93
90
  version: '0'
94
91
  requirements: []
95
- rubygems_version: 3.6.9
92
+ rubygems_version: 4.0.6
96
93
  specification_version: 4
97
94
  summary: A Ruby gem for tracking packages using the Tcat system.
98
95
  test_files: []
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,25 +0,0 @@
1
- AllCops:
2
- TargetRubyVersion: 2.7
3
- Exclude:
4
- - 'bin/*'
5
-
6
- # Style/StringLiterals:
7
- # Enabled: true
8
- # EnforcedStyle: double_quotes
9
-
10
- # Style/StringLiteralsInInterpolation:
11
- # Enabled: true
12
- # EnforcedStyle: double_quotes
13
-
14
- Metrics/AbcSize:
15
- Exclude:
16
- - 'lib/tcat/query.rb'
17
-
18
- Metrics/MethodLength:
19
- Exclude:
20
- - 'lib/tcat/query.rb'
21
-
22
- Layout/LineLength:
23
- Exclude:
24
- - 'lib/tcat/query.rb'
25
- - tcat.gemspec
data/.tool-versions DELETED
@@ -1 +0,0 @@
1
- ruby 3.3.8
data/Rakefile DELETED
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- require 'rubocop/rake_task'
9
-
10
- RuboCop::RakeTask.new
11
-
12
- task default: %i[spec rubocop]