routific 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d2e7ffe5c2bb636a3ab3c1e594516b763d2e8197
4
+ data.tar.gz: be71b166f79ade2947066ab085952980b04b5a5d
5
+ SHA512:
6
+ metadata.gz: ef023e2e3aca0209ded96748d90bc1cc158f05d819a057ad16a4d71fde24c9a113e4ee084ab388c4bcdc51bec5f51553dde2d9a1bff7bdabc0b604fe68b62caa
7
+ data.tar.gz: 007e6e6b7a0b5cbb8873aa25257835425f7ae0822d9afaa90a66f6cdac2f96341a9c0a3ccc366cddd57219c04a08029fbb3466059586623343ec55e455f50cd2
@@ -0,0 +1,150 @@
1
+ Routific Ruby Gem
2
+ =================
3
+
4
+ This Ruby Gem assists users to easily access the [Routific API][1], which is a practical and scalable solution to the Vehicle Routing Problem.
5
+
6
+ Logistics companies struggle with this challenge every day; most of them are still manually scheduling their fleet with a team of dispatchers.
7
+
8
+ Routific can automate this process, and optimize it. The savings are tremendous: less fuel, and fewer vehicles, drivers and dispatchers.
9
+
10
+ In the U.S., 1/8th of all fuel is consumed by trucks - that's 50 billion gallons a year. Our optimization algorithms will reduce that number by 20%!
11
+
12
+ [1]: https://routific.com
13
+
14
+ Installing
15
+ ----------
16
+
17
+ > gem install routific
18
+
19
+ Usage
20
+ -----
21
+ Remember to require it before using it
22
+
23
+ > require 'routific'
24
+
25
+ The following instance methods are available:
26
+
27
+ - Sets a location with the specified ID and parameters
28
+
29
+ Required arguments in params:
30
+
31
+ - lat: Latitude of this location
32
+ - lng: Longitude of this location
33
+
34
+ Optional arguments in params:
35
+ - name: Name of this location
36
+
37
+ > routific.setLocation( id, params )
38
+
39
+ - Sets a visit for the specified location using the specified parameters
40
+
41
+ Optional arguments in params:
42
+ - start: the earliest time for this visit. Default value is 00:00, if not specified.
43
+ - end: the latest time for this visit. Default value is 23:59, if not specified.
44
+ - duration: the length of this visit in minutes
45
+ - demand: the capacity that this visit requires
46
+
47
+ > routific.setVisit( id, [params] )
48
+
49
+ - Sets a vehicle with the specified ID and parameters
50
+
51
+ Required arguments in params:
52
+ - start_location: ID of start location for this vehicle
53
+
54
+ Optional arguments in params:
55
+ - end_location: ID of end location for this vehicle
56
+ - shift_start: this vehicle's start shift time (e.g. '08:00'). Default value is 00:00, if not specified.
57
+ - shift_end: this vehicle's end shift time (e.g. '17:00'). Default value is 23:59, if not specified.
58
+ - capacity: the capacity that this vehicle can load
59
+
60
+ > routific.setVehicle( id, params )
61
+
62
+ - Returns the route using the previously provided network, visits and
63
+ fleet information
64
+ > routific.getRoute()
65
+
66
+ The following class methods are available:
67
+
68
+ - Sets the default access token to use
69
+ > Routific.setToken( token )
70
+
71
+ - Returns the route using the specified access token, network, visits and fleet information
72
+ > Routific.getRoute( id, [params] )
73
+
74
+ Both getRoute functions return the Route object, which has the following methods:
75
+
76
+ - status: A sanity check, will always be success when the HTTP code is 200
77
+ - fitness: Total travel-time, representing the fitness score of the solution (less is better)
78
+ - unserved: List of visits that could not be scheduled.
79
+ - vehicleRoutes: The optimized schedule
80
+
81
+ Examples
82
+ --------
83
+ Example 1:
84
+
85
+ require 'routific'
86
+
87
+ routific = Routific.new(--API_KEY--)
88
+ routific.setLocation("order_1", {
89
+ "name" => "6800 Cambie",
90
+ "lat" => 49.227107,
91
+ "lng" => -123.1163085,
92
+ })
93
+
94
+ routific.setLocation("depot", {
95
+ "name" => "800 Kingsway",
96
+ "lat" => 49.2553636,
97
+ "lng" => -123.0873365,
98
+ })
99
+
100
+ routific.setVisit("order_1", {
101
+ "start" => "9:00",
102
+ "end" => "12:00",
103
+ "duration" => 10,
104
+ })
105
+
106
+ routific.setVehicle("vehicle_1", {
107
+ "start_location" => "depot",
108
+ "end_location" => "depot",
109
+ "shift_start" => "8:00",
110
+ "shift_end" => "12:00",
111
+ })
112
+
113
+ Example 2:
114
+
115
+ require 'routific'
116
+
117
+ Routific.setToken(--API_KEY--)
118
+ network = {
119
+ "order_1" => {
120
+ "name" => "6800 Cambie",
121
+ "lat" => 49.227107,
122
+ "lng" => -123.1163085
123
+ },
124
+ "depot" => {
125
+ "name" => "800 Kingsway",
126
+ "lat" => 49.2553636,
127
+ "lng" => -123.0873365
128
+ }
129
+ }
130
+ visits = {
131
+ "order_1" => {
132
+ "start" => "9:00",
133
+ "end" => "12:00",
134
+ "duration" => 10
135
+ }
136
+ }
137
+ fleet = {
138
+ "vehicle_1" => {
139
+ "start-location" => "depot",
140
+ "end-location" => "depot",
141
+ "shift-start" => "8:00",
142
+ "shift-end" => "12:00"
143
+ }
144
+ }
145
+ @data = {
146
+ network: network,
147
+ visits: visits,
148
+ fleet: fleet
149
+ }
150
+ Routific.getRoute(@data)
@@ -0,0 +1,88 @@
1
+ require 'rest-client'
2
+ require 'json'
3
+
4
+ require_relative './routific/location'
5
+ require_relative './routific/visit'
6
+ require_relative './routific/vehicle'
7
+ require_relative './routific/route'
8
+ require_relative './routific/way_point'
9
+
10
+ # Main class of this gem
11
+ class Routific
12
+ attr_reader :token, :network, :visits, :fleet
13
+
14
+ # Constructor
15
+ # token: Access token for Routific API
16
+ def initialize(token)
17
+ @token = token
18
+ @network = {}
19
+ @visits = {}
20
+ @fleet = {}
21
+ end
22
+
23
+ # Sets a location with the specified ID and parameters
24
+ # id: location ID
25
+ # params: parameters for this location
26
+ def setLocation(id, params)
27
+ network[id] = Location.new(params)
28
+ end
29
+
30
+ # Sets a visit for the specified location using the specified parameters
31
+ # id: ID of location to visit
32
+ # params: parameters for this visit
33
+ def setVisit(id, params={})
34
+ visits[id] = Visit.new(params)
35
+ end
36
+
37
+ # Sets a vehicle with the specified ID and parameters
38
+ # id: vehicle ID
39
+ # params: parameters for this vehicle
40
+ def setVehicle(id, params)
41
+ fleet[id] = Vehicle.new(params)
42
+ end
43
+
44
+ # Returns the route using the previously provided network, visits and fleet information
45
+ def getRoute
46
+ data = {
47
+ network: network,
48
+ visits: visits,
49
+ fleet: fleet
50
+ }
51
+
52
+ Routific.getRoute(data, token)
53
+ end
54
+
55
+ class << self
56
+ # Sets the default access token to use
57
+ def setToken(token)
58
+ @@token = token
59
+ end
60
+
61
+ def token
62
+ @@token
63
+ end
64
+
65
+ # Returns the route using the specified access token, network, visits and fleet information
66
+ # If no access token is provided, the default access token previously set is used
67
+ # If the default access token either is nil or has not been set, an ArgumentError is raised
68
+ def getRoute(data, token = @@token)
69
+ if token.nil?
70
+ raise ArgumentError, "access token must be set"
71
+ end
72
+
73
+ # Sends HTTP request to Routific API server
74
+ response = RestClient.post('https://routific.com/api/vrp',
75
+ data.to_json,
76
+ 'Authorization' => "bearer #{token}",
77
+ content_type: :json,
78
+ accept: :json
79
+ )
80
+
81
+ # Parse the HTTP request response to JSON
82
+ jsonResponse = JSON.parse(response)
83
+
84
+ # Parse the JSON representation into a Route object
85
+ Route.parse(jsonResponse)
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,41 @@
1
+ # This class represents a location in the network
2
+ class Location
3
+ attr_accessor :name, :lat, :lng
4
+
5
+ # Constructor
6
+ #
7
+ # Required arguments in params:
8
+ # lat: Latitude of this location
9
+ # lng: Longitude of this location
10
+ #
11
+ # Optional arguments in params:
12
+ # name: Name of this location
13
+ def initialize(params)
14
+ # Validates the parameters provided
15
+ validate(params)
16
+
17
+ @lat = params["lat"]
18
+ @lng = params["lng"]
19
+ @name = params["name"]
20
+ end
21
+
22
+ # Returns the JSON representation of this object
23
+ def to_json(options = nil)
24
+ jsonData = {}
25
+ jsonData["name"] = self.name if self.name
26
+ jsonData["lat"] = self.lat
27
+ jsonData["lng"] = self.lng
28
+
29
+ jsonData.to_json
30
+ end
31
+
32
+ private
33
+ # Validates the parameters being provided
34
+ # Raises an ArgumentError if any of the required parameters is not provided.
35
+ # Required parameters are: latitude and longitude
36
+ def validate(params)
37
+ if(params["lat"].nil? || params["lng"].nil?)
38
+ raise ArgumentError, "'lat' and 'lng' parameters must be provided"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,49 @@
1
+ # This class represents the resulting route returned by the Routific API
2
+ class Route
3
+ attr_reader :status, :fitness, :unserved, :vehicleRoutes
4
+
5
+ # Constructor
6
+ def initialize(status, fitness, unserved)
7
+ @status = status
8
+ @fitness = fitness
9
+ @unserved = unserved
10
+ @vehicleRoutes = Hash.new()
11
+ end
12
+
13
+ # Adds a new way point for the specified vehicle
14
+ def addWayPoint(vehicle_name, way_point)
15
+ if @vehicleRoutes[vehicle_name].nil?
16
+ # No previous way point was added for the specified vehicle, so create a new array
17
+ @vehicleRoutes[vehicle_name] = []
18
+ end
19
+ # Adds the provided way point for the specified vehicle
20
+ @vehicleRoutes[vehicle_name] << way_point
21
+ end
22
+
23
+ class << self
24
+ # Parse the JSON representation of a route, and return it as a Route object
25
+ def parse(routeJson)
26
+ status = routeJson["status"]
27
+ fitness = routeJson["fitness"]
28
+ unserved = routeJson["unserved"]
29
+ route = Route.new(status, fitness, unserved)
30
+
31
+ # Get way points for each vehicles
32
+ routeJson["solution"].each do |vehicle_name, way_points|
33
+ # Get all way points for this vehicle
34
+ way_points.each do |waypoint_info|
35
+ # Get all information for this way point
36
+ location_id = waypoint_info["location_id"]
37
+ location_name = waypoint_info["location_name"]
38
+ arrival_time = waypoint_info["arrival_time"]
39
+ finish_time = waypoint_info["finish_time"]
40
+ way_point = WayPoint.new(location_id, location_name, arrival_time, finish_time)
41
+ route.addWayPoint(vehicle_name, way_point)
42
+ end
43
+ end
44
+
45
+ # Return the resulting Route object
46
+ route
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,47 @@
1
+ # This class represents a vehicle in the fleet
2
+ class Vehicle
3
+ attr_accessor :start_location, :end_location, :shift_start, :shift_end, :capacity
4
+
5
+ # Constructor
6
+ #
7
+ # Required arguments in params:
8
+ # start_location: ID of start location for this vehicle
9
+ #
10
+ # Optional arguments in params:
11
+ # end_location: ID of end location for this vehicle
12
+ # shift_start: this vehicle's start shift time (e.g. '08:00'). Default value is 00:00, if not specified.
13
+ # shift_end: this vehicle's end shift time (e.g. '17:00'). Default value is 23:59, if not specified.
14
+ # capacity: the capacity that this vehicle can load
15
+ def initialize(params)
16
+ # Validates the provided parameters
17
+ validate(params)
18
+
19
+ @start_location = params["start_location"]
20
+ @end_location = params["end_location"]
21
+ @shift_start = params["shift_start"]
22
+ @shift_end = params["shift_end"]
23
+ @capacity = params["capacity"]
24
+ end
25
+
26
+ # Returns the JSON representation of this object
27
+ def to_json(options = nil)
28
+ jsonData = {}
29
+ jsonData["start-location"] = self.start_location
30
+ jsonData["end-location"] = self.end_location if self.end_location
31
+ jsonData["shift-start"] = self.shift_start if self.shift_start
32
+ jsonData["shift-end"] = self.shift_end if self.shift_end
33
+ jsonData["capacity"] = self.capacity if self.capacity
34
+
35
+ jsonData.to_json
36
+ end
37
+
38
+ private
39
+ # Validates the parameters being provided
40
+ # Raises an ArgumentError if any of the required parameters is not provided.
41
+ # Required parameter is: start_location
42
+ def validate(params)
43
+ if(params["start_location"].nil?)
44
+ raise ArgumentError, "'start_location' parameter must be provided"
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,29 @@
1
+ # This class represents a location to be visited
2
+ class Visit
3
+ attr_reader :start, :end, :duration, :demand
4
+
5
+ # Constructor
6
+ #
7
+ # Optional arguments in params:
8
+ # start: the earliest time for this visit. Default value is 00:00, if not specified.
9
+ # end: the latest time for this visit. Default value is 23:59, if not specified.
10
+ # duration: the length of this visit in minutes
11
+ # demand: the capacity that this visit requires
12
+ def initialize(params = {})
13
+ @start = params["start"]
14
+ @end = params["end"]
15
+ @duration = params["duration"]
16
+ @demand = params["demand"]
17
+ end
18
+
19
+ # Returns the JSON representation of this object
20
+ def to_json(options = nil)
21
+ jsonData = {}
22
+ jsonData["start"] = self.start if self.start
23
+ jsonData["end"] = self.end if self.end
24
+ jsonData["duration"] = self.duration if self.duration
25
+ jsonData["demand"] = self.demand if self.demand
26
+
27
+ jsonData.to_json
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ # This class represents a location to visit in the route
2
+ class WayPoint
3
+ attr_reader :location_id, :location_name, :arrival_time, :finish_time
4
+
5
+ # Constructor
6
+ def initialize(location_id, location_name, arrival_time, finish_time)
7
+ @location_id = location_id
8
+ @location_name = location_name
9
+ @arrival_time = arrival_time
10
+ @finish_time = finish_time
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: routific
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Marc Kuo
8
+ - Andre Soesilo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-07-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.7'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.7'
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.8'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.8'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: faker
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '1.4'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.4'
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '0.10'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '0.10'
84
+ - !ruby/object:Gem::Dependency
85
+ name: pry-debugger
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '0.2'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '0.2'
98
+ - !ruby/object:Gem::Dependency
99
+ name: dotenv
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '0.11'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '0.11'
112
+ description: Gem to use Routific API
113
+ email: asoesilo@live.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files:
117
+ - README.md
118
+ files:
119
+ - "./lib/routific.rb"
120
+ - "./lib/routific/location.rb"
121
+ - "./lib/routific/route.rb"
122
+ - "./lib/routific/vehicle.rb"
123
+ - "./lib/routific/visit.rb"
124
+ - "./lib/routific/way_point.rb"
125
+ - README.md
126
+ homepage: https://routific.com/
127
+ licenses:
128
+ - MIT
129
+ metadata:
130
+ source_code: https://github.com/asoesilo/routific-gem
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.2.2
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: routific API
151
+ test_files: []