routing 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +2 -2
- data/LICENSE +2 -2
- data/lib/routing/adapter.rb +2 -1
- data/lib/routing/adapter/here.rb +62 -0
- data/lib/routing/parser.rb +2 -1
- data/lib/routing/parser/here_simple.rb +110 -0
- data/lib/routing/version.rb +1 -1
- data/spec/fixtures/here/error_response.json +17 -0
- data/spec/fixtures/here/response.json +245 -0
- data/spec/routing/adapter/here_spec.rb +88 -0
- data/spec/routing/parser/here_simple_spec.rb +81 -0
- metadata +40 -23
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6f2365563b9f8bbdedbfc071a7617b1d0d5865d1
|
4
|
+
data.tar.gz: f39f04367027d8d773ff8e9e98246fc29649f701
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3bc6220170518feca7a9ba21ae7a0c4af6ba7a3cbe51b8ee5996f53f2a9552747acee5d74a02bf79ca19cc471ae45ea30073ca8a40b0b0784495dffc43757ef1
|
7
|
+
data.tar.gz: fe3dde7390ad12fbed60fa4647877f16a82adef21ad1dad3dcd68e60ed4fecbf14f9e850c2c4d5c757e4be8897eaf1afe1c25206cdeafc8ee567942479d2b22b
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c)
|
1
|
+
Copyright (c) 2014 flinc AG
|
2
2
|
|
3
3
|
MIT License
|
4
4
|
|
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/routing/adapter.rb
CHANGED
@@ -15,8 +15,9 @@ class Routing
|
|
15
15
|
# as only parameters and will return an Array of {Routing::GeoPoint}s when the calculation is done.
|
16
16
|
module Adapter
|
17
17
|
|
18
|
+
autoload :Here, "routing/adapter/here"
|
18
19
|
autoload :Navteq, "routing/adapter/navteq"
|
19
20
|
autoload :Test, "routing/adapter/test"
|
20
21
|
|
21
22
|
end
|
22
|
-
end
|
23
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
class Routing
|
5
|
+
module Adapter
|
6
|
+
|
7
|
+
# Adapter for a Nokia Here Routing Service v7 server.
|
8
|
+
# It passes the {GeoPoint}s to the routing service and will return another
|
9
|
+
# Array of {GeoPoint}s, representing the calculated route.
|
10
|
+
class Here
|
11
|
+
|
12
|
+
def initialize(options = {})
|
13
|
+
@options = {
|
14
|
+
:host => 'http://route.api.here.com',
|
15
|
+
:service_path => '/routing/7.2/calculateroute.json',
|
16
|
+
:parser => ::Routing::Parser::HereSimple
|
17
|
+
}.merge(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def calculate(geo_points)
|
21
|
+
response = connection.get do |request|
|
22
|
+
request.url(options[:service_path])
|
23
|
+
request.params = default_params.merge(geo_points_to_params(geo_points)).merge(options[:credentials])
|
24
|
+
end
|
25
|
+
|
26
|
+
parse(response.body)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def parse(response)
|
32
|
+
options[:parser].new(response).to_geo_points
|
33
|
+
end
|
34
|
+
|
35
|
+
def default_params
|
36
|
+
options[:default_params] || {
|
37
|
+
departure: Time.now.utc.iso8601,
|
38
|
+
mode: "fastest;car",
|
39
|
+
language: "de_DE",
|
40
|
+
legattributes: "all,-links",
|
41
|
+
maneuverattributes: "position,travelTime,length,time"
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def geo_points_to_params(geo_points)
|
46
|
+
Hash[geo_points.each_with_index.map { |point, i| [ "waypoint#{i}", "geo!#{point.lat},#{point.lng}" ] }]
|
47
|
+
end
|
48
|
+
|
49
|
+
def connection
|
50
|
+
@connection ||= Faraday.new(:url => options[:host]) do |builder|
|
51
|
+
builder.request :url_encoded
|
52
|
+
builder.adapter :net_http
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def options
|
57
|
+
@options || {}
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/routing/parser.rb
CHANGED
@@ -7,6 +7,7 @@ class Routing
|
|
7
7
|
module Parser
|
8
8
|
|
9
9
|
autoload :NavteqSimple, "routing/parser/navteq_simple"
|
10
|
+
autoload :HereSimple, "routing/parser/here_simple"
|
10
11
|
|
11
12
|
# This error is thrown by the parsers if a calculated waypoint can't be matched
|
12
13
|
# to one of the initial passed geo points that were routed.
|
@@ -23,4 +24,4 @@ class Routing
|
|
23
24
|
end
|
24
25
|
|
25
26
|
end
|
26
|
-
end
|
27
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
class Routing
|
2
|
+
module Parser
|
3
|
+
|
4
|
+
# A very simple parser implementation for a Nokia Here Routing Service v7.
|
5
|
+
# It converts the json response of the routing service to an Array of {GeoPoint}s.
|
6
|
+
class HereSimple
|
7
|
+
|
8
|
+
# Creates a new instance of the parser.
|
9
|
+
#
|
10
|
+
# @param [String] response
|
11
|
+
# A json response string of a Nokia Here routing server.
|
12
|
+
def initialize(response)
|
13
|
+
response = JSON.parse(response)
|
14
|
+
check_for_error(response)
|
15
|
+
|
16
|
+
@route = response["response"]["route"].first
|
17
|
+
@overall_covered_distance = 0
|
18
|
+
@overall_relative_time = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
# Converts the server response in an Array of {GeoPoint}s
|
22
|
+
#
|
23
|
+
# @return [Array<GeoPoint>]
|
24
|
+
# List of {GeoPoint}s that represent the calculated route.
|
25
|
+
def to_geo_points
|
26
|
+
legs = @route["leg"]
|
27
|
+
geo_points = legs.map { |leg| parse_leg(leg) }.flatten
|
28
|
+
|
29
|
+
# At last we add the destination point
|
30
|
+
geo_points << parse_maneuver(legs.last["maneuver"].last, waypoint: true)
|
31
|
+
geo_points
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# Parses is single leg of the route including all its maneuvers.
|
37
|
+
#
|
38
|
+
# @param [Hash] leg
|
39
|
+
# The route leg to parse.
|
40
|
+
#
|
41
|
+
# @return [Array<GeoPoint>]
|
42
|
+
# List of {GeoPoint}s that represent the passed Leg.
|
43
|
+
def parse_leg(leg)
|
44
|
+
# Skip the last maneuver as it is the same as the first one
|
45
|
+
# of the next maneuver.
|
46
|
+
# For the last leg we parse the last maneuver right at the end
|
47
|
+
maneuvers = leg["maneuver"][0...-1]
|
48
|
+
maneuvers.map do |maneuver|
|
49
|
+
parse_maneuver(maneuver, :waypoint => (maneuver == maneuvers.first))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Parses is single maneuver of a route leg.
|
54
|
+
#
|
55
|
+
# @param [Hash] maneuver
|
56
|
+
# The maneuver to parse.
|
57
|
+
#
|
58
|
+
# @param [Hash] attributes
|
59
|
+
# Additional attributes that should be set on the returned {GeoPoint}.
|
60
|
+
#
|
61
|
+
# @return [GeoPoint]
|
62
|
+
# A {GeoPoint} that represents the passed maneuver.
|
63
|
+
def parse_maneuver(maneuver, attributes = {})
|
64
|
+
geo_point = ::Routing::GeoPoint.new attributes.merge({
|
65
|
+
lat: maneuver["position"]["latitude"],
|
66
|
+
lng: maneuver["position"]["longitude"],
|
67
|
+
relative_time: @overall_relative_time,
|
68
|
+
distance: @overall_covered_distance
|
69
|
+
})
|
70
|
+
|
71
|
+
@overall_relative_time += maneuver["travelTime"].to_i
|
72
|
+
@overall_covered_distance += maneuver["length"].to_i
|
73
|
+
|
74
|
+
search_original_position(geo_point) if geo_point.waypoint?
|
75
|
+
|
76
|
+
geo_point
|
77
|
+
end
|
78
|
+
|
79
|
+
# Matches a parsed {GeoPoint} of the route response
|
80
|
+
# with the (unmapped) position of the
|
81
|
+
# corresponding {GeoPoint} of the request.
|
82
|
+
#
|
83
|
+
# @param [GeoPoint] geo_point
|
84
|
+
# Point of the response to find the initial position for.
|
85
|
+
#
|
86
|
+
# @return [GeoPoint]
|
87
|
+
# The passed in {GeoPoint}, enriched with the information about the original position in the request.
|
88
|
+
#
|
89
|
+
# @raise [NoMatchingMappedPositionFound] If no matching original position is found.
|
90
|
+
def search_original_position(geo_point)
|
91
|
+
matching_waypoint = @route["waypoint"].detect do |waypoint|
|
92
|
+
waypoint["mappedPosition"]["latitude"] == geo_point.lat &&
|
93
|
+
waypoint["mappedPosition"]["longitude"] == geo_point.lng
|
94
|
+
end or raise NoMatchingMappedPositionFound
|
95
|
+
|
96
|
+
geo_point.original_lat = matching_waypoint["originalPosition"]["latitude"]
|
97
|
+
geo_point.original_lng = matching_waypoint["originalPosition"]["longitude"]
|
98
|
+
|
99
|
+
geo_point
|
100
|
+
end
|
101
|
+
|
102
|
+
def check_for_error(response)
|
103
|
+
if error = response['type'] && response['type'][/error/i]
|
104
|
+
raise Routing::Parser::RoutingFailed.new("#{response['type']}(#{response['subtype']}) - #{response['details']}")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/routing/version.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
{
|
2
|
+
"type": "ApplicationError",
|
3
|
+
"subtype": "NoRouteFound",
|
4
|
+
"details": "Error is NGEO_ERROR_ROUTE_NO_END_POINT",
|
5
|
+
"additionalData": [
|
6
|
+
{
|
7
|
+
"key": "error_code",
|
8
|
+
"value": "NGEO_ERROR_ROUTE_NO_END_POINT"
|
9
|
+
}
|
10
|
+
],
|
11
|
+
"metaInfo": {
|
12
|
+
"timestamp": "2014-02-20T08:49:26.399Z",
|
13
|
+
"mapVersion": "8.30.53.153",
|
14
|
+
"moduleVersion": "7.2.42.0_CD-902_1",
|
15
|
+
"interfaceVersion": "2.4.37"
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,245 @@
|
|
1
|
+
{
|
2
|
+
"response": {
|
3
|
+
"metaInfo": {
|
4
|
+
"timestamp": "2014-02-20T08:48:17.028Z",
|
5
|
+
"mapVersion": "8.30.53.153",
|
6
|
+
"moduleVersion": "7.2.42.0_CD-902_1",
|
7
|
+
"interfaceVersion": "2.4.37"
|
8
|
+
},
|
9
|
+
"route": [
|
10
|
+
{
|
11
|
+
"waypoint": [
|
12
|
+
{
|
13
|
+
"linkId": "+1600996215040705549",
|
14
|
+
"mappedPosition": {
|
15
|
+
"latitude": 49.9019153,
|
16
|
+
"longitude": 8.8588599
|
17
|
+
},
|
18
|
+
"originalPosition": {
|
19
|
+
"latitude": 49.90261,
|
20
|
+
"longitude": 8.85866
|
21
|
+
},
|
22
|
+
"type": "stopOver",
|
23
|
+
"spot": 0.4035088,
|
24
|
+
"sideOfStreet": "left",
|
25
|
+
"mappedRoadName": "Hohe Straße",
|
26
|
+
"label": "Hohe Straße",
|
27
|
+
"shapeIndex": 0
|
28
|
+
},
|
29
|
+
{
|
30
|
+
"linkId": "-1601136969708929748",
|
31
|
+
"mappedPosition": {
|
32
|
+
"latitude": 49.9533103,
|
33
|
+
"longitude": 8.9529667
|
34
|
+
},
|
35
|
+
"originalPosition": {
|
36
|
+
"latitude": 49.9532,
|
37
|
+
"longitude": 8.95293
|
38
|
+
},
|
39
|
+
"type": "stopOver",
|
40
|
+
"spot": 0.3484848,
|
41
|
+
"sideOfStreet": "right",
|
42
|
+
"mappedRoadName": "Südring",
|
43
|
+
"label": "Südring",
|
44
|
+
"shapeIndex": 55
|
45
|
+
}
|
46
|
+
],
|
47
|
+
"mode": {
|
48
|
+
"type": "fastest",
|
49
|
+
"transportModes": [
|
50
|
+
"car"
|
51
|
+
],
|
52
|
+
"trafficMode": "default",
|
53
|
+
"feature": []
|
54
|
+
},
|
55
|
+
"leg": [
|
56
|
+
{
|
57
|
+
"start": {
|
58
|
+
"linkId": "+1600996215040705549",
|
59
|
+
"mappedPosition": {
|
60
|
+
"latitude": 49.9019153,
|
61
|
+
"longitude": 8.8588599
|
62
|
+
},
|
63
|
+
"originalPosition": {
|
64
|
+
"latitude": 49.90261,
|
65
|
+
"longitude": 8.85866
|
66
|
+
},
|
67
|
+
"type": "stopOver",
|
68
|
+
"spot": 0.4035088,
|
69
|
+
"sideOfStreet": "left",
|
70
|
+
"mappedRoadName": "Hohe Straße",
|
71
|
+
"label": "Hohe Straße",
|
72
|
+
"shapeIndex": 0
|
73
|
+
},
|
74
|
+
"end": {
|
75
|
+
"linkId": "-1601136969708929748",
|
76
|
+
"mappedPosition": {
|
77
|
+
"latitude": 49.9533103,
|
78
|
+
"longitude": 8.9529667
|
79
|
+
},
|
80
|
+
"originalPosition": {
|
81
|
+
"latitude": 49.9532,
|
82
|
+
"longitude": 8.95293
|
83
|
+
},
|
84
|
+
"type": "stopOver",
|
85
|
+
"spot": 0.3484848,
|
86
|
+
"sideOfStreet": "right",
|
87
|
+
"mappedRoadName": "Südring",
|
88
|
+
"label": "Südring",
|
89
|
+
"shapeIndex": 55
|
90
|
+
},
|
91
|
+
"length": 9117,
|
92
|
+
"travelTime": 592,
|
93
|
+
"maneuver": [
|
94
|
+
{
|
95
|
+
"position": {
|
96
|
+
"latitude": 49.9019153,
|
97
|
+
"longitude": 8.8588599
|
98
|
+
},
|
99
|
+
"instruction": "Fahren Sie auf <span class=\"street\">Hohe Straße</span> nach <span class=\"heading\">Osten</span>. <span class=\"distance-description\">Fahren Sie <span class=\"length\">159 m</span></span>.",
|
100
|
+
"travelTime": 35,
|
101
|
+
"length": 159,
|
102
|
+
"time": "2014-02-20T08:48:19Z",
|
103
|
+
"id": "M1",
|
104
|
+
"_type": "PrivateTransportManeuverType"
|
105
|
+
},
|
106
|
+
{
|
107
|
+
"position": {
|
108
|
+
"latitude": 49.9020696,
|
109
|
+
"longitude": 8.8610744
|
110
|
+
},
|
111
|
+
"instruction": "Biegen Sie <span class=\"direction\">links</span> ab auf die <span class=\"number\">K128</span>. <span class=\"distance-description\">Fahren Sie <span class=\"length\">1.1 km</span></span>.",
|
112
|
+
"travelTime": 88,
|
113
|
+
"length": 1103,
|
114
|
+
"time": "2014-02-20T08:48:54Z",
|
115
|
+
"id": "M2",
|
116
|
+
"_type": "PrivateTransportManeuverType"
|
117
|
+
},
|
118
|
+
{
|
119
|
+
"position": {
|
120
|
+
"latitude": 49.9085712,
|
121
|
+
"longitude": 8.8707948
|
122
|
+
},
|
123
|
+
"instruction": "Biegen Sie <span class=\"direction\">links</span> ab auf die <span class=\"number\">B26</span>. <span class=\"distance-description\">Fahren Sie <span class=\"length\">7.8 km</span></span>.",
|
124
|
+
"travelTime": 455,
|
125
|
+
"length": 7763,
|
126
|
+
"time": "2014-02-20T08:50:22Z",
|
127
|
+
"id": "M3",
|
128
|
+
"_type": "PrivateTransportManeuverType"
|
129
|
+
},
|
130
|
+
{
|
131
|
+
"position": {
|
132
|
+
"latitude": 49.9537396,
|
133
|
+
"longitude": 8.9518619
|
134
|
+
},
|
135
|
+
"instruction": "Biegen Sie <span class=\"direction\">rechts</span> ab auf <span class=\"next-street\">Südring</span>. <span class=\"distance-description\">Fahren Sie <span class=\"length\">92 m</span></span>.",
|
136
|
+
"travelTime": 14,
|
137
|
+
"length": 92,
|
138
|
+
"time": "2014-02-20T08:57:57Z",
|
139
|
+
"id": "M4",
|
140
|
+
"_type": "PrivateTransportManeuverType"
|
141
|
+
},
|
142
|
+
{
|
143
|
+
"position": {
|
144
|
+
"latitude": 49.9533103,
|
145
|
+
"longitude": 8.9529667
|
146
|
+
},
|
147
|
+
"instruction": "Sie erreichen <span class=\"street\">Südring</span>. Ihr Ziel liegt auf der rechten Seite.",
|
148
|
+
"travelTime": 0,
|
149
|
+
"length": 0,
|
150
|
+
"time": "2014-02-20T08:58:11Z",
|
151
|
+
"id": "M5",
|
152
|
+
"_type": "PrivateTransportManeuverType"
|
153
|
+
}
|
154
|
+
],
|
155
|
+
"boundingBox": {
|
156
|
+
"topLeft": {
|
157
|
+
"latitude": 49.9537396,
|
158
|
+
"longitude": 8.8588599
|
159
|
+
},
|
160
|
+
"bottomRight": {
|
161
|
+
"latitude": 49.9019153,
|
162
|
+
"longitude": 8.9529667
|
163
|
+
}
|
164
|
+
},
|
165
|
+
"shape": [
|
166
|
+
"49.9019153,8.8588599",
|
167
|
+
"49.901973,8.8593256",
|
168
|
+
"49.9020696,8.8610744",
|
169
|
+
"49.9025095,8.8611817",
|
170
|
+
"49.9029493,8.861289",
|
171
|
+
"49.9037647,8.8615787",
|
172
|
+
"49.9040115,8.8616967",
|
173
|
+
"49.904741,8.8621795",
|
174
|
+
"49.90502,8.862437",
|
175
|
+
"49.9054062,8.8628447",
|
176
|
+
"49.9057817,8.8632846",
|
177
|
+
"49.9061894,8.8638747",
|
178
|
+
"49.9069083,8.8651192",
|
179
|
+
"49.9071443,8.8655806",
|
180
|
+
"49.9073482,8.8660741",
|
181
|
+
"49.9074447,8.8663852",
|
182
|
+
"49.9075949,8.8672328",
|
183
|
+
"49.9076915,8.8675761",
|
184
|
+
"49.907949,8.868295",
|
185
|
+
"49.9086678,8.8700974",
|
186
|
+
"49.9087322,8.8702905",
|
187
|
+
"49.9087429,8.870548",
|
188
|
+
"49.9087214,8.8706338",
|
189
|
+
"49.9086571,8.8707197",
|
190
|
+
"49.9085712,8.8707948",
|
191
|
+
"49.9086678,8.8709557",
|
192
|
+
"49.9101484,8.8739598",
|
193
|
+
"49.9104702,8.8746464",
|
194
|
+
"49.9114037,8.8769531",
|
195
|
+
"49.9127448,8.8803542",
|
196
|
+
"49.913528,8.8822746",
|
197
|
+
"49.9138498,8.882972",
|
198
|
+
"49.9140751,8.883369",
|
199
|
+
"49.9143648,8.8838089",
|
200
|
+
"49.914633,8.8841629",
|
201
|
+
"49.9154699,8.8850641",
|
202
|
+
"49.9202979,8.8900208",
|
203
|
+
"49.9205768,8.8903213",
|
204
|
+
"49.9208665,8.8907182",
|
205
|
+
"49.9210382,8.8910079",
|
206
|
+
"49.9212849,8.8915551",
|
207
|
+
"49.9214458,8.8921237",
|
208
|
+
"49.9215531,8.8925743",
|
209
|
+
"49.9216604,8.8934648",
|
210
|
+
"49.9217892,8.8952565",
|
211
|
+
"49.9218857,8.8959432",
|
212
|
+
"49.921993,8.8962972",
|
213
|
+
"49.9222076,8.8968337",
|
214
|
+
"49.942764,8.9327645",
|
215
|
+
"49.9496412,8.9447272",
|
216
|
+
"49.9522698,8.9493299",
|
217
|
+
"49.9536109,8.9516366",
|
218
|
+
"49.9537396,8.9518619",
|
219
|
+
"49.9534822,8.9524198",
|
220
|
+
"49.9533641,8.9527309",
|
221
|
+
"49.9533103,8.9529667"
|
222
|
+
],
|
223
|
+
"firstPoint": 0,
|
224
|
+
"lastPoint": 55,
|
225
|
+
"trafficTime": 667,
|
226
|
+
"baseTime": 592,
|
227
|
+
"summary": {
|
228
|
+
"distance": 9117,
|
229
|
+
"trafficTime": 667,
|
230
|
+
"baseTime": 592,
|
231
|
+
"travelTime": 592
|
232
|
+
}
|
233
|
+
}
|
234
|
+
],
|
235
|
+
"summary": {
|
236
|
+
"distance": 9117,
|
237
|
+
"trafficTime": 667,
|
238
|
+
"baseTime": 592,
|
239
|
+
"travelTime": 592
|
240
|
+
}
|
241
|
+
}
|
242
|
+
],
|
243
|
+
"language": "de-de"
|
244
|
+
}
|
245
|
+
}
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Routing::Adapter::Here do
|
4
|
+
|
5
|
+
let(:response) { mock(:response).as_null_object }
|
6
|
+
let(:request) { mock(:request).as_null_object }
|
7
|
+
let(:connection) { mock(:connection).as_null_object }
|
8
|
+
let(:parser_class) { mock(:parser_class, :new => parser) }
|
9
|
+
let(:parser) { mock(:parser).as_null_object }
|
10
|
+
|
11
|
+
let(:options) do
|
12
|
+
{ :parser => parser_class, :credentials => { :app_id => "123", :app_code => "456" } }
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:geo_points) { [stub(:lat => 1, :lng => 2), stub(:lat => 3, :lng => 4), stub(:lat => 5, :lng => 6)] }
|
16
|
+
|
17
|
+
subject { described_class.new(options) }
|
18
|
+
|
19
|
+
before do
|
20
|
+
connection.stub(:get).and_yield(request).and_return(response)
|
21
|
+
Faraday.stub(:new).and_return(connection)
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'creating a new instance' do
|
25
|
+
it 'can be instantiated without arguments' do
|
26
|
+
expect { described_class.new }.to_not raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'allows setting the host' do
|
30
|
+
Faraday.should_receive(:new).with(:url => 'http://other.com')
|
31
|
+
options.merge!(:host => 'http://other.com')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'allows setting the default params' do
|
35
|
+
params = { :hello => "world" }
|
36
|
+
options.merge!(:default_params => params)
|
37
|
+
request.should_receive(:params=).with(hash_including(params))
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'sets the api credentials' do
|
41
|
+
request.should_receive(:params=).with(hash_including({ :app_id => "123", :app_code => "456" }))
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should allow setting the service path' do
|
45
|
+
options.merge!(:service_path => '/some/path.json')
|
46
|
+
request.should_receive(:url).with('/some/path.json')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should use a default service path when none is given' do
|
50
|
+
request.should_receive(:url).with('/routing/7.2/calculateroute.json')
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should allow setting the parser' do
|
54
|
+
options.merge!(:parser => parser_class)
|
55
|
+
parser_class.should_receive(:new)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should use a default parser when none is given' do
|
59
|
+
options.delete(:parser)
|
60
|
+
Routing::Parser::HereSimple.should_receive(:new).and_return(parser)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'ignores unknown options' do
|
64
|
+
expect { described_class.new(:hello => "world") }.to_not raise_error
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#calculate' do
|
69
|
+
it 'passes the response to the parser' do
|
70
|
+
response.stub(:body => '...')
|
71
|
+
parser_class.should_receive(:new).with('...')
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should return the parser\'s result' do
|
75
|
+
result = [double, double, double]
|
76
|
+
parser.stub(:to_geo_points => result)
|
77
|
+
subject.calculate(geo_points).should be(result)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should convert the geo points into a compatible format' do
|
81
|
+
request.should_receive(:params=).with hash_including({
|
82
|
+
'waypoint0' => 'geo!1,2',
|
83
|
+
'waypoint1' => 'geo!3,4',
|
84
|
+
'waypoint2' => 'geo!5,6'
|
85
|
+
})
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
describe Routing::Parser::HereSimple do
|
5
|
+
|
6
|
+
context 'with a error response' do
|
7
|
+
let(:error_response) { fixture('here/error_response.json') }
|
8
|
+
|
9
|
+
it 'should throw an RoutingFailed error' do
|
10
|
+
lambda{ described_class.new(error_response) }.should raise_error(Routing::Parser::RoutingFailed)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with a successful routing response' do
|
15
|
+
let(:response) { fixture('here/response.json') }
|
16
|
+
let(:json_response) { JSON.parse(response) }
|
17
|
+
let(:original_geo_points) do
|
18
|
+
json_response['response']['route'].first['waypoint'].collect do |waypoint|
|
19
|
+
mock({
|
20
|
+
lat: waypoint['originalPosition']['latitude'],
|
21
|
+
lng: waypoint['originalPosition']['longitude']
|
22
|
+
})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#to_geo_points' do
|
27
|
+
subject { described_class.new(response).to_geo_points }
|
28
|
+
|
29
|
+
it 'returns geopoints' do
|
30
|
+
subject.each { |point| point.should be_a(::Routing::GeoPoint) }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'number of geo points' do
|
34
|
+
let(:leg_size) { json_response["response"]["route"].first["leg"].size }
|
35
|
+
let(:leg_touching_point_size) { leg_size - 1 }
|
36
|
+
let(:maneuver_size) { json_response["response"]["route"].first["leg"].inject(0) { |sum, leg| sum + leg["maneuver"].size } }
|
37
|
+
|
38
|
+
it 'has the length of all maneuvers minus the duplicate ones at the touching points' do
|
39
|
+
should have(maneuver_size - leg_touching_point_size).geo_points
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'coordinates' do
|
44
|
+
it 'sets the calculated latitude and longitude for each geo point' do
|
45
|
+
subject.each do |geo_point|
|
46
|
+
geo_point.lat.should be
|
47
|
+
geo_point.lng.should be
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'original waypoints' do
|
53
|
+
subject { described_class.new(response).to_geo_points.select(&:waypoint?) }
|
54
|
+
|
55
|
+
it 'includes the same number of waypoints as passed in' do
|
56
|
+
should have(original_geo_points.size).geo_points
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'sets original_lat and original_lng on the waypoints' do
|
60
|
+
subject.each_with_index do |geo_point, index|
|
61
|
+
geo_point.original_lat.should eq(original_geo_points[index].lat)
|
62
|
+
geo_point.original_lng.should eq(original_geo_points[index].lng)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when response does not contain the original waypoints' do
|
67
|
+
let(:response) do
|
68
|
+
corrupted_response = JSON.parse(fixture('here/response.json'))
|
69
|
+
corrupted_response['response']['route'].first['waypoint'].first['mappedPosition']['latitude'] += 0.1
|
70
|
+
corrupted_response['response']['route'].first['waypoint'].first['mappedPosition']['longitude'] += 0.1
|
71
|
+
JSON.dump(corrupted_response)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'raises an exception if no matching original position was found' do
|
75
|
+
expect { subject }.to raise_error(Routing::Parser::NoMatchingMappedPositionFound)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: routing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.4
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Christian Bäuerlein
|
@@ -10,42 +9,51 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date:
|
12
|
+
date: 2014-02-20 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: faraday
|
17
|
-
requirement:
|
18
|
-
none: false
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
19
17
|
requirements:
|
20
|
-
- -
|
18
|
+
- - ">="
|
21
19
|
- !ruby/object:Gem::Version
|
22
20
|
version: 0.7.0
|
23
21
|
type: :runtime
|
24
22
|
prerelease: false
|
25
|
-
version_requirements:
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.7.0
|
26
28
|
- !ruby/object:Gem::Dependency
|
27
29
|
name: json
|
28
|
-
requirement:
|
29
|
-
none: false
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
|
-
- -
|
32
|
+
- - ">="
|
32
33
|
- !ruby/object:Gem::Version
|
33
34
|
version: '0'
|
34
35
|
type: :runtime
|
35
36
|
prerelease: false
|
36
|
-
version_requirements:
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
37
42
|
- !ruby/object:Gem::Dependency
|
38
43
|
name: rspec
|
39
|
-
requirement:
|
40
|
-
none: false
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
41
45
|
requirements:
|
42
|
-
- -
|
46
|
+
- - ">="
|
43
47
|
- !ruby/object:Gem::Version
|
44
48
|
version: 2.9.0
|
45
49
|
type: :development
|
46
50
|
prerelease: false
|
47
|
-
version_requirements:
|
48
|
-
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 2.9.0
|
56
|
+
description: "\n Provides a generic interface for routing services that can by
|
49
57
|
used to calculate directions between geolocations.\n Makes parsing and use-case
|
50
58
|
specific data handling easy trough an extendable middleware stack.\n "
|
51
59
|
email:
|
@@ -55,7 +63,7 @@ executables: []
|
|
55
63
|
extensions: []
|
56
64
|
extra_rdoc_files: []
|
57
65
|
files:
|
58
|
-
- .gitignore
|
66
|
+
- ".gitignore"
|
59
67
|
- Gemfile
|
60
68
|
- Guardfile
|
61
69
|
- LICENSE
|
@@ -63,52 +71,61 @@ files:
|
|
63
71
|
- Rakefile
|
64
72
|
- lib/routing.rb
|
65
73
|
- lib/routing/adapter.rb
|
74
|
+
- lib/routing/adapter/here.rb
|
66
75
|
- lib/routing/adapter/navteq.rb
|
67
76
|
- lib/routing/adapter/test.rb
|
68
77
|
- lib/routing/geo_point.rb
|
69
78
|
- lib/routing/middleware.rb
|
70
79
|
- lib/routing/parser.rb
|
80
|
+
- lib/routing/parser/here_simple.rb
|
71
81
|
- lib/routing/parser/navteq_simple.rb
|
72
82
|
- lib/routing/version.rb
|
73
83
|
- routing.gemspec
|
84
|
+
- spec/fixtures/here/error_response.json
|
85
|
+
- spec/fixtures/here/response.json
|
74
86
|
- spec/fixtures/navteq/error_response.json
|
75
87
|
- spec/fixtures/navteq/response.json
|
88
|
+
- spec/routing/adapter/here_spec.rb
|
76
89
|
- spec/routing/adapter/navteq_spec.rb
|
77
90
|
- spec/routing/adapter/test_spec.rb
|
78
91
|
- spec/routing/geo_point_spec.rb
|
92
|
+
- spec/routing/parser/here_simple_spec.rb
|
79
93
|
- spec/routing/parser/navteq_simple_spec.rb
|
80
94
|
- spec/routing_spec.rb
|
81
95
|
- spec/spec_helper.rb
|
82
96
|
homepage: https://github.com/flinc/routing
|
83
97
|
licenses: []
|
98
|
+
metadata: {}
|
84
99
|
post_install_message:
|
85
100
|
rdoc_options: []
|
86
101
|
require_paths:
|
87
102
|
- lib
|
88
103
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
104
|
requirements:
|
91
|
-
- -
|
105
|
+
- - ">="
|
92
106
|
- !ruby/object:Gem::Version
|
93
107
|
version: '0'
|
94
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
109
|
requirements:
|
97
|
-
- -
|
110
|
+
- - ">="
|
98
111
|
- !ruby/object:Gem::Version
|
99
112
|
version: '0'
|
100
113
|
requirements: []
|
101
114
|
rubyforge_project:
|
102
|
-
rubygems_version:
|
115
|
+
rubygems_version: 2.2.0
|
103
116
|
signing_key:
|
104
|
-
specification_version:
|
117
|
+
specification_version: 4
|
105
118
|
summary: A ruby interface for route calculation services
|
106
119
|
test_files:
|
120
|
+
- spec/fixtures/here/error_response.json
|
121
|
+
- spec/fixtures/here/response.json
|
107
122
|
- spec/fixtures/navteq/error_response.json
|
108
123
|
- spec/fixtures/navteq/response.json
|
124
|
+
- spec/routing/adapter/here_spec.rb
|
109
125
|
- spec/routing/adapter/navteq_spec.rb
|
110
126
|
- spec/routing/adapter/test_spec.rb
|
111
127
|
- spec/routing/geo_point_spec.rb
|
128
|
+
- spec/routing/parser/here_simple_spec.rb
|
112
129
|
- spec/routing/parser/navteq_simple_spec.rb
|
113
130
|
- spec/routing_spec.rb
|
114
131
|
- spec/spec_helper.rb
|