diff --git a/Gemfile b/Gemfile index 276e671..4359af1 100644 --- a/Gemfile +++ b/Gemfile @@ -3,4 +3,5 @@ source 'https://rubygems.org' gem 'rake' gem 'rspec' gem 'activesupport' -gem 'geocoder' +gem "geocoder" +gem 'nokogiri' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 28827b4..9d419d7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,9 +5,11 @@ GEM i18n (~> 0.6) multi_json (~> 1.0) diff-lcs (1.1.3) - geocoder (1.1.1) + geocoder (1.1.6) i18n (0.6.0) multi_json (1.3.4) + nokogiri (1.5.9) + nokogiri (1.5.9-x86-mingw32) rake (0.9.2.2) rspec (2.10.0) rspec-core (~> 2.10.0) @@ -20,9 +22,11 @@ GEM PLATFORMS ruby + x86-mingw32 DEPENDENCIES activesupport geocoder + nokogiri rake rspec diff --git a/lib/calculates_route.rb b/lib/calculates_route.rb index 4488393..0c37655 100644 --- a/lib/calculates_route.rb +++ b/lib/calculates_route.rb @@ -1,22 +1,29 @@ class CalculatesRoute - def self.calculate(points) + attr_reader :total_distance + def self.calculate(points, start_point) + @total_distance = 0 remaining_points = points route = [] - route << remaining_points.slice!(0) + index = remaining_points.index(start_point) + if index.nil? + route << remaining_points.slice!(0) + else + route << remaining_points.slice!(index) + end until remaining_points == [] do next_point = shortest_distance(route.last, remaining_points) - route << remaining_points.slice!(remaining_points.index(next_point)) + route << remaining_points.slice!(remaining_points.index(next_point.fetch(:point))) + @total_distance += next_point.fetch(:distance) end - route + vals = {route: route, distance: @total_distance} end def self.shortest_distance(from, possible) distances = possible.map do |point| {point: point, distance: Map.distance_between(from, point)} end - distances.sort{|a,b| a.fetch(:distance) <=> b.fetch(:distance)}.first.fetch(:point) + point = distances.sort{|a,b| a.fetch(:distance) <=> b.fetch(:distance)}.first end end - diff --git a/lib/map.rb b/lib/map.rb index e9abfde..994c189 100644 --- a/lib/map.rb +++ b/lib/map.rb @@ -1,4 +1,11 @@ require 'geocoder' + +Geocoder.configure( + lookup: :bing, + api_key: 'AkTjVpt-Si67rkjRTerrBqnmMIJSwWAEXSsoMJQMHa3ZO1rbHbECo1crQ_iuGTg-', + timeout: 10 +) + class Map def self.search(terms) diff --git a/lib/sales_person.rb b/lib/sales_person.rb index d0c2890..128d99c 100644 --- a/lib/sales_person.rb +++ b/lib/sales_person.rb @@ -9,7 +9,19 @@ def schedule_city(city) @cities << city unless @cities.include?(city) end - def route - CalculatesRoute.calculate(cities) + def find_city(city_name) + found = cities.select {|city| city if city.name == city_name} + found.first end + + def route(start) + city = find_city(start) + vals = CalculatesRoute.calculate(cities, city) + results = {route: vals.fetch(:route), time: traveling_time(vals.fetch(:distance)) } + end + + def traveling_time(distance) + time = distance / 55 + end + end diff --git a/salesperson.rb b/salesperson.rb index 9cafbd7..8b19fd3 100644 --- a/salesperson.rb +++ b/salesperson.rb @@ -1,10 +1,58 @@ Dir["./lib/*.rb"].each {|file| require file } - +require "benchmark" +require 'nokogiri' +require 'open-uri' phil = SalesPerson.new -phil.schedule_city(Place.build("Dallas, TX")) -phil.schedule_city(Place.build("El Paso, TX")) -phil.schedule_city(Place.build("Austin, TX")) -phil.schedule_city(Place.build("Lubbock, TX")) +# these locations work with google, but not bing +#phil.schedule_city(Place.build("Target, Smyrna, GA")) +#phil.schedule_city(Place.build("IKEA, Atlanta, GA")) +#phil.schedule_city(Place.build("Petco, Kennesaw, GA")) +#phil.schedule_city(Place.build("Hobby Town USA, Kennesaw, GA")) +#phil.schedule_city(Place.build("Publix Delk Rd, Marietta, GA")) +phil.schedule_city(Place.build("Marietta, GA")) +phil.schedule_city(Place.build("Sandy Springs, GA")) +phil.schedule_city(Place.build("Roswell, GA")) +phil.schedule_city(Place.build("Buford, GA")) +phil.schedule_city(Place.build("Smyrna, GA")) + +puts "All places:" +puts phil.cities +puts +puts "Where should the person start?" +puts +start = gets.chomp +if (start.empty? == false) + vals = phil.route(start) + puts "The route starting at #{start}:\n" + puts vals.fetch(:route) + travel = vals.fetch(:time) + puts "Total traveling time in hours: #{vals.fetch(:time).round(2)}" + +end + +texas_cities = [] +doc = Nokogiri::HTML(open('http://www.texas.gov/en/discover/Pages/topic.aspx?topicid=/government/localgov')) +doc.css(".TGOV_SCRD_Header a").map do |node| + texas_cities << node.content +end + +bench_vals = [2, 10, 50, 200] +bench_vals.each do |val| + current = SalesPerson.new + texas_cities.shuffle.take(val).each do |city| + current.schedule_city(Place.build(city)) + end -puts phil.route + the_route = [] + puts "\nBenchmarking results for #{val} cities:" + Benchmark.bm do |x| + x.report do + vals = current.route(nil) + end + puts "The route:" + puts vals.fetch(:route) + travel = vals.fetch(:time) + puts "Total traveling time in hours: #{vals.fetch(:time).round(2)}" + end +end \ No newline at end of file diff --git a/spec/calculates_route_spec.rb b/spec/calculates_route_spec.rb index 47679d6..a1d284a 100644 --- a/spec/calculates_route_spec.rb +++ b/spec/calculates_route_spec.rb @@ -10,6 +10,12 @@ it "should calculate the route" do points = [dallas, el_paso, austin, lubbock] expected = [dallas, austin, lubbock, el_paso] - CalculatesRoute.calculate(points).should eq(expected) + CalculatesRoute.calculate(points, "dallas").fetch(:route).should eq(expected) + end + + it "should log the total miles" do + points = [dallas, el_paso, austin, lubbock] + vals = CalculatesRoute.calculate(points, "Austin, TX") + vals.fetch(:distance).should_not be(0) end end diff --git a/spec/sales_person_spec.rb b/spec/sales_person_spec.rb index 08a6ce9..c6b1d90 100644 --- a/spec/sales_person_spec.rb +++ b/spec/sales_person_spec.rb @@ -16,15 +16,28 @@ }.to change(subject.cities,:count).by(1) end + it "should find a city using a name entered by the user" do + city = stub + city.stub(name:"Atlanta, GA") + subject.schedule_city(city) + subject.find_city("Atlanta, GA").should eq(city) + end + it "should calculate a route via the CalculatesRoute" do - cities = [stub, stub, stub] + start = stub(name: "Atlanta, GA") + last = stub(name: "Marietta, GA") + cities = [start, last] subject.stub(:cities) { cities } - CalculatesRoute.should_receive(:calculate).with(cities) - subject.route + CalculatesRoute.should_receive(:calculate).with(cities, start) + subject.route("Atlanta, GA") end - it "should returns the route from CalculatesRoute" do - route_stub = [stub, stub] + + it "should return the route from CalculatesRoute" do + route_stub = [stub("Marietta, GA"), stub("Atlanta, GA")] + start = stub("Marietta, GA") CalculatesRoute.stub(:calculate) { route_stub } - subject.route.should eq(route_stub) + CalculatesRoute.stub(:route).and_return(route_stub) + subject.route(start).should eq(route_stub) end + end