From c8b3b99446f0aaf596353fb11a87d1e6bed553c4 Mon Sep 17 00:00:00 2001 From: Laura Rokita Date: Thu, 24 Jul 2014 16:28:21 -0500 Subject: [PATCH] refactor tests and all_paths.rb --- lib/all_paths.rb | 208 +++++++++++---------------- lib/best_flights.rb | 18 +-- lib/flight_parser.rb | 11 +- spec/all_paths_spec.rb | 18 ++- spec/best_flights_spec.rb | 2 +- spec/flight_formatter_spec.rb | 15 +- spec/flight_parser_spec.rb | 16 ++- spec/flight_route_calculator_spec.rb | 14 +- spec/runner_spec.rb | 11 +- start.rb | 2 +- 10 files changed, 157 insertions(+), 158 deletions(-) diff --git a/lib/all_paths.rb b/lib/all_paths.rb index 14eb44c..f9e132c 100644 --- a/lib/all_paths.rb +++ b/lib/all_paths.rb @@ -1,135 +1,93 @@ require 'ostruct' class AllPaths - - def initialize(flights, departure_city, arrival_city) - @flights = flights - @departure_city = departure_city - @arrival_city = arrival_city - @final_paths = [] - end - - def create_paths - from_city_groups = group_flights_by_from_city - from_city_groups[@departure_city.to_sym].each do |flight_from_dep_city| - if flight_from_dep_city.to == @arrival_city - @final_paths << flight_from_dep_city - else - @current_path = create_new_path(flight_from_dep_city) - reset_price(flight_from_dep_city) - reset_arrivals(flight_from_dep_city) - reset_arrival_cities(flight_from_dep_city) - update_current_path(flight_from_dep_city.to, from_city_groups) - end + def initialize(flights, departure_city, arrival_city) + @flights = flights + @departure_city = departure_city + @arrival_city = arrival_city + @final_paths = [] + end + + def create_paths + @departure_city_groups = group_flights_by_departure_city + @departure_city_groups[@departure_city.to_sym].each do |flight_from_dep_city| + if flight_from_dep_city.to == @arrival_city + @final_paths << flight_from_dep_city + else + @current_path = create_new_path(flight_from_dep_city) + @path_attributes = reset_path_attributes(flight_from_dep_city) + update_current_path end - @final_paths end - - def group_flights_by_from_city - from_city_groups = {} - @flights.each do |flight| - new_from = flight.from.to_sym - from_city_groups[new_from] = [] if from_city_groups[new_from].nil? - from_city_groups[new_from] << flight + @final_paths + end + + def group_flights_by_departure_city + departure_city_groups = {} + @flights.each do |flight| + new_from = flight.from.to_sym + departure_city_groups[new_from] ||= [] + departure_city_groups[new_from] << flight + end + departure_city_groups + end + + def create_new_path(flight) + OpenStruct.new(:from => @departure_city, :to => nil, :dep => flight.dep, :arr => nil, :price => nil) + end + + def reset_path_attributes(flight) + path_attributes = {} + path_attributes[:prices], path_attributes[:arrival_times], path_attributes[:arrival_cities] = [], [], [] + path_attributes[:prices] << flight.price + path_attributes[:arrival_times] << flight.arr + path_attributes[:arrival_cities] << flight.to + path_attributes + end + + def update_current_path(new_path_level = false) + new_dep_city = @path_attributes[:arrival_cities].last.to_sym + @departure_city_groups[new_dep_city].each do |possible_flight| + if new_path_level == false + remove_attributes_from_last_flight if @path_attributes[:arrival_cities].size > 1 end - from_city_groups - end - - private - - def create_new_path(flight) - OpenStruct.new(:from => @departure_city, :to => nil, :dep => flight.dep, :arr => nil, :price => nil) - end - - def reset_price(flight) - @prices = [] - @prices << flight.price - end - - def reset_arrivals(flight) - @arrival_times = [] - @arrival_times << flight.arr - end - - def reset_arrival_cities(flight) - @arrival_cities = [] - @arrival_cities << flight.to - end - - def update_current_path(current_from_city, from_city_groups, loop = false) - new_from_city = current_from_city.to_sym - from_city_groups[new_from_city].each do |possible_flight| - if loop == false - reset_to_price_from_city if @prices.size > 1 - reset_arrivals_from_city if @arrival_times.size > 1 - reset_arrival_cities_from_city if @arrival_cities.size > 1 - end - if valid_next_flight?(possible_flight) - #update_path(possible_flight) - update_price(possible_flight) - update_arrivals(possible_flight) - update_arrival_cities(possible_flight) - if possible_flight.to == @arrival_city - add_prices_to_path - add_arrivals_to_path(possible_flight) - add_arrival_cities_to_path(possible_flight) - reset_to_price_from_city - reset_arrivals_from_city - reset_arrival_cities_from_city - add_current_path_to_final_paths(possible_flight) - next - end - update_current_path(@arrival_cities.last, from_city_groups, true) + if valid_next_flight?(possible_flight) + update_path_attributes(possible_flight) + if possible_flight.to == @arrival_city + add_attributes_to_path + add_current_path_to_final_paths + remove_attributes_from_last_flight + next end + update_current_path(true) end - end - - def valid_next_flight?(possible_flight) - @arrival_times.last < possible_flight.dep && possible_flight.to > possible_flight.from - end - - def update_path(possible_flight) - @current_path.to = possible_flight.to if possible_flight.to != @arrival_city - end - - def update_price(possible_flight) - @prices << possible_flight.price - end - - def update_arrivals(possible_flight) - @arrival_times << possible_flight.arr - end - - def update_arrival_cities(possible_flight) - @arrival_cities << possible_flight.to - end - - def add_prices_to_path - @current_path.price = @prices.reduce(:+) - end - - def add_arrivals_to_path(possible_flight) - @current_path.arr = @arrival_times.last - end - - def add_arrival_cities_to_path(possible_flight) - @current_path.to = @arrival_cities.last - end - - def reset_to_price_from_city - @prices.pop - end - - def reset_arrivals_from_city - @arrival_times.pop - end - - def reset_arrival_cities_from_city - @arrival_cities.pop - end - - def add_current_path_to_final_paths(possible_flight) - end_path = @current_path.dup - @final_paths << end_path end + end + + def valid_next_flight?(possible_flight) + @path_attributes[:arrival_times].last < possible_flight.dep && possible_flight.to > possible_flight.from + end + + def update_path_attributes(possible_flight) + @path_attributes[:prices] << possible_flight.price + @path_attributes[:arrival_times] << possible_flight.arr + @path_attributes[:arrival_cities] << possible_flight.to + end + + def add_attributes_to_path + @current_path.price = @path_attributes[:prices].reduce(:+) + @current_path.arr = @path_attributes[:arrival_times].last + @current_path.to = @path_attributes[:arrival_cities].last + end + + def remove_attributes_from_last_flight + @path_attributes[:prices].pop + @path_attributes[:arrival_times].pop + @path_attributes[:arrival_cities].pop + end + + def add_current_path_to_final_paths + end_path = @current_path.dup + @final_paths << end_path + end end \ No newline at end of file diff --git a/lib/best_flights.rb b/lib/best_flights.rb index 58585dc..3abf572 100644 --- a/lib/best_flights.rb +++ b/lib/best_flights.rb @@ -1,12 +1,12 @@ class BestFlights class << self def get_cheapest_flight(all_flight_paths) - @lowest_price = nil + lowest_price = nil all_flight_paths.each do |flight| - if @lowest_price.nil? || flight.price < @lowest_price + if lowest_price.nil? || flight.price < lowest_price @best_flight = flight - @lowest_price = flight.price - elsif @lowest_price == flight.price + lowest_price = flight.price + elsif lowest_price == flight.price @best_flight = get_fastest_flight([@best_flight, flight]) end end @@ -14,13 +14,13 @@ def get_cheapest_flight(all_flight_paths) end def get_fastest_flight(all_flight_paths) - @shortest_length = nil + shortest_length = nil all_flight_paths.each do |flight| - @length = flight.arr - flight.dep - if @shortest_length.nil? || @length < @shortest_length + length = flight.arr - flight.dep + if shortest_length.nil? || length < shortest_length @best_flight = flight - @shortest_length = @length - elsif @shortest_length == @length + shortest_length = length + elsif shortest_length == length @best_flight = get_cheapest_flight([@best_flight, flight]) end end diff --git a/lib/flight_parser.rb b/lib/flight_parser.rb index 27962d0..69ac682 100644 --- a/lib/flight_parser.rb +++ b/lib/flight_parser.rb @@ -3,8 +3,7 @@ class FlightParser class << self def parse(txt_file) - @all_flights = [] - @all_cases = [] + all_cases = [] flights_created = 0 file = File.open(txt_file).read @@ -19,10 +18,10 @@ def parse(txt_file) from, to, dep, arr, price = line.strip.split(" ") @new_case << create_flight(from, to, dep, arr, price) flights_created += 1 - @all_cases << @new_case if flights_created == @number_of_flights + all_cases << @new_case if flights_created == @number_of_flights end end - @all_cases + all_cases end def create_flight(from, to, dep, arr, price) @@ -38,9 +37,7 @@ def create_flight(from, to, dep, arr, price) def to_number(time) hour, minutes = time.split(":") hour.to_i * 60 + minutes.to_i - end - - private + end def empty_line?(line, index) index < 2 || line == "\n" diff --git a/spec/all_paths_spec.rb b/spec/all_paths_spec.rb index a09dfb9..854aa4f 100644 --- a/spec/all_paths_spec.rb +++ b/spec/all_paths_spec.rb @@ -20,6 +20,7 @@ let(:departure_city){"A"} let(:arrival_city){"Z"} + let(:all_paths){AllPaths.new([flight_one, flight_five], departure_city, arrival_city)} it "gets the correct paths for just two flights" do all_flights = [flight_one, flight_five] @@ -55,8 +56,23 @@ all_flights = [flight_one, flight_two, flight_three, flight_four, flight_five, flight_six, flight_seven, flight_eight] all_paths_class = AllPaths.new(all_flights, departure_city, arrival_city) - all_froms = all_paths_class.group_flights_by_from_city + all_froms = all_paths_class.group_flights_by_departure_city expect(all_froms[:A]).to eq([flight_one, flight_two, flight_three]) end + + it "creates a new path" do + path = all_paths.create_new_path(flight_one) + + expect(path.from).to eq(flight_one.from) + expect(path.to).to eq(nil) + expect(path.dep).to eq(flight_one.dep) + expect(path.arr).to eq(nil) + expect(path.price).to eq(nil) + end + + it "resets path attributes" do + path_attributes = all_paths.reset_path_attributes(flight_one) + expect(path_attributes).to eq({:prices =>[50],:arrival_times => [540],:arrival_cities => ["B"]}) + end end \ No newline at end of file diff --git a/spec/best_flights_spec.rb b/spec/best_flights_spec.rb index ac0e401..5cdeb4a 100644 --- a/spec/best_flights_spec.rb +++ b/spec/best_flights_spec.rb @@ -6,7 +6,7 @@ let(:flight_three){OpenStruct.new(:from => "A", :to => "Z", :dep => 600, :arr => 720, :price => 300.00)} let(:case_one){[flight_one, flight_two, flight_three]} - it "gets the cheapest flight" do + it "gets the cheapest flight if they're equally cheap" do best_flight = BestFlights.get_cheapest_flight(case_one) expect(best_flight).to eq(flight_one) end diff --git a/spec/flight_formatter_spec.rb b/spec/flight_formatter_spec.rb index f530ac0..8a78178 100644 --- a/spec/flight_formatter_spec.rb +++ b/spec/flight_formatter_spec.rb @@ -1,11 +1,20 @@ require 'flight_formatter' describe "Flight formatter" do - let(:flight_one){OpenStruct.new(:from => "A", :to => "B", :dep => 540, :arr => 600, :price => 100.00)} - let(:flight_two){OpenStruct.new(:from => "B", :to => "Z", :dep => 690, :arr => 810, :price => 100.00)} - it "creates the correct flight format" do + flight_one = OpenStruct.new(:from => "A", :to => "B", :dep => 540, :arr => 600, :price => 100.00) + flight_two = OpenStruct.new(:from => "B", :to => "Z", :dep => 690, :arr => 810, :price => 100.00) + line = FlightFormatter.get_print_format([flight_one, flight_two]) + expect(line).to include("9:00 10:00 100.00\n") end + + it "formats the correct time" do + expect(FlightFormatter.format_time(550)).to eq("09:10") + end + + it "formats the correct price" do + expect(FlightFormatter.format_price(375.2)).to eq("375.20") + end end \ No newline at end of file diff --git a/spec/flight_parser_spec.rb b/spec/flight_parser_spec.rb index 3e92573..84062c4 100644 --- a/spec/flight_parser_spec.rb +++ b/spec/flight_parser_spec.rb @@ -1,16 +1,16 @@ require 'flight_parser' describe "Flight parser" do - let(:file){"sample-input.txt"} - it "parses flights" do - cases = FlightParser.parse(file) + cases = FlightParser.parse("sample-input.txt") + expect(cases.size).to eq(2) expect(cases[0].size).to eq(3) end it "creates a flight object" do new_flight = FlightParser.create_flight("A", "Z", "9:00", "10:00", "100.00") + expect(new_flight.from).to eq("A") expect(new_flight.to).to eq("Z") expect(new_flight.dep).to eq(540) @@ -21,4 +21,14 @@ number = FlightParser.to_number("9:15") expect(number).to eq(555) end + + it "checks for empty lines" do + result = FlightParser.empty_line?("\n", 3) + expect(result).to eq(true) + end + + it "checks for the case number" do + result = FlightParser.number_of_cases?("5") + expect(result).to eq(true) + end end \ No newline at end of file diff --git a/spec/flight_route_calculator_spec.rb b/spec/flight_route_calculator_spec.rb index 298ac3b..825d1a1 100644 --- a/spec/flight_route_calculator_spec.rb +++ b/spec/flight_route_calculator_spec.rb @@ -1,21 +1,23 @@ require 'flight_route_calculator' describe "Flight route calc" do - let(:file){"sample-input.txt"} let(:flight_one){OpenStruct.new(:from => "A", :to => "B", :dep => 540, :arr => 600, :price => 100.00)} let(:flight_two){OpenStruct.new(:from => "B", :to => "Z", :dep => 690, :arr => 810, :price => 100.00)} let(:flight_three){OpenStruct.new(:from => "A", :to => "Z", :dep => 600, :arr => 720, :price => 300.00)} let(:case_one){[flight_one, flight_two, flight_three]} - let(:departure_city){"A"} - let(:arrival_city){"Z"} it "parses text file into cases" do - cases = FlightRouteCalculator.get_cases(file) - expect(cases.size).to eq(2) + cases = FlightRouteCalculator.get_cases("input.txt") + expect(cases.size).to eq(3) end it "finds the best flights for each case" do - expect(FlightRouteCalculator).to respond_to(:find_all_flight_paths) + departure_city = "A" + arrival_city = "Z" + + all_paths = FlightRouteCalculator.find_all_flight_paths(case_one, departure_city, arrival_city) + + expect(all_paths.size).to eq(2) end it "finds the cheapest flight" do diff --git a/spec/runner_spec.rb b/spec/runner_spec.rb index 0ffba4c..0df5897 100644 --- a/spec/runner_spec.rb +++ b/spec/runner_spec.rb @@ -6,6 +6,10 @@ let(:arrival_city) {"Z"} it "gets the cases from the flight parser" do + file = "sample-input.txt" + departure_city = "A" + arrival_city = "Z" + expect(File).to receive(:open) expect(FlightRouteCalculator).to receive(:get_cases) {[1, 1]} expect(FlightRouteCalculator).to receive(:find_all_flight_paths).twice @@ -13,14 +17,17 @@ expect(FlightRouteCalculator).to receive(:get_fastest_flight).twice expect(FlightRouteCalculator).to receive(:get_print_format).twice expect(Runner).to receive(:write_to_file).twice + Runner.run_flight_route_calculator(file, departure_city, arrival_city) end it "writes to a file" do temp_output = StringIO.new - Runner.write_to_file("testing stuff", temp_output) + + Runner.write_to_file("testing", temp_output) + temp_output.each_line do |line| - expect(line).to eq("tesing stuff") + expect(temp_output.read).to eq("tesing") end end end \ No newline at end of file diff --git a/start.rb b/start.rb index 8b7f275..dd7abf0 100644 --- a/start.rb +++ b/start.rb @@ -1,6 +1,6 @@ require_relative 'lib/runner.rb' -flights_to_parse = "sample-input.txt" +flights_to_parse = "input.txt" departure_city = "A" arrival_city = "Z"