diff --git a/lib/api.rb b/lib/api.rb index a8d499c..9d1ccf8 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -4,21 +4,25 @@ require_relative "./movie" class Api - APIKEY="4t6456xa33z8qhcqyuqgnkjh" + APIKEY="u2wh4hkgt7xkuqh6bhgm7f83" def self.search_by_title(title) url = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=#{APIKEY}&q=#{URI.encode(title)}&page_limit=1" struct = OpenStruct.new(get_url_as_json(url).fetch("movies").first) - Movie.new(id: struct.id.to_i, - title: struct.title, - year: struct.year, - score: struct.ratings["critics_score"] - ) + if !struct.id.nil? + Movie.new(id: struct.id.to_i, + title: struct.title, + year: struct.year, + score: struct.ratings["critics_score"] + ) + else + puts "No Movies returned" + end end def self.get_url_as_json(url) - JSON.parse(open(url).read) + JSON.parse(open(url, 'User-Agent' => 'Ruby').read) end end diff --git a/lib/movie.rb b/lib/movie.rb index 167a23e..bd7edd1 100644 --- a/lib/movie.rb +++ b/lib/movie.rb @@ -1,10 +1,13 @@ class Movie attr_reader :id, :title, :year, :score + attr_accessor :liked_at + def initialize(hash={}) @id = hash.fetch(:id) @title = hash.fetch(:title) @year = hash.fetch(:year) @score = hash.fetch(:score) + @liked_at = Time.now.year end end diff --git a/lib/user.rb b/lib/user.rb new file mode 100644 index 0000000..b15c8f3 --- /dev/null +++ b/lib/user.rb @@ -0,0 +1,67 @@ +class User + attr_reader :name, :searches + + def initialize(name) + @name = name + @searches = [] + end + + def add_to_searches(movie) + @searches << movie + end + + def rating + searches.delete_if { |m| m == nil } # since we are returning a string when no movie is found, I'm removing any nil values + movie_scores = searches.map { |movie| movie.score } + movie_scores.inject { |sum, el| sum + el } / searches.size + end + + def average_year + searches.delete_if { |m| m == nil } + movie_years = searches.map { |movie| movie.year } + movie_years.inject { |sum, el| sum + el } / searches.size + end + + def average_rating_per_year + years_and_scores = searches.map { |movie| { movie.liked_at.to_s => movie.score }} + merged = Hash.new(0) + years_and_scores.each do |h| + h.each do |y| + if merged[y[0]].is_a?(Array) + merged[y[0]] << y[1] + else + merged[y[0]] = [y[1]] + end + end + end + + output = {} + # Compute the average + merged.each do |m| + output[m[0]] = m[1].inject { |sum, el| sum + el } / m[1].length + end + output + end + + def calculate_slope + avg_ratings = average_rating_per_year + key_array = [] + avg_ratings.each_key { |key| key_array << key.to_i } + if key_array.size > 1 + first_year = key_array.min + last_year = key_array.max + (avg_ratings[last_year.to_s] - avg_ratings[first_year.to_s]) / (last_year - first_year) + else + "No slope" + end + end + + def picking_ability + if calculate_slope == "No slope" + "not yet determined." + else + calculate_slope > 0 ? "getting better." : "getting worse." + end + end +end + diff --git a/movie_json.rb b/movie_json.rb index d8a91d7..f9d4ae2 100644 --- a/movie_json.rb +++ b/movie_json.rb @@ -1,13 +1,35 @@ require_relative "lib/movie" require_relative "lib/api" +require_relative "lib/user" + +def start_movie_finder + puts "OH HAI. What's your name?" + @user = User.new(gets) +end def find_movie - puts "OH HAI. Search?" + puts "Add a movie you really like, #{@user.name}" movie_title = gets movie = Api.search_by_title(movie_title) - puts "Found: #{movie.title}. Score: #{movie.score}" + @user.add_to_searches(movie) + if !movie.nil? + puts "Found: #{movie.title}. Score: #{movie.score}" + end +end + +def show_movie_searches + puts "============================" + puts "Your overall average movie rating score is: #{@user.rating}" + puts "The average year for the movies you have liked is: #{@user.average_year}" + puts "============================" + @user.average_rating_per_year.each_pair { |k, v| puts "For #{k}, your average movie rating was #{v}!"} + puts "Your picking ability is #{@user.picking_ability}" + puts "============================" + puts "Your search history:" + @user.searches.each { |movie| puts movie.title } end +start_movie_finder find_movie while true do @@ -16,6 +38,7 @@ def find_movie if answer == "Y" find_movie else + show_movie_searches break end end diff --git a/spec/api_spec.rb b/spec/api_spec.rb index 9014106..4859ebe 100644 --- a/spec/api_spec.rb +++ b/spec/api_spec.rb @@ -13,15 +13,32 @@ movie.title.should eq("Forrest Gump") end - it "should return the score" do - movie.score.should eq(71) - end + context "when movie is found" do + + it "should return the score" do + movie.score.should eq(71) + end + + it "should return the id" do + movie.id.should eq(10036) + end - it "should return the id" do - movie.id.should eq(10036) + it "should return the year" do + movie.year.should eq(1994) + end end - it "should return the year" do - movie.year.should eq(1994) + context "when movie is not found" do + + before do + Api.stub(:get_url_as_json) { JSON.parse(File.read("spec/fixtures/no_movie.json")) } + end + + let(:no_movie_found) { Api.search_by_title("No movies exists") } + + it "doesn't raise an error" do + expect{:no_movie_found}.to_not raise_error(NoMethodError) + end end + end diff --git a/spec/fixtures/no_movie.json b/spec/fixtures/no_movie.json new file mode 100644 index 0000000..cc94537 --- /dev/null +++ b/spec/fixtures/no_movie.json @@ -0,0 +1 @@ +{"total":0,"movies":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies.json?q=top+tomatoes&page_limit=1&page=1"},"link_template":"http://api.rottentomatoes.com/api/public/v1.0/movies.json?q={search-term}&page_limit={results-per-page}&page={page-number}"} \ No newline at end of file diff --git a/spec/movie_spec.rb b/spec/movie_spec.rb index 088bd37..b12cc0a 100644 --- a/spec/movie_spec.rb +++ b/spec/movie_spec.rb @@ -3,10 +3,12 @@ it "should store the title, year, and score" do movie = Movie.new(id: "the-id", title: "the-title", year: 1998, score: 50) + movie.liked_at = 2012 movie.id.should eq("the-id") movie.title.should eq("the-title") movie.year.should eq(1998) movie.score.should eq(50) + movie.liked_at.should eq(2012) end end diff --git a/spec/user_spec.rb b/spec/user_spec.rb new file mode 100644 index 0000000..73293de --- /dev/null +++ b/spec/user_spec.rb @@ -0,0 +1,67 @@ +require_relative "../lib/user" +require_relative "../lib/movie" +describe User do + + let(:user) { User.new("Ralph") } + let(:movie) { Movie.new(id: "1", title: "First movie", year: 1985, score: 80) } + let(:second_movie) { Movie.new(id: "2", title: "Second movie", year: 2000, score: 60) } + let(:third_movie) { Movie.new(id: "3", title: "Third movie", year: 2000, score: 90) } + + + context "when user is initialized" do + + it "has a name" do + expect(user.name).to eq("Ralph") + end + + it "has an empty list of movie searches" do + expect(user.searches).to eq([]) + end + + it "can calculate the average rating per year" do + add_movies_to_searches(user) + average_ratings = user.average_rating_per_year + expect(average_ratings).to eq({"2012" => 70, "2010" => 90}) + end + + it "can calculate a total average movie rating score" do + add_movies_to_searches(user) + expect(user.rating).to eq 76 + end + + it "can calculate the average year of movies liked" do + add_movies_to_searches(user) + expect(user.average_year).to eq 1995 + end + + it "can calculate the slope of yearly average ratings" do + add_movies_to_searches(user) + expect(user.calculate_slope).to eq -10 + end + + it "can tell if user is getting worse at picking movies" do + add_movies_to_searches(user) + expect(user.picking_ability).to eq("getting worse.") + end + end + + context "when searching" do + + it "records a user's search" do + add_movies_to_searches(user) + expect(user.searches.first).to eq(movie) + end + + it "records multiple searches" do + add_movies_to_searches(user) + expect(user.searches).to eq([movie, second_movie, third_movie]) + end + end + + def add_movies_to_searches(user) + third_movie.liked_at = 2010 + user.add_to_searches(movie) + user.add_to_searches(second_movie) + user.add_to_searches(third_movie) + end +end