Created
March 22, 2013 01:11
-
-
Save moserrya/5218204 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative 'geocoder' | |
require 'shoulda-matchers' | |
require 'geocoder' | |
require 'debugger' | |
class ActivityCluster | |
MAX_ROUTE_LENGTH = 4 | |
MAX_DISTANCE = 20 | |
def initialize(destinations) | |
raise ArgumentError unless destinations.is_a?(Array) && destinations.any? | |
@destinations = destinations | |
# partition_destinations | |
# best_cluster_and_route | |
end | |
# def best_cluster_and_route | |
# @non_meal_dest.each do |dest| | |
# shortest_route(dest, @destinations) | |
# end | |
# return shortest_route | |
# end | |
# def shortest_route(starting_point) | |
# route = [starting_point] | |
# until route.length == MAX_ROUTE_LENGTH do | |
# next_destination = closest_location(route.last, destinations) | |
# route << destinations.slice!(destinations.index(next_destination)) | |
# end | |
# route | |
# end | |
def closest_location(location, destinations) | |
distances = destinations.map do |destination| | |
{location: destination, distance: self.distance_between(location, destination)} | |
end | |
distances.sort{|a, b| a[:distance] <=> b[:distance]}.first[:location] | |
end | |
def distance_between(location, destination) | |
Geocoder::Calculations.distance_between(location, destination) | |
end | |
# def partition_destinations | |
# @non_meal_dest, @meal_dest = @destinations.partition {|dest| dest.meal.zero? } | |
# end | |
end | |
class FakeLocation | |
attr_reader :meal | |
def initialize(latitude, longitude, meal) | |
@latitude = latitude | |
@longitude = longitude | |
@meal = meal | |
end | |
def to_coordinates | |
[@latitude, @longitude] | |
end | |
end | |
describe ActivityCluster do | |
before do | |
@los_angeles = FakeLocation.new 34.080185, -118.4692524, 0 | |
@san_francisco_m = FakeLocation.new 37.7935572, -122.4218255, 1 | |
@seattle_m = FakeLocation.new 47.6218387802915, -122.3482996197085, 1 | |
@vancouver = FakeLocation.new 49.2776215, -123.1061451, 0 | |
@austin = FakeLocation.new 30.2760276802915, -97.73898386970849, 0 | |
@boulder_m = FakeLocation.new 39.9128860000000, -105.6943651, 1 | |
end | |
let(:activity_cluster) { ActivityCluster.new [@los_angeles, | |
@san_francisco_m, | |
@seattle_m, | |
@vancouver, | |
@austin, | |
@boulder_m]} | |
context ".new" do | |
it 'requires an array of destinations' do | |
expect { | |
ActivityCluster.new | |
}.to raise_error(ArgumentError) | |
expect { | |
ActivityCluster.new(@los_angeles) | |
}.to raise_error(ArgumentError) | |
expect { | |
ActivityCluster.new(@los_angeles, @seattle_m) | |
}.to raise_error(ArgumentError) | |
expect { | |
ActivityCluster.new([]) | |
}.to raise_error(ArgumentError) | |
end | |
end | |
context "#closest_location" do | |
it "returns a location" do | |
activity_cluster.closest_location(@los_angeles, [@san_francisco_m, @seattle_m, @vancouver]). | |
should be_a(FakeLocation) | |
end | |
it "knows the nearest location" do | |
activity_cluster. | |
closest_location(@san_francisco_m, [@los_angeles, @seattle_m, @vancouver]). | |
should eq @los_angeles | |
end | |
end | |
context '#shortest_route' do | |
context 'returns ordered array' do | |
it 'returns an array of length 4 given at least 2 meal and 2 non-meal locations' do | |
activity_cluster.shortest_route(@los_angeles). | |
length.should eq 4 | |
end | |
it 'alternating meal, non-meal' do | |
activity_cluster.shortest_route(@los_angeles). | |
map { |destination| destination.meal }.should eq [0, 1, 0, 1] | |
end | |
it 'of locations ordered by shortest distance start to finish' do | |
activity_cluster.shortest_route(@los_angeles). | |
should eq [@los_angeles, @san_francisco_m, @vancouver, @seattle_m] | |
end | |
it 'does not include the starting point twice in the resulting array' do | |
shortest_route = activity_cluster.shortest_route(@los_angeles) | |
shortest_route.length.should eq(shortest_route.uniq.length) | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'shoulda-matchers' | |
require 'geocoder' | |
require 'debugger' | |
class InvalidAddressError < StandardError | |
end | |
class NoStreetError < StandardError | |
end | |
class Location | |
attr_reader :street, :city, :country, :zip_code, :state, :longitude, :latitude | |
def initialize(address) | |
@street = address[:street] | |
@city = address[:city] | |
@country = address[:country] | |
@zip_code = address[:zip_code] | |
@state = address[:state] | |
raise NoStreetError unless @street | |
geocode | |
end | |
private | |
def address_string | |
"#{street}, #{city}, #{state} #{zip_code} #{country}" | |
end | |
def geocode | |
api_details = Geocoder.search(address_string).first | |
raise InvalidAddressError if api_details.nil? | |
@latitude = api_details.data["geometry"]["location"]["lat"] | |
@longitude = api_details.data["geometry"]["location"]["lng"] | |
end | |
end | |
# describe Location do | |
# let(:address) { {:street => "717 California St.", | |
# :city => "San Francisco", | |
# :country => "USA", | |
# :zip_code => "94108", | |
# :state => "CA"} } | |
# let(:location) { Location.new(address) } | |
# context '.new' do | |
# it { location.should be_a(Location) } | |
# it { location.should respond_to(:street) } | |
# it { location.should respond_to(:city) } | |
# it { location.should respond_to(:country) } | |
# it { location.should respond_to(:zip_code) } | |
# it { location.should respond_to(:state) } | |
# it { location.should respond_to(:longitude) } | |
# it { location.should respond_to(:latitude) } | |
# context 'arguments' do | |
# it 'accepts one argument hash' do | |
# expect { | |
# Location.new | |
# }.to raise_error(ArgumentError) | |
# end | |
# let(:invalid_address) { { :city => "San Francisco", | |
# :country => "USA", | |
# :zip_code => "94108", | |
# :state => "CA"} } | |
# it 'must have a street' do | |
# expect { | |
# Location.new(invalid_address) | |
# }.to raise_error(NoStreetError) | |
# end | |
# end | |
# context 'invalid address' do | |
# let(:address) { {:street => ""}} | |
# it "raises an invalid addres error" do | |
# expect { | |
# Location.new(address) | |
# }.to raise_error(InvalidAddressError) | |
# end | |
# end | |
# context 'longitude and latitude should be calculated' do | |
# it { location.longitude.should_not be_nil } | |
# it { location.latitude.should_not be_nil } | |
# end | |
# end | |
# end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment