Skip to content

Commit

Permalink
Refactors navteq_simple.rb and navteq_simple_spec.rb
Browse files Browse the repository at this point in the history
  • Loading branch information
benedikt committed May 11, 2012
1 parent bf37338 commit c4224d5
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 98 deletions.
91 changes: 25 additions & 66 deletions lib/routing/parser/navteq_simple.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,65 +10,31 @@ class NavteqSimple
# @param [String] response
# A json response string of a NAVTEQ routing server.
def initialize(response)
@response = JSON.parse(response)
response = JSON.parse(response)
check_for_error(response)

check_for_error!

# only take the first route
@route = self.response["Response"]["Route"].first
@route = response["Response"]["Route"].first
@overall_covered_distance = 0
@overall_relative_time = 0

self
end

# The server response, as a Ruby hash.
#
# @return [Hash]
# The response, converted from json into a Ruby hash.
attr_accessor :response

# Route from the response that will be parsed.
# This will always be the first route returned.
#
# @return [Hash]
# The route, converted from json into a Ruby hash.
attr_accessor :route

# The overall distance of the parsed route in meters.
#
# @return [Fixnum]
# Overall distance in meters.
attr_accessor :overall_covered_distance

# The overall relative time of the parsed route in seconds.
#
# @return [Fixnum]
# Overall relative time in seconds.
attr_accessor :overall_relative_time

# Converts the server response in an Array of {GeoPoint}s
#
# @return [Array<GeoPoint>]
# List of {GeoPoint}s that represent the calculated route.
def to_geo_points
geo_points = []

legs = route["Leg"]

legs.each_with_index do |leg, index|
geo_points += parse_leg(leg)
end
legs = @route["Leg"]
geo_points = legs.map { |leg| parse_leg(leg) }.flatten

# At last we add the destination point
geo_points << parse_maneuver(legs.last["Maneuver"].last, waypoint: true)

# Search for the original input positions for every waypoint
geo_points.select(&:waypoint?).each{|wp| search_original_position(wp) }

geo_points
end

# private

# Parses is single leg of the route including all its maneuvers.
#
# @param [Hash] leg
Expand All @@ -77,18 +43,13 @@ def to_geo_points
# @return [Array<GeoPoint>]
# List of {GeoPoint}s that represent the passed Leg.
def parse_leg(leg)
leg_geo_points = []

maneuvers = leg["Maneuver"]

# Skip the last maneuver as it is the same as the first one
# of the next maneuver.
# For the last leg we parse the last maneuver right at the end
maneuvers[0...-1].each do |maneuver|
leg_geo_points << parse_maneuver(maneuver, :waypoint => (maneuver == maneuvers.first))
maneuvers = leg["Maneuver"][0...-1]
maneuvers.map do |maneuver|
parse_maneuver(maneuver, :waypoint => (maneuver == maneuvers.first))
end

leg_geo_points
end

# Parses is single maneuver of a route leg.
Expand All @@ -102,17 +63,19 @@ def parse_leg(leg)
# @return [GeoPoint]
# A {GeoPoint} that represents the passed maneuver.
def parse_maneuver(maneuver, attributes = {})
geopoint = ::Routing::GeoPoint.new attributes.merge({
geo_point = ::Routing::GeoPoint.new attributes.merge({
lat: maneuver["Position"]["Latitude"],
lng: maneuver["Position"]["Longitude"],
relative_time: overall_relative_time.to_i,
distance: overall_covered_distance.to_i
relative_time: @overall_relative_time,
distance: @overall_covered_distance
})

@overall_relative_time += maneuver["TravelTime"]
@overall_covered_distance += maneuver["Length"]
@overall_relative_time += maneuver["TravelTime"].to_i
@overall_covered_distance += maneuver["Length"].to_i

geopoint
search_original_position(geo_point) if geo_point.waypoint?

geo_point
end

# Matches a parsed {GeoPoint} of the route response
Expand All @@ -127,24 +90,20 @@ def parse_maneuver(maneuver, attributes = {})
#
# @raise [NoMatchingMappedPositionFound] If no matching original position is found.
def search_original_position(geo_point)
waypoints = route["Waypoint"]
matching_waypoint = route["Waypoint"].select do |waypoint|
waypoint["MappedPosition"]["Latitude"] == geo_point.lat && waypoint["MappedPosition"]["Longitude"] == geo_point.lng
end

matching_waypoint = matching_waypoint.first or raise NoMatchingMappedPositionFound
matching_waypoint = @route["Waypoint"].detect do |waypoint|
waypoint["MappedPosition"]["Latitude"] == geo_point.lat &&
waypoint["MappedPosition"]["Longitude"] == geo_point.lng
end or raise NoMatchingMappedPositionFound

geo_point.original_lat = matching_waypoint["OriginalPosition"]["Latitude"]
geo_point.original_lng = matching_waypoint["OriginalPosition"]["Longitude"]

geo_point
end

private

def check_for_error!
if @response['Error']
raise Routing::Parser::RoutingFailed.new "#{@response['Error']['type']}(#{@response['Error']['subtype']}) - #{@response['Error']['Details']}"
def check_for_error(response)
if error = response['Error']
raise Routing::Parser::RoutingFailed.new("#{error['type']}(#{error['subtype']}) - #{error['Details']}")
end
end

Expand Down
41 changes: 9 additions & 32 deletions spec/routing/parser/navteq_simple_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,26 @@

let(:geo_point_array) do
[
Routing::GeoPoint.new(lat: 49.958, lng: 8.961),
Routing::GeoPoint.new(lat: 49.8634, lng: 8.7523),
Routing::GeoPoint.new(lat: 49.8752, lng: 8.654)
mock(lat: 49.9580, lng: 8.9610),
mock(lat: 49.8634, lng: 8.7523),
mock(lat: 49.8752, lng: 8.6540)
]
end

let(:response) { fixture('navteq/response.json') }
let(:json_response) { JSON.parse(response) }
subject{ described_class.new(response) }

let(:parsed_leg) { subject.parse_leg(subject.route["Leg"].first) }

let(:maneuver_item) { subject.route["Leg"].first["Maneuver"].first }
let(:maneuver_item) { json_response["Response"]["Route"].first["Leg"].first["Maneuver"].first }
let(:parsed_maneuver_item) { subject.parse_maneuver(maneuver_item) }

context 'creating a new instance' do

its(:route) { should be_a(Hash) }

it "should save the response" do
subject.response.should == JSON.parse(response)
end

end

context 'parsing an error from the server' do

let(:error_response) { fixture('navteq/error_response.json') }

it 'should throw an RoutingFailed error' do
lambda{ described_class.new(error_response) }.should raise_error(Routing::Parser::RoutingFailed)
end

end

describe '#to_geo_points' do
Expand All @@ -48,9 +36,9 @@

describe 'length of the geopoint array' do

let(:leg_size) { subject.route["Leg"].size }
let(:leg_size) { json_response["Response"]["Route"].first["Leg"].size }
let(:leg_touching_point_size) { leg_size - 1 }
let(:maneuver_size) { subject.route["Leg"].inject(0) {|sum, leg| sum + leg["Maneuver"].size } }
let(:maneuver_size) { json_response["Response"]["Route"].first["Leg"].inject(0) { |sum, leg| sum + leg["Maneuver"].size } }

it 'has the length of all maneuvers minus the duplicate ones at the touching points' do
subject.to_geo_points.size.should == maneuver_size - leg_touching_point_size
Expand All @@ -65,14 +53,15 @@
end

describe '#parse_leg' do
let(:parsed_leg) { subject.parse_leg(json_response["Response"]["Route"].first["Leg"].first) }

it 'collects all maneuvers as geo points' do
parsed_leg.should be_an(Array)
parsed_leg.first.should be_a(::Routing::GeoPoint)
end

it 'leaves out the first maneuver' do
parsed_leg.size.should == subject.route["Leg"].first["Maneuver"].size - 1
parsed_leg.size.should == json_response["Response"]["Route"].first["Leg"].first["Maneuver"].size - 1
end

it 'marks only the first maneuver as waypoint' do
Expand Down Expand Up @@ -100,18 +89,6 @@
subject.parse_maneuver(maneuver_item, waypoint: true).waypoint.should be
end

it 'sets distance and increases the overall distance' do
old_distance = subject.overall_covered_distance
subject.parse_maneuver(maneuver_item)
subject.overall_covered_distance.should eql(old_distance + maneuver_item["Length"])
end

it 'sets time and increases the overall time' do
old_time = subject.overall_relative_time
subject.parse_maneuver(maneuver_item)
subject.overall_relative_time.should eql(old_time + maneuver_item["TravelTime"])
end

end

describe '#search_original_position' do
Expand Down

0 comments on commit c4224d5

Please sign in to comment.