routing 0.0.3 → 0.0.4
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 +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
|