route4me 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.travis.yml +10 -0
- data/Gemfile +2 -0
- data/README.md +72 -0
- data/VERSION +1 -0
- data/examples/addresses.json +410 -0
- data/examples/get_route_manifest.rb +6 -0
- data/examples/get_route_tracking.rb +9 -0
- data/examples/helper.rb +7 -0
- data/examples/multiple_depot_multiple_driver.rb +20 -0
- data/examples/multiple_depot_with_time_window.rb +20 -0
- data/examples/reoptimization.rb +9 -0
- data/examples/single_driver_round_trip.rb +20 -0
- data/examples/single_driver_route_ten_stops.rb +18 -0
- data/examples/track.rb +14 -0
- data/lib/route4me.rb +119 -0
- data/lib/route4me/enum/algorithm_type.rb +11 -0
- data/lib/route4me/enum/avoid.rb +8 -0
- data/lib/route4me/enum/device_type.rb +9 -0
- data/lib/route4me/enum/direction_method.rb +7 -0
- data/lib/route4me/enum/distance_unit.rb +6 -0
- data/lib/route4me/enum/metric.rb +9 -0
- data/lib/route4me/enum/optimization_type.rb +7 -0
- data/lib/route4me/enum/travel_mode.rb +7 -0
- data/lib/route4me/errors/api_error.rb +4 -0
- data/lib/route4me/errors/route4me_error.rb +16 -0
- data/lib/route4me/optimization_problem.rb +40 -0
- data/lib/route4me/route.rb +21 -0
- data/lib/route4me/track.rb +17 -0
- data/lib/route4me/util.rb +28 -0
- data/lib/route4me/version.rb +3 -0
- data/route4me.gemspec +24 -0
- data/spec/route4me/optimization_problem_spec.rb +217 -0
- data/spec/route4me/route_spec.rb +60 -0
- data/spec/route4me/track_spec.rb +35 -0
- data/spec/spec_helper.rb +49 -0
- metadata +134 -0
data/examples/helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'route4me'
|
2
|
+
require './helper'
|
3
|
+
|
4
|
+
Route4me.api_key = '11111111111111111111111111111111'
|
5
|
+
problem = Route4me::OptimizationProblem.optimize(
|
6
|
+
:addresses => addresses,
|
7
|
+
:parameters => {
|
8
|
+
:algorithm_type => Route4me::AlgorithmType::CVRP_TW_MD,
|
9
|
+
:distance_unit => Route4me::DistanceUnit::MILES,
|
10
|
+
:device_type => Route4me::DeviceType::WEB,
|
11
|
+
:optimize => Route4me::OptimizationType::DISTANCE,
|
12
|
+
:travel_mode => Route4me::TravelMode::DRIVING,
|
13
|
+
:route_max_duration => 86400,
|
14
|
+
:vehicle_capacity => 50,
|
15
|
+
:vehicle_max_distance_mi => 10000,
|
16
|
+
:parts => 50
|
17
|
+
}
|
18
|
+
)
|
19
|
+
|
20
|
+
puts problem
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'route4me'
|
2
|
+
require './helper'
|
3
|
+
|
4
|
+
Route4me.api_key = '11111111111111111111111111111111'
|
5
|
+
problem = Route4me::OptimizationProblem.optimize(
|
6
|
+
:addresses => addresses,
|
7
|
+
:parameters => {
|
8
|
+
:algorithm_type => Route4me::AlgorithmType::CVRP_TW_SD,
|
9
|
+
:distance_unit => Route4me::DistanceUnit::MILES,
|
10
|
+
:device_type => Route4me::DeviceType::WEB,
|
11
|
+
:optimize => Route4me::OptimizationType::DISTANCE,
|
12
|
+
:travel_mode => Route4me::TravelMode::DRIVING,
|
13
|
+
:route_max_duration => 86400,
|
14
|
+
:vehicle_capacity => 50,
|
15
|
+
:vehicle_max_distance_mi => 10000,
|
16
|
+
:parts => 50
|
17
|
+
}
|
18
|
+
)
|
19
|
+
|
20
|
+
puts problem
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'route4me'
|
2
|
+
require './helper'
|
3
|
+
|
4
|
+
Route4me.api_key = '11111111111111111111111111111111'
|
5
|
+
problem = Route4me::OptimizationProblem.optimize(
|
6
|
+
:addresses => addresses,
|
7
|
+
:parameters => {
|
8
|
+
:algorithm_type => Route4me::AlgorithmType::TSP,
|
9
|
+
:distance_unit => Route4me::DistanceUnit::MILES,
|
10
|
+
:device_type => Route4me::DeviceType::WEB,
|
11
|
+
:optimize => Route4me::OptimizationType::DISTANCE,
|
12
|
+
:travel_mode => Route4me::TravelMode::DRIVING,
|
13
|
+
:route_max_duration => 86400,
|
14
|
+
:vehicle_capacity => 1,
|
15
|
+
:vehicle_max_distance_mi => 10000,
|
16
|
+
:rt => true
|
17
|
+
}
|
18
|
+
)
|
19
|
+
|
20
|
+
puts problem
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'route4me'
|
2
|
+
require './helper'
|
3
|
+
|
4
|
+
Route4me.api_key = '11111111111111111111111111111111'
|
5
|
+
problem = Route4me::OptimizationProblem.optimize(
|
6
|
+
:addresses => addresses.first(10),
|
7
|
+
:parameters => {
|
8
|
+
:algorithm_type => Route4me::AlgorithmType::TSP,
|
9
|
+
:distance_unit => Route4me::DistanceUnit::MILES,
|
10
|
+
:device_type => Route4me::DeviceType::WEB,
|
11
|
+
:optimize => Route4me::OptimizationType::DISTANCE,
|
12
|
+
:travel_mode => Route4me::TravelMode::DRIVING,
|
13
|
+
:vehicle_capacity => 1,
|
14
|
+
:vehicle_max_distance_mi => 10000
|
15
|
+
}
|
16
|
+
)
|
17
|
+
|
18
|
+
puts problem
|
data/examples/track.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'route4me'
|
2
|
+
|
3
|
+
Route4me.api_key = '11111111111111111111111111111111'
|
4
|
+
Route4me::Track.set(
|
5
|
+
format: 'json',
|
6
|
+
member_id: 1,
|
7
|
+
route_id: '0CDA1358186D616AFD39FEB579A64974',
|
8
|
+
course: 1,
|
9
|
+
speed: 120,
|
10
|
+
lat: 41.8927521,
|
11
|
+
lng: -109.0803888,
|
12
|
+
device_type: Route4me::DeviceType::IPHONE,
|
13
|
+
device_guid: '036BFC6AC46F45153D7381BE321CB9235585FD83'
|
14
|
+
)
|
data/lib/route4me.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# Stripe Ruby bindings
|
2
|
+
# API spec at https://stripe.com/docs/api
|
3
|
+
require 'cgi'
|
4
|
+
require 'set'
|
5
|
+
require 'openssl'
|
6
|
+
require 'rest_client'
|
7
|
+
require 'json'
|
8
|
+
|
9
|
+
# Enums
|
10
|
+
require 'route4me/enum/algorithm_type'
|
11
|
+
require 'route4me/enum/distance_unit'
|
12
|
+
require 'route4me/enum/device_type'
|
13
|
+
require 'route4me/enum/optimization_type'
|
14
|
+
require 'route4me/enum/travel_mode'
|
15
|
+
require 'route4me/enum/metric'
|
16
|
+
require 'route4me/enum/direction_method'
|
17
|
+
require 'route4me/enum/avoid'
|
18
|
+
|
19
|
+
# Errors
|
20
|
+
require 'route4me/errors/route4me_error'
|
21
|
+
require 'route4me/errors/api_error'
|
22
|
+
|
23
|
+
# Version
|
24
|
+
require 'route4me/version'
|
25
|
+
|
26
|
+
# Util
|
27
|
+
require 'route4me/util'
|
28
|
+
|
29
|
+
# Resources
|
30
|
+
require 'route4me/optimization_problem'
|
31
|
+
# require 'route4me/address'
|
32
|
+
require 'route4me/route'
|
33
|
+
require 'route4me/track'
|
34
|
+
|
35
|
+
module Route4me
|
36
|
+
class << self
|
37
|
+
attr_accessor :api_key, :api_base
|
38
|
+
end
|
39
|
+
|
40
|
+
@api_base = 'http://route4me.com'
|
41
|
+
|
42
|
+
def self.api_url(url='')
|
43
|
+
@api_base + url
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.uri_encode(params)
|
47
|
+
params.map{ |k,v| "#{k}=#{Util.url_encode(v)}" }.join('&')
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.request(method, url, opts)
|
51
|
+
unless @api_key
|
52
|
+
raise ArgumentError.new('No API key provided.')
|
53
|
+
end
|
54
|
+
|
55
|
+
get = opts[:get] || {}
|
56
|
+
json = opts[:json] || {}
|
57
|
+
|
58
|
+
url = api_url(url)
|
59
|
+
get[:api_key] = self.api_key
|
60
|
+
url += "?#{uri_encode(get)}"
|
61
|
+
|
62
|
+
case method.to_s.downcase.to_sym
|
63
|
+
when :post, :put
|
64
|
+
payload = json.to_json if json && json.any?
|
65
|
+
else
|
66
|
+
payload = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
request_opts = {
|
70
|
+
method: method, open_timeout: 30, url: url,
|
71
|
+
timeout: 80, payload: payload
|
72
|
+
}
|
73
|
+
|
74
|
+
begin
|
75
|
+
response = execute(request_opts)
|
76
|
+
rescue SocketError => e
|
77
|
+
handle_error(e)
|
78
|
+
rescue RestClient::ExceptionWithResponse => e
|
79
|
+
if rcode = e.http_code and rbody = e.http_body
|
80
|
+
handle_api_error(rcode, rbody)
|
81
|
+
else
|
82
|
+
handle_error(e)
|
83
|
+
end
|
84
|
+
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
85
|
+
handle_error(e)
|
86
|
+
end
|
87
|
+
|
88
|
+
Util.symbolize_names(parse(response))
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.execute(attrs)
|
92
|
+
RestClient::Request.execute(attrs)
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.parse(response)
|
96
|
+
begin
|
97
|
+
response = JSON.parse(response.body)
|
98
|
+
rescue JSON::ParserError
|
99
|
+
response = nil
|
100
|
+
end
|
101
|
+
|
102
|
+
response
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.handle_error(e)
|
106
|
+
raise Route4meError, e.message
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.handle_api_error(code, body)
|
110
|
+
begin
|
111
|
+
error_message = JSON.parse(body)
|
112
|
+
error_message = error_message['errors']
|
113
|
+
rescue
|
114
|
+
raise Route4meError
|
115
|
+
end
|
116
|
+
|
117
|
+
raise ApiError, code, error_message
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Route4me
|
2
|
+
class Route4meError < StandardError
|
3
|
+
attr_reader :message, :http_status, :http_body
|
4
|
+
|
5
|
+
def initialize(message=nil, http_status=nil, http_body=nil)
|
6
|
+
@message = message
|
7
|
+
@http_status = http_status
|
8
|
+
@http_body = http_body
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
|
13
|
+
"#{status_string}#{@message}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Route4me
|
2
|
+
class OptimizationProblem
|
3
|
+
def self.url
|
4
|
+
'/api.v4/optimization_problem.php'
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.get(params={})
|
8
|
+
get = Util.extract(params, [
|
9
|
+
:optimization_problem_id, :wait_for_final_state,
|
10
|
+
:state, :limit, :offset
|
11
|
+
])
|
12
|
+
|
13
|
+
optimization = Route4me.request(:get, self.url, get: get)
|
14
|
+
if (optimization[:optimizations]).nil?
|
15
|
+
optimization
|
16
|
+
else
|
17
|
+
optimization[:optimizations]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.optimize(params={})
|
22
|
+
json = Util.extract(params, [:addresses, :parameters])
|
23
|
+
get = Util.extract(params, [
|
24
|
+
:directions, :format, :route_path_output, :optimized_callback_url
|
25
|
+
])
|
26
|
+
|
27
|
+
Route4me.request(:post, self.url, get: get, json: json)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.update(params={})
|
31
|
+
json = Util.extract(params, [:addresses, :parameters])
|
32
|
+
get = Util.extract(params, [
|
33
|
+
:optimization_problem_id, :directions, :format,
|
34
|
+
:route_path_output, :reoptimize
|
35
|
+
])
|
36
|
+
|
37
|
+
Route4me.request(:post, self.url, get: get, json: json)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Route4me
|
2
|
+
class Route
|
3
|
+
def self.url
|
4
|
+
'/api.v4/route.php'
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.get(params={})
|
8
|
+
get = Util.extract(params, [
|
9
|
+
:route_id, :directions, :route_path_output, :device_tracking_history,
|
10
|
+
:limit, :offset, :original
|
11
|
+
])
|
12
|
+
Route4me.request(:get, self.url, get: get)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.delete(params={})
|
16
|
+
get = Util.extract(params, [:route_id])
|
17
|
+
status = Route4me.request(:delete, self.url, get: get)
|
18
|
+
status[:deleted]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Route4me
|
2
|
+
class Track
|
3
|
+
def self.url
|
4
|
+
'/track/set.php'
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.set(params={})
|
8
|
+
get = Util.extract(params, [
|
9
|
+
:format, :member_id, :route_id, :tx_id, :vehicle_id, :course,
|
10
|
+
:speed, :lat, :lng, :altitude, :device_type, :device_guid,
|
11
|
+
:device_timestamp, :app_version
|
12
|
+
])
|
13
|
+
|
14
|
+
Route4me.request(:get, self.url, get: get)[:status]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Route4me
|
2
|
+
module Util
|
3
|
+
def self.extract(params, keys)
|
4
|
+
s = params.select{|k,v| keys.include? k.to_sym }
|
5
|
+
Hash[s.map{|k, v| [k.to_sym, v] }]
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.url_encode(key)
|
9
|
+
URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.symbolize_names(object)
|
13
|
+
case object
|
14
|
+
when Hash
|
15
|
+
new = {}
|
16
|
+
object.each do |key, value|
|
17
|
+
key = (key.to_sym rescue key) || key
|
18
|
+
new[key] = symbolize_names(value)
|
19
|
+
end
|
20
|
+
new
|
21
|
+
when Array
|
22
|
+
object.map { |value| symbolize_names(value) }
|
23
|
+
else
|
24
|
+
object
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|