geocodio-gem 0.3.0 → 0.5.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: 7edbfd26554e922c6d274ef187e68595dc9f824089afc29817c70664f7289c63
4
- data.tar.gz: fdf4febbc8917dc38dd128343680a146fb69164670cbd7c98b669c26fbb7ab05
3
+ metadata.gz: 0dcf45fbaa749a3272901c9448961eadc96adcd24f8d1122ab9ae691e76ad30e
4
+ data.tar.gz: 3f26bbc4c74fe7b9062d952615d7de520d4ef3043d41d0bc3cfb02fa5def5f97
5
5
  SHA512:
6
- metadata.gz: 358ee3b3599c87ab971d04d202c55596d4c3179c729f8c8742fdec7c96c72bbdaa748553cac3716d6546dadf09a9b28a8959bc253e3b33f41612466ad39c85b4
7
- data.tar.gz: 36833379cf833c4ff78b5bc97c2267e8720cca21242c00bf31c8733738120a146df3bd10648a3d7da6bac64e386cd09afa4ff1c638b8f996ef0f2b63c21b98f5
6
+ metadata.gz: fc0809146e16875b323b13da38765f1a2267238f6956dc9f0a04deca4a01f6a50ea427419d6ef6a123009303ab58e3d59f37329e4e80baea943dde16a5ed2582
7
+ data.tar.gz: d04e79756c2c7fb4682f26d928f40239634f0d20782df767356021d69b9afcf0622ad7fb833774c0f88a59b85f93823bef13b4d35dca6dde835236960c21ccec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## [0.5.0] - 2026-01-06
2
+ - Added Distance API support:
3
+ - `distance()` - Calculate distances from single origin to multiple destinations
4
+ - `distanceMatrix()` - Calculate full distance matrix (multiple origins x destinations)
5
+ - `createDistanceMatrixJob()` - Create async distance matrix jobs
6
+ - `distanceMatrixJobStatus()` - Check job status
7
+ - `distanceMatrixJobs()` - List all distance jobs
8
+ - `getDistanceMatrixJobResults()` - Get completed job results
9
+ - `downloadDistanceMatrixJob()` - Download results to file
10
+ - `deleteDistanceMatrixJob()` - Delete a job
11
+ - Enhanced `geocode()` and `reverse()` with optional distance parameters
12
+ - Support for multiple coordinate formats (string, array, hash) with optional IDs
13
+ - Support for driving mode with duration estimates
14
+ - Support for distance filtering options (max_results, max_distance, etc.)
15
+ - Updated API endpoint from v1.8 to v1.9
16
+
1
17
  ## [0.3.0] - 2025-5-20
2
18
  - Updated API endpoint from v1.7 to v1.8
3
19
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- geocodio-gem (0.3.0)
4
+ geocodio-gem (0.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -213,6 +213,233 @@ To use `deleteList()`, pass in the ID of the list you would like to delete.
213
213
  response # => {"success"=>true}
214
214
  ```
215
215
 
216
+ ## Distance Calculations
217
+
218
+ The Distance API allows you to calculate distances from a single origin to multiple destinations, or compute full distance matrices.
219
+
220
+ ### Coordinate Formats with Custom IDs
221
+
222
+ You can add custom identifiers to coordinates using various formats. The ID will be returned in the response, making it easy to match results back to your data:
223
+
224
+ ```ruby
225
+ # String format with ID
226
+ "37.7749,-122.4194,warehouse_1"
227
+
228
+ # Array format with ID
229
+ [37.7749, -122.4194, "warehouse_1"]
230
+
231
+ # Hash format with ID
232
+ { lat: 37.7749, lng: -122.4194, id: "warehouse_1" }
233
+ ```
234
+
235
+ ### Distance Mode and Units
236
+
237
+ The SDK supports different distance calculation modes and units:
238
+
239
+ ```ruby
240
+ # Available modes
241
+ :straightline # Default - great-circle (as the crow flies)
242
+ :driving # Road network routing with duration
243
+ :haversine # Alias for straightline (backward compatibility)
244
+
245
+ # Available units
246
+ :miles # Default
247
+ :kilometers
248
+ ```
249
+
250
+ > **Note:** The default mode is `:straightline` (great-circle distance). Use `:driving` if you need road network routing with duration estimates.
251
+
252
+ ### Single Origin to Multiple Destinations
253
+
254
+ Calculate distances from one origin to multiple destinations:
255
+
256
+ ```ruby
257
+ # Basic usage with string coordinates
258
+ response = geocodio.distance(
259
+ "38.8977,-77.0365,white_house",
260
+ ["38.9072,-77.0369,capitol", "38.8895,-77.0353,monument"]
261
+ )
262
+
263
+ response["origin"]["id"] # => "white_house"
264
+ response["destinations"][0]["distance_miles"] # => 0.7
265
+ response["destinations"][0]["id"] # => "capitol"
266
+
267
+ # With driving mode (includes duration)
268
+ response = geocodio.distance(
269
+ "38.8977,-77.0365",
270
+ ["38.9072,-77.0369"],
271
+ mode: :driving
272
+ )
273
+
274
+ response["destinations"][0]["duration_seconds"] # => 180
275
+
276
+ # With filtering and sorting options
277
+ response = geocodio.distance(
278
+ "38.8977,-77.0365,warehouse",
279
+ [
280
+ "38.9072,-77.0369,store_1",
281
+ "39.2904,-76.6122,store_2",
282
+ "39.9526,-75.1652,store_3"
283
+ ],
284
+ mode: :driving,
285
+ units: :kilometers,
286
+ max_results: 2,
287
+ max_distance: 100.0,
288
+ order_by: :distance,
289
+ sort: :asc
290
+ )
291
+
292
+ # Using array format for coordinates
293
+ response = geocodio.distance(
294
+ [38.8977, -77.0365, "headquarters"],
295
+ [[38.9072, -77.0369, "branch_1"]]
296
+ )
297
+
298
+ # Using hash format for coordinates
299
+ response = geocodio.distance(
300
+ { lat: 38.8977, lng: -77.0365, id: "hq" },
301
+ [{ lat: 38.9072, lng: -77.0369, id: "branch" }]
302
+ )
303
+ ```
304
+
305
+ ### Distance Matrix (Multiple Origins to Multiple Destinations)
306
+
307
+ Calculate full distance matrix from multiple origins to multiple destinations:
308
+
309
+ ```ruby
310
+ origins = [
311
+ "38.8977,-77.0365,warehouse_dc",
312
+ "39.2904,-76.6122,warehouse_baltimore"
313
+ ]
314
+ destinations = [
315
+ "38.9072,-77.0369,customer_1",
316
+ "39.9526,-75.1652,customer_2"
317
+ ]
318
+
319
+ response = geocodio.distanceMatrix(origins, destinations)
320
+
321
+ response["results"][0]["origin"]["id"] # => "warehouse_dc"
322
+ response["results"][0]["destinations"][0]["distance_miles"] # => 0.7
323
+
324
+ # With driving mode
325
+ response = geocodio.distanceMatrix(
326
+ origins,
327
+ destinations,
328
+ mode: :driving,
329
+ units: :kilometers
330
+ )
331
+
332
+ # With filtering options
333
+ response = geocodio.distanceMatrix(
334
+ origins,
335
+ destinations,
336
+ max_results: 2,
337
+ max_distance: 50.0,
338
+ min_distance: 1.0,
339
+ order_by: :distance,
340
+ sort: :asc
341
+ )
342
+ ```
343
+
344
+ ### Add Distance to Geocoding Requests
345
+
346
+ You can add distance calculations to existing geocode or reverse geocode requests:
347
+
348
+ ```ruby
349
+ # Geocode an address and calculate distances to store locations
350
+ response = geocodio.geocode(
351
+ ["1600 Pennsylvania Ave NW, Washington DC"],
352
+ [], # fields
353
+ nil, # limit
354
+ nil, # format
355
+ destinations: [
356
+ "38.9072,-77.0369,store_dc",
357
+ "39.2904,-76.6122,store_baltimore"
358
+ ],
359
+ distance_mode: :driving,
360
+ distance_units: :miles
361
+ )
362
+
363
+ response["results"][0]["destinations"][0]["distance_miles"] # => distance to first destination
364
+ response["results"][0]["destinations"][0]["id"] # => "store_dc"
365
+
366
+ # Reverse geocode with distances
367
+ response = geocodio.reverse(
368
+ ["38.8977,-77.0365"],
369
+ [],
370
+ nil,
371
+ nil,
372
+ destinations: ["38.9072,-77.0369,capitol"],
373
+ distance_mode: :straightline
374
+ )
375
+
376
+ response["results"][0]["destinations"] # => array of destinations with distances
377
+ ```
378
+
379
+ ### Async Distance Matrix Jobs
380
+
381
+ For large distance matrix calculations, use async jobs that process in the background:
382
+
383
+ ```ruby
384
+ # Create a new distance matrix job
385
+ job = geocodio.createDistanceMatrixJob(
386
+ "My Distance Calculation",
387
+ ["38.8977,-77.0365,origin_1", "38.9072,-77.0369,origin_2"],
388
+ ["38.8895,-77.0353,dest_1", "39.2904,-76.6122,dest_2"],
389
+ mode: :driving,
390
+ units: :miles,
391
+ callback_url: "https://example.com/webhook" # Optional
392
+ )
393
+
394
+ job["id"] # => Job identifier
395
+
396
+ # Or use list IDs from previously uploaded lists
397
+ job = geocodio.createDistanceMatrixJob(
398
+ "Distance from Lists",
399
+ 12345, # List ID for origins
400
+ 67890, # List ID for destinations
401
+ mode: :straightline
402
+ )
403
+
404
+ # Check job status
405
+ status = geocodio.distanceMatrixJobStatus(job["id"])
406
+
407
+ status["data"]["status"] # => "COMPLETED", "PROCESSING", or "FAILED"
408
+ status["data"]["progress"] # => 0-100
409
+
410
+ # List all jobs (paginated)
411
+ jobs = geocodio.distanceMatrixJobs
412
+ jobs = geocodio.distanceMatrixJobs(2) # Page 2
413
+
414
+ # Get job results as parsed hash
415
+ results = geocodio.getDistanceMatrixJobResults(job["id"])
416
+
417
+ results["results"][0]["origin"]["id"] # => "origin_1"
418
+ results["results"][0]["destinations"] # => array of destinations with distances
419
+
420
+ # Download results to file
421
+ geocodio.downloadDistanceMatrixJob(job["id"], "/path/to/results.json")
422
+
423
+ # Delete a job
424
+ geocodio.deleteDistanceMatrixJob(job["id"])
425
+ ```
426
+
427
+ ### Distance Filtering Options
428
+
429
+ All distance methods support the following filtering options:
430
+
431
+ | Option | Type | Description |
432
+ |--------|------|-------------|
433
+ | `mode` | Symbol | `:straightline` (default), `:driving`, or `:haversine` |
434
+ | `units` | Symbol | `:miles` (default), `:kilometers`, or `:km` |
435
+ | `max_results` | Integer | Limit number of results |
436
+ | `max_distance` | Float | Filter by maximum distance |
437
+ | `min_distance` | Float | Filter by minimum distance |
438
+ | `max_duration` | Integer | Filter by max duration in seconds (driving mode only) |
439
+ | `min_duration` | Integer | Filter by min duration in seconds (driving mode only) |
440
+ | `order_by` | Symbol | `:distance` (default) or `:duration` |
441
+ | `sort` | Symbol | `:asc` (default) or `:desc` |
442
+
216
443
  ## Testing
217
444
 
218
445
  To run tests, be sure to create a `.env` file that export your Geocodio API Key within a variable of API_KEY.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Geocodio
4
- VERSION = "0.3.0"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/geocodio/gem.rb CHANGED
@@ -2,6 +2,7 @@ require_relative "gem/version"
2
2
  require "faraday"
3
3
  require "faraday/follow_redirects"
4
4
  require "csv"
5
+ require "uri"
5
6
 
6
7
  module Geocodio
7
8
 
@@ -14,7 +15,7 @@ module Geocodio
14
15
  @api_key = api_key
15
16
 
16
17
  @conn = Faraday.new(
17
- url: 'https://api.geocod.io/v1.8/',
18
+ url: 'https://api.geocod.io/v1.9/',
18
19
  headers: {'Content-Type' => 'application/json' }
19
20
  ) do |f|
20
21
  f.response :follow_redirects
@@ -22,11 +23,34 @@ module Geocodio
22
23
  end
23
24
  end
24
25
 
25
- def geocode(query=[], fields=[], limit=nil, format=nil)
26
+ # Forward geocode addresses to coordinates
27
+ # @param query [Array] Array of address strings
28
+ # @param fields [Array] Optional fields to append (e.g., ["timezone", "cd"])
29
+ # @param limit [Integer] Maximum number of results
30
+ # @param format [String] Response format ("simple" for simplified response)
31
+ # @param destinations [Array] Optional array of destination coordinates for distance calculation
32
+ # @param distance_mode [Symbol] Distance mode (:straightline, :driving, :haversine)
33
+ # @param distance_units [Symbol] Distance units (:miles, :kilometers)
34
+ # @param distance_options [Hash] Additional distance options (max_results, max_distance, etc.)
35
+ def geocode(query=[], fields=[], limit=nil, format=nil,
36
+ destinations: nil, distance_mode: nil, distance_units: nil, distance_options: nil)
26
37
  if query.size < 1
27
38
  raise ArgumentError, 'Please provide at least one address to geocode.'
28
- elsif query.size == 1
29
- response = JSON.parse(@conn.get('geocode', { q: query.join(""), fields: fields.join(","), limit: limit, format: format, api_key: @api_key }).body)
39
+ elsif query.size == 1
40
+ # Build query string manually to handle array parameters correctly
41
+ query_parts = [
42
+ "api_key=#{@api_key}",
43
+ "q=#{URI.encode_www_form_component(query.join(""))}"
44
+ ]
45
+ query_parts << "fields=#{URI.encode_www_form_component(fields.join(","))}" if fields && !fields.empty?
46
+ query_parts << "limit=#{limit}" if limit
47
+ query_parts << "format=#{format}" if format
48
+
49
+ # Add distance parameters if destinations provided
50
+ distance_parts = build_geocode_distance_query_parts(destinations, distance_mode, distance_units, distance_options)
51
+ query_parts.concat(distance_parts)
52
+
53
+ response = JSON.parse(@conn.get("geocode?#{query_parts.join('&')}").body)
30
54
  return response
31
55
  elsif query.size > 1
32
56
  response = @conn.post('geocode') do |req|
@@ -39,11 +63,34 @@ module Geocodio
39
63
  end
40
64
  end
41
65
 
42
- def reverse(query=[], fields=[], limit=nil, format=nil)
66
+ # Reverse geocode coordinates to addresses
67
+ # @param query [Array] Array of coordinate strings ("lat,lng")
68
+ # @param fields [Array] Optional fields to append (e.g., ["timezone", "cd"])
69
+ # @param limit [Integer] Maximum number of results
70
+ # @param format [String] Response format ("simple" for simplified response)
71
+ # @param destinations [Array] Optional array of destination coordinates for distance calculation
72
+ # @param distance_mode [Symbol] Distance mode (:straightline, :driving, :haversine)
73
+ # @param distance_units [Symbol] Distance units (:miles, :kilometers)
74
+ # @param distance_options [Hash] Additional distance options (max_results, max_distance, etc.)
75
+ def reverse(query=[], fields=[], limit=nil, format=nil,
76
+ destinations: nil, distance_mode: nil, distance_units: nil, distance_options: nil)
43
77
  if query.size < 1
44
78
  raise ArgumentError, 'Please provide at least one set of coordinates to geocode.'
45
79
  elsif query.size == 1
46
- response = JSON.parse(@conn.get('reverse', { q: query.join(""), fields: fields.join(","), limit: limit, format: format, api_key: @api_key}).body)
80
+ # Build query string manually to handle array parameters correctly
81
+ query_parts = [
82
+ "api_key=#{@api_key}",
83
+ "q=#{URI.encode_www_form_component(query.join(""))}"
84
+ ]
85
+ query_parts << "fields=#{URI.encode_www_form_component(fields.join(","))}" if fields && !fields.empty?
86
+ query_parts << "limit=#{limit}" if limit
87
+ query_parts << "format=#{format}" if format
88
+
89
+ # Add distance parameters if destinations provided
90
+ distance_parts = build_geocode_distance_query_parts(destinations, distance_mode, distance_units, distance_options)
91
+ query_parts.concat(distance_parts)
92
+
93
+ response = JSON.parse(@conn.get("reverse?#{query_parts.join('&')}").body)
47
94
  return response
48
95
  elsif query.size > 1
49
96
  response = @conn.post('reverse') do |req|
@@ -96,6 +143,294 @@ module Geocodio
96
143
  response = JSON.parse(@conn.delete("lists/#{id}", { api_key: @api_key}).body)
97
144
  return response
98
145
  end
146
+
147
+ # Distance API Methods
148
+
149
+ # Calculate distances from a single origin to multiple destinations
150
+ # @param origin [String, Array, Hash] Origin coordinate ("lat,lng" or "lat,lng,id" or [lat, lng] or [lat, lng, id] or {lat:, lng:, id:})
151
+ # @param destinations [Array] Array of destination coordinates in any supported format
152
+ # @param options [Hash] Optional parameters:
153
+ # - mode: :straightline (default), :driving, or :haversine (alias for straightline)
154
+ # - units: :miles (default) or :kilometers
155
+ # - max_results: Integer, limit number of results
156
+ # - max_distance: Float, filter by max distance
157
+ # - max_duration: Integer, filter by max duration (seconds, driving only)
158
+ # - min_distance: Float, filter by min distance
159
+ # - min_duration: Integer, filter by min duration (seconds, driving only)
160
+ # - order_by: :distance (default) or :duration
161
+ # - sort: :asc (default) or :desc
162
+ def distance(origin, destinations, options = {})
163
+ raise ArgumentError, 'Please provide an origin coordinate.' if origin.nil?
164
+ raise ArgumentError, 'Please provide at least one destination.' if destinations.nil? || destinations.empty?
165
+
166
+ # Build query string manually to handle array parameters correctly
167
+ query_parts = [
168
+ "api_key=#{@api_key}",
169
+ "origin=#{URI.encode_www_form_component(format_coordinate_string(origin))}"
170
+ ]
171
+
172
+ # Add destinations as properly formatted array parameters
173
+ destinations.each do |dest|
174
+ query_parts << "destinations[]=#{URI.encode_www_form_component(format_coordinate_string(dest))}"
175
+ end
176
+
177
+ # Add distance options
178
+ build_distance_params(options).each do |key, value|
179
+ query_parts << "#{key}=#{URI.encode_www_form_component(value.to_s)}"
180
+ end
181
+
182
+ response = JSON.parse(@conn.get("distance?#{query_parts.join('&')}").body)
183
+ return response
184
+ end
185
+
186
+ # Calculate distance matrix from multiple origins to multiple destinations
187
+ # @param origins [Array] Array of origin coordinates
188
+ # @param destinations [Array] Array of destination coordinates
189
+ # @param options [Hash] Same options as distance() method
190
+ def distanceMatrix(origins, destinations, options = {})
191
+ raise ArgumentError, 'Please provide at least one origin.' if origins.nil? || origins.empty?
192
+ raise ArgumentError, 'Please provide at least one destination.' if destinations.nil? || destinations.empty?
193
+
194
+ body = {
195
+ origins: origins.map { |coord| format_coordinate_object(coord) },
196
+ destinations: destinations.map { |coord| format_coordinate_object(coord) }
197
+ }
198
+
199
+ # Add distance options to body
200
+ body.merge!(build_distance_body_params(options))
201
+
202
+ response = @conn.post('distance-matrix') do |req|
203
+ req.params = { api_key: @api_key }
204
+ req.headers['Content-Type'] = 'application/json'
205
+ req.body = body.to_json
206
+ end
207
+
208
+ parsed = JSON.parse(response.body)
209
+ return parsed
210
+ end
211
+
212
+ # Create an async distance matrix job
213
+ # @param name [String] Job name
214
+ # @param origins [Array, Integer] Array of coordinates or list ID
215
+ # @param destinations [Array, Integer] Array of coordinates or list ID
216
+ # @param options [Hash] Same options as distanceMatrix() plus:
217
+ # - callback_url: URL for webhook notification
218
+ def createDistanceMatrixJob(name, origins, destinations, options = {})
219
+ raise ArgumentError, 'Please provide a job name.' if name.nil? || name.empty?
220
+ raise ArgumentError, 'Please provide origins.' if origins.nil?
221
+ raise ArgumentError, 'Please provide destinations.' if destinations.nil?
222
+
223
+ body = { name: name }
224
+
225
+ # Origins can be array of coordinates or list ID (integer)
226
+ if origins.is_a?(Integer)
227
+ body[:origins] = origins
228
+ else
229
+ body[:origins] = origins.map { |coord| format_coordinate_object(coord) }
230
+ end
231
+
232
+ # Destinations can be array of coordinates or list ID (integer)
233
+ if destinations.is_a?(Integer)
234
+ body[:destinations] = destinations
235
+ else
236
+ body[:destinations] = destinations.map { |coord| format_coordinate_object(coord) }
237
+ end
238
+
239
+ # Add distance options
240
+ body.merge!(build_distance_body_params(options))
241
+
242
+ # Add callback URL if provided
243
+ body[:callback_url] = options[:callback_url] if options[:callback_url]
244
+
245
+ response = @conn.post('distance-jobs') do |req|
246
+ req.params = { api_key: @api_key }
247
+ req.headers['Content-Type'] = 'application/json'
248
+ req.body = body.to_json
249
+ end
250
+
251
+ parsed = JSON.parse(response.body)
252
+ return parsed
253
+ end
254
+
255
+ # Get status of a distance matrix job
256
+ # @param id [String, Integer] Job ID
257
+ def distanceMatrixJobStatus(id)
258
+ response = JSON.parse(@conn.get("distance-jobs/#{id}", { api_key: @api_key }).body)
259
+ return response
260
+ end
261
+
262
+ # List all distance matrix jobs
263
+ # @param page [Integer] Optional page number for pagination
264
+ def distanceMatrixJobs(page = nil)
265
+ params = { api_key: @api_key }
266
+ params[:page] = page if page
267
+ response = JSON.parse(@conn.get("distance-jobs", params).body)
268
+ return response
269
+ end
270
+
271
+ # Get results of a completed distance matrix job
272
+ # @param id [String, Integer] Job ID
273
+ def getDistanceMatrixJobResults(id)
274
+ response = JSON.parse(@conn.get("distance-jobs/#{id}/download", { api_key: @api_key }).body)
275
+ return response
276
+ end
277
+
278
+ # Download distance matrix job results to a file
279
+ # @param id [String, Integer] Job ID
280
+ # @param file_path [String] Path to save the file
281
+ def downloadDistanceMatrixJob(id, file_path)
282
+ response = @conn.get("distance-jobs/#{id}/download", { api_key: @api_key })
283
+ File.write(file_path, response.body)
284
+ return { success: true, file_path: file_path }
285
+ end
286
+
287
+ # Delete a distance matrix job
288
+ # @param id [String, Integer] Job ID
289
+ def deleteDistanceMatrixJob(id)
290
+ response = JSON.parse(@conn.delete("distance-jobs/#{id}", { api_key: @api_key }).body)
291
+ return response
292
+ end
293
+
294
+ private
295
+
296
+ # Format a coordinate for GET requests (string format: "lat,lng" or "lat,lng,id")
297
+ def format_coordinate_string(coord)
298
+ case coord
299
+ when String
300
+ coord
301
+ when Array
302
+ if coord.length >= 3
303
+ "#{coord[0]},#{coord[1]},#{coord[2]}"
304
+ else
305
+ "#{coord[0]},#{coord[1]}"
306
+ end
307
+ when Hash
308
+ str = "#{coord[:lat]},#{coord[:lng]}"
309
+ str += ",#{coord[:id]}" if coord[:id]
310
+ str
311
+ else
312
+ raise ArgumentError, "Invalid coordinate format: #{coord.inspect}"
313
+ end
314
+ end
315
+
316
+ # Format a coordinate for POST requests (object format: {lat:, lng:, id:})
317
+ def format_coordinate_object(coord)
318
+ case coord
319
+ when String
320
+ parts = coord.split(',').map(&:strip)
321
+ obj = { lat: parts[0].to_f, lng: parts[1].to_f }
322
+ obj[:id] = parts[2] if parts[2]
323
+ obj
324
+ when Array
325
+ obj = { lat: coord[0].to_f, lng: coord[1].to_f }
326
+ obj[:id] = coord[2].to_s if coord[2]
327
+ obj
328
+ when Hash
329
+ obj = { lat: coord[:lat].to_f, lng: coord[:lng].to_f }
330
+ obj[:id] = coord[:id].to_s if coord[:id]
331
+ obj
332
+ else
333
+ raise ArgumentError, "Invalid coordinate format: #{coord.inspect}"
334
+ end
335
+ end
336
+
337
+ # Build distance query parameters for GET requests
338
+ def build_distance_params(options)
339
+ params = {}
340
+
341
+ # Mode (map haversine to straightline)
342
+ if options[:mode]
343
+ mode = options[:mode].to_s
344
+ mode = 'straightline' if mode == 'haversine'
345
+ params[:mode] = mode
346
+ end
347
+
348
+ # Units (map kilometers to km for API compatibility)
349
+ if options[:units]
350
+ units = options[:units].to_s
351
+ units = 'km' if units == 'kilometers'
352
+ params[:units] = units
353
+ end
354
+
355
+ params[:max_results] = options[:max_results] if options[:max_results]
356
+ params[:max_distance] = options[:max_distance] if options[:max_distance]
357
+ params[:max_duration] = options[:max_duration] if options[:max_duration]
358
+ params[:min_distance] = options[:min_distance] if options[:min_distance]
359
+ params[:min_duration] = options[:min_duration] if options[:min_duration]
360
+ params[:order_by] = options[:order_by].to_s if options[:order_by]
361
+ params[:sort] = options[:sort].to_s if options[:sort]
362
+
363
+ params
364
+ end
365
+
366
+ # Build distance body parameters for POST requests
367
+ def build_distance_body_params(options)
368
+ params = {}
369
+
370
+ # Mode (map haversine to straightline)
371
+ if options[:mode]
372
+ mode = options[:mode].to_s
373
+ mode = 'straightline' if mode == 'haversine'
374
+ params[:mode] = mode
375
+ end
376
+
377
+ # Units (map kilometers to km for API compatibility)
378
+ if options[:units]
379
+ units = options[:units].to_s
380
+ units = 'km' if units == 'kilometers'
381
+ params[:units] = units
382
+ end
383
+
384
+ params[:max_results] = options[:max_results] if options[:max_results]
385
+ params[:max_distance] = options[:max_distance] if options[:max_distance]
386
+ params[:max_duration] = options[:max_duration] if options[:max_duration]
387
+ params[:min_distance] = options[:min_distance] if options[:min_distance]
388
+ params[:min_duration] = options[:min_duration] if options[:min_duration]
389
+ params[:order_by] = options[:order_by].to_s if options[:order_by]
390
+ params[:sort] = options[:sort].to_s if options[:sort]
391
+
392
+ params
393
+ end
394
+
395
+ # Build distance query string parts for geocode/reverse requests
396
+ # Returns an array of query string parts to be joined with '&'
397
+ def build_geocode_distance_query_parts(destinations, distance_mode, distance_units, distance_options)
398
+ parts = []
399
+
400
+ return parts unless destinations && !destinations.empty?
401
+
402
+ # Add destinations as properly formatted array parameters
403
+ destinations.each do |dest|
404
+ parts << "destinations[]=#{URI.encode_www_form_component(format_coordinate_string(dest))}"
405
+ end
406
+
407
+ # Mode (map haversine to straightline)
408
+ if distance_mode
409
+ mode = distance_mode.to_s
410
+ mode = 'straightline' if mode == 'haversine'
411
+ parts << "distance_mode=#{mode}"
412
+ end
413
+
414
+ # Units (map kilometers to km)
415
+ if distance_units
416
+ units = distance_units.to_s
417
+ units = 'km' if units == 'kilometers'
418
+ parts << "distance_units=#{units}"
419
+ end
420
+
421
+ # Additional options
422
+ if distance_options
423
+ parts << "distance_max_results=#{distance_options[:max_results]}" if distance_options[:max_results]
424
+ parts << "distance_max_distance=#{distance_options[:max_distance]}" if distance_options[:max_distance]
425
+ parts << "distance_max_duration=#{distance_options[:max_duration]}" if distance_options[:max_duration]
426
+ parts << "distance_min_distance=#{distance_options[:min_distance]}" if distance_options[:min_distance]
427
+ parts << "distance_min_duration=#{distance_options[:min_duration]}" if distance_options[:min_duration]
428
+ parts << "distance_order_by=#{distance_options[:order_by]}" if distance_options[:order_by]
429
+ parts << "distance_sort=#{distance_options[:sort]}" if distance_options[:sort]
430
+ end
431
+
432
+ parts
433
+ end
99
434
  end
100
435
  end
101
436
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geocodio-gem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GoldenPavilion
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-05-20 00:00:00.000000000 Z
11
+ date: 2026-01-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby Gem to help you integrate your application with the Geocodio API.
14
14
  email: