rotten 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rotten (0.2.0)
4
+ rotten (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/README.md CHANGED
@@ -10,17 +10,35 @@
10
10
  movie.reviews
11
11
  movie.cast
12
12
 
13
- # list upcoming movies
13
+ # List upcoming movies
14
14
  Rotten::Movie.upcoming
15
15
 
16
- # list movies opening this week
16
+ # List movies in theatres now
17
+ Rotten::Movie.in_theatres
18
+
19
+ # List movies opening this week
17
20
  Rotten::Movie.opening
18
21
 
22
+ # List movies coming to dvd this week
23
+ Rotten::Movie.dvd_release
24
+
25
+ # Use a file cache (baked in)
26
+ Rotten::Movie.enable_cache!
27
+ Rotten::Movie.search "What about bob?" # Hits API
28
+ Rotten::Movie.search "What about bob?" # Hits on-disk cache
29
+
30
+ # Custom cache. Should respond to #read & #write. Recommended over included cache.
31
+ Rotten::Movie.cache= ActiveSupport::Cache::MemoryStore.new
32
+ Rotten::Movie.search "Blue Velvet" # Hits API
33
+ Rotten::Movie.search "Blue Velvet" # Hits MemoryStore
34
+
35
+
19
36
  ### Features
20
37
  - Movie search
21
38
  - Movies opening this week
22
39
  - Movies upcoming
23
40
  - Movie reviews
41
+ - Caching
24
42
 
25
43
  #### TODO
26
44
  - Implement all APIs
@@ -8,6 +8,7 @@ module Rotten
8
8
  autoload :Cast, "rotten/cast"
9
9
  autoload :Review, "rotten/review"
10
10
  autoload :Movie, "rotten/movie"
11
+ autoload :Cache, "rotten/cache"
11
12
 
12
13
  def api_key=(val)
13
14
  @api_key = val
@@ -23,16 +23,60 @@ module Rotten
23
23
  '1.0'
24
24
  end
25
25
 
26
+ def use_cache?
27
+ @use_cache == true
28
+ end
29
+
30
+ def enable_cache!
31
+ @use_cache = true
32
+ end
33
+
34
+ def disable_cache!
35
+ @use_cache = false
36
+ end
37
+
38
+ def cache
39
+ @cache ||= Cache.new
40
+ @cache.store
41
+ end
42
+
43
+ # Use your own cache, such as ActiveSupport::Cache::MemoryStore
44
+ def cache=(_cache)
45
+ enable_cache!
46
+ @cache = Cache.new :store => _cache
47
+ end
48
+
49
+ def get_from_cache url
50
+ if use_cache?
51
+ cache.read(url)
52
+ end
53
+ end
54
+
55
+ def write_to_cache url, data
56
+ cache.write(url, data) if use_cache?
57
+ end
58
+
26
59
  def get path, options={}
27
60
  if Rotten.api_key.nil?
28
61
  raise UndefinedApiKeyError, "Please define your API key with Rotten.api_key=(your_key)"
29
62
  end
30
63
 
31
- url = url_for(path, options)
64
+ url = url_for(path, options)
65
+ cached = get_from_cache(url)
66
+ if cached
67
+ puts "Using cache.."
68
+ if block_given?
69
+ return yield(cached)
70
+ else
71
+ return cached
72
+ end
73
+ end
74
+
32
75
  open( url ) do |response|
33
76
  data = JSON.parse(response.read)
77
+ write_to_cache url, data
34
78
  if block_given?
35
- yield data
79
+ yield(data)
36
80
  else
37
81
  data
38
82
  end
@@ -0,0 +1,25 @@
1
+ # Capture JSON responses and re-use them
2
+ # Works with any cache store that accepts the "read" and "write" methods
3
+ # TODO method_missing should hit the @store
4
+
5
+ module Rotten
6
+ autoload :SimpleCache, "rotten/simple_cache.rb"
7
+
8
+ class Cache
9
+
10
+ attr_reader :store
11
+ def initialize options={}
12
+ @store = options.delete(:store) || SimpleCache.new(options)
13
+ end
14
+
15
+ def read key
16
+ @store.read key
17
+ end
18
+ alias_method :get, :read
19
+
20
+ def write key, value
21
+ @store.write key, value
22
+ end
23
+ alias_method :set, :write
24
+ end
25
+ end
@@ -17,8 +17,6 @@ module Rotten
17
17
  @characters[index]
18
18
  end
19
19
 
20
- def first; at[0]; end
21
-
22
20
  def process array
23
21
  array.each do |hash|
24
22
  actor = @actors.detect{|a| a.name == hash["name"] } || a=Actor.new; a.attributes=hash
@@ -0,0 +1,18 @@
1
+ module Rotten
2
+ require "ostruct"
3
+ class Entity < OpenStruct
4
+ class << self
5
+ def from_json(json)
6
+ e = new
7
+ e.attributes = json
8
+ e
9
+ end
10
+ end
11
+
12
+ def attributes= hash={}
13
+ hash.each_pair do |k,v|
14
+ instance_variable_get("@table")[k.to_sym] = v
15
+ end
16
+ end
17
+ end
18
+ end
@@ -12,6 +12,15 @@ module Rotten
12
12
  fetch "lists/movies/upcoming", options
13
13
  end
14
14
 
15
+ def dvd_releases options={}
16
+ fetch "lists/dvds/new_releases", options
17
+ end
18
+
19
+ def in_theaters options={}
20
+ fetch "lists/movies/in_theaters", options
21
+ end
22
+ alias_method :in_theatres, :in_theaters
23
+
15
24
  def search phrase, options={}
16
25
  options.delete :q
17
26
  options[:q] = phrase
@@ -23,7 +32,7 @@ module Rotten
23
32
  if json.is_a?(Array)
24
33
  json.map{|m| extract_movie_info(m) }
25
34
  else
26
- return Movie.new(json)
35
+ Movie.new(json)
27
36
  end
28
37
  end
29
38
 
@@ -0,0 +1,4 @@
1
+ module Rotten
2
+ class Review < Entity
3
+ end
4
+ end
@@ -0,0 +1,30 @@
1
+ module Rotten
2
+ class SimpleCache
3
+ attr_reader :cache_file
4
+ def initialize options={}
5
+ require "yaml"
6
+ if options[:cache_path] && File.exists?(options[:cache_path])
7
+ @cache_file = options[:cache_path]
8
+ @data = YAML.load_file @cache_file || {}
9
+ else
10
+ require "tempfile"
11
+ @cache_file = Tempfile.new "__rotten"
12
+ @data = YAML.load_file(@cache_file) || {}
13
+ end
14
+ end
15
+
16
+ def read key
17
+ @data[key.to_s]
18
+ end
19
+
20
+ def write key, value
21
+ @data[key.to_s] = value
22
+ save_to_disk
23
+ end
24
+
25
+ private
26
+ def save_to_disk
27
+ File.open(@cache_file, "w"){|f| f.puts(YAML.dump(@data)) }
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module Rotten
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+
3
+ describe Rotten::Cache do
4
+ context ".new" do
5
+ context "when :store is not given" do
6
+ it "should set the store to SimpleCache" do
7
+ Rotten::Cache.new.store.class.should == Rotten::SimpleCache
8
+ end
9
+ end
10
+ end
11
+
12
+ context "#read" do
13
+ before :each do
14
+ @cache = Rotten::SimpleCache.new
15
+ @cache.write :name, "bob"
16
+ end
17
+
18
+ context "given a key" do
19
+ it "should read the key from the cache" do
20
+ @cache.read(:name).should == "bob"
21
+ YAML.load(@cache.cache_file).should == {"name" => "bob"}
22
+ end
23
+ end
24
+ end
25
+
26
+ context "#write" do
27
+ before :each do
28
+ @cache = Rotten::SimpleCache.new
29
+ @cache.write :name, "hank"
30
+ end
31
+ context "given a key/value" do
32
+ it "should write the data to the cache" do
33
+ YAML.load(@cache.cache_file).should == {"name" => "hank"}
34
+ end
35
+ end
36
+ end
37
+
38
+ context "hooked into Rotten::Movie" do
39
+ before :each do
40
+ Rotten::Movie.enable_cache!
41
+ simulate "movies/search", "search.json", :q => "There Will Be Blood"
42
+ #TODO figure out how open uri uses Net::HTTP for better tests
43
+ Net::HTTP.stub(:open){ raise }
44
+ Net::HTTP.stub(:start){ raise }
45
+ Net::HTTP.stub(:get){ raise }
46
+ end
47
+
48
+ it "should fetch from the cache" do
49
+ Rotten::Movie.search("There Will Be Blood").should be_an_instance_of(Array)
50
+ json = JSON.parse(File.read( File.join(fixture_path, "search.json") ) )
51
+ YAML.load(Rotten::Movie.cache.cache_file)["http://api.rottentomatoes.com/api/public/v1.0/movies/search.json?apikey=1234567890&q=There%20Will%20Be%20Blood"]["movies"].should == json["movies"]
52
+ end
53
+ end
54
+ end
@@ -0,0 +1 @@
1
+ {"total":41,"reviews":[{"critic":"Bob Mondello","date":"2008-10-18","publication":"NPR.org","quote":"This sometimes magnificent, decidedly strange film is a portrait of a terrible, rapacious man.","links":{"review":"http://www.npr.org/templates/story/story.php?storyId=17628099"}},{"critic":"Richard Schickel","date":"2008-10-18","publication":"TIME Magazine","quote":"One of the most wholly original American movies ever made.","links":{"review":"http://www.time.com/time/arts/article/0,8599,1698168,00.html"}},{"critic":"Christopher Orr","date":"2008-09-18","publication":"New Republic","quote":"There Will Be Blood establishes itself as a film of Darwinian ferocity, a stark and pitiless parable of American capitalism.","links":{"review":"http://www.tnr.com/booksarts/story.html?id=ba49de78-d44a-4963-9d96-65ef4fef9e21"}},{"critic":"Jonathan F. Richards","date":"2008-02-05","publication":"Film.com","quote":"Daniel Day-Lewis bestrides the narrow world like a colossus as Daniel Plainview, a turn-of-the-last-century prospector for gold and silver who stumbles upon oil in rural California and goes after it with the ferocity, focus, and ethical sensitivity of a f","links":{"review":"http://www.filmfreak.be/index.php?module=filmfreak&func=viewpub&tid=9&pid=420&title=There.Will.Be.Blood"}},{"critic":"Christy Lemire","date":"2008-01-18","publication":"Associated Press","quote":"Someday, we're probably going to look back at There Will Be Blood, Paul Thomas Anderson's epic about greed, lies, manipulation and insanity, and call it his masterpiece.","links":{}},{"critic":"Roger Moore","date":"2008-01-18","original_score":"4/5","publication":"Orlando Sentinel","quote":"It's oil, and a West that was just discovering it, that makes There Will Be Blood intriguing. But it's Day-Lewis who draws us in.","links":{"review":"http://www.orlandosentinel.com/entertainment/movies/orl-db-moviereviews-searchresults,0,3279701,results.formprofile?turbine_cdb_lib__cdb_01_txt=There%20Will%20Be%20Blood&Find+it%21=Submit+Query"}},{"critic":"Amy Biancolli","date":"2008-01-11","original_score":"3.5/4","publication":"Houston Chronicle","quote":"As an incurable romantic, I hold out hope that Anderson's flawed but phenomenal feat here marks the start of a new, mature stage in a long career. He has genius in him. So does the movie -- before its ending.","links":{"review":"http://www.chron.com/disp/story.mpl/ent/movies/reviews/5320054.html"}},{"critic":"Adam Graham","date":"2008-01-11","original_score":"B-","publication":"Detroit News","quote":"A maddening epic with a towering, bravura performance from star Daniel Day-Lewis, There Will Be Blood will rattle your brain for weeks, even months after you see it.","links":{"review":"http://www.detnews.com/apps/pbcs.dll/article?AID=/20080111/ENT02/801110391/1034/ENT02"}},{"critic":"Peter Travers","date":"2008-01-08","original_score":"4/4","publication":"Rolling Stone","quote":"There Will Be Blood hits with hurricane force. Lovers of formula and sugarcoating will hate it. Screw them. In terms of excitement, imagination and rule-busting experimentation, it's a gusher.","links":{}},{"critic":"Richard Roeper","date":"2008-01-07","publication":"Ebert & Roeper","quote":"Filmmaking at the highest level.","links":{}},{"critic":"Michael Phillips","date":"2008-01-04","original_score":"4/4","publication":"Chicago Tribune","quote":"There Will Be Blood reminds us that the greatest screen performances don't settle for capturing one trait, a dominant emotion or an easy way in.","links":{"review":"http://chicago.metromix.com/movies/movie_review/movie-review-there-will/276085/content"}},{"critic":"Peter Howell","date":"2008-01-04","original_score":"3.5/4","publication":"Toronto Star","quote":"There Will Be Blood, the astounding new film by Paul Thomas Anderson, is Horatio Alger by way of Faust.","links":{"review":"http://www.thestar.com/entertainment/Movies/article/290905"}},{"critic":"Mick LaSalle","date":"2008-01-04","original_score":"2.5/4","publication":"San Francisco Chronicle","quote":"Individual scenes and sequences are too strange, haunting and emotionally right for the film to be dismissed. There should be no attempt or temptation to dismiss it.","links":{"review":"http://www.sfgate.com/cgi-bin/article.cgi?file=/c/a/2008/01/04/DDVCU8QKP.DTL&type=movies"}},{"critic":"Liam Lacey","date":"2008-01-04","original_score":"3.5/4","publication":"Globe and Mail","quote":"Conjure up the maddest despot scene you can remember and you might get a sense of the seismic register of Day-Lewis's extravagant performance. Watch and marvel, though you may have to suspend your disbelief from the top of an oil derrick.","links":{"review":"http://www.theglobeandmail.com/servlet/story/RTGAM.20080103.blood04nat/BNStory/Entertainment/home"}},{"critic":"Lisa Kennedy","date":"2008-01-04","original_score":"4/4","publication":"Denver Post","quote":"If [Day-Lewis] does not win the Academy Award for this protean portrayal, it will be because he's won before. Or because his gift, his discipline, is so daunting it can be confounding.","links":{"review":"http://www.denverpost.com/movies/ci_7866021"}},{"critic":"Chris Vognar","date":"2008-01-04","original_score":"A-","publication":"Dallas Morning News","quote":"A haunting enigma that refuses to conform to any recognizable pattern, period or otherwise. I suppose you could see it as a descendent of Citizen Kane. But such comparisons aren't really fair to either film.","links":{"review":"http://www.guidelive.com/portal/page?_pageid=33,97283&_dad=portal&_schema=PORTAL&item_id=62157"}},{"critic":"Wesley Morris","date":"2008-01-04","original_score":"4/4","publication":"Boston Globe","quote":"There Will Be Blood is anti-state of the art. It's the work of an analog filmmaker railing against an increasingly digitized world. In that sense, the movie is idiosyncratic, too: vintage visionary stuff. It's physical and tactile.","links":{"review":"http://www.boston.com/movies/display?display=movie&id=10610"}},{"critic":"Roger Ebert","date":"2008-01-04","original_score":"3.5/4","publication":"Chicago Sun-Times","quote":"A force beyond categories.","links":{"review":"http://rogerebert.suntimes.com/apps/pbcs.dll/article?AID=/20080103/REVIEWS/801030301"}},{"critic":"Ann Hornaday","date":"2008-01-04","publication":"Washington Post","quote":"Paul Thomas Anderson becomes California's certified cinematic poet laureate with There Will Be Blood.","links":{"review":"http://www.washingtonpost.com/wp-dyn/content/article/2008/01/03/AR2008010304142.html"}},{"critic":"Colin Covert","date":"2008-01-04","original_score":"4/4","publication":"Minneapolis Star Tribune","quote":"A work of stunning intelligence and dramatic sweep, a portrait of a young nation struggling to find itself, torn between religious and business values.","links":{"review":"http://www.startribune.http://www.startribune.com/entertainment/movies/13018431.htmlcom/movies/"}}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770671487/reviews.json?review_type=topCritic&page_limit=20&country=us&page=1","next":"http://api.rottentomatoes.com/api/public/v1.0/movies/770671487/reviews.json?review_type=topCritic&page_limit=20&country=us&page=2","alternate":"http://www.rottentomatoes.com/m/there_will_be_blood/#reviews","rel":"http://api.rottentomatoes.com/api/public/v1.0/movies/770671487.json"},"link_template":"http://api.rottentomatoes.com/api/public/v1.0/movies/{movie-id}/reviews.json?review_type={top_critic|all|dvd}&page_limit={results-per-page}&page={page-number}&country={country-code}"}
@@ -3,9 +3,9 @@ require "spec_helper"
3
3
  describe Rotten::Movie do
4
4
  context "#cast" do
5
5
  before :each do
6
- simulate_movie_search
6
+ simulate "movies/search", "search.json", :q => "There Will Be Blood"
7
7
  @movie = Rotten::Movie.search("There Will Be Blood").pop
8
- simulate_full_cast(@movie)
8
+ simulate "movies/#{@movie.id}/cast", "cast.json"
9
9
  end
10
10
 
11
11
  context "sent :full" do
@@ -18,9 +18,9 @@ describe Rotten::Movie do
18
18
 
19
19
  context "#reviews" do
20
20
  before :each do
21
- simulate_movie_search
21
+ simulate "movies/search", "search.json", :q => "There Will Be Blood"
22
22
  @movie = Rotten::Movie.search("There Will Be Blood").pop
23
- simulate_movie_reviews(@movie)
23
+ simulate "movies/#{@movie.id}/reviews", "reviews.json"
24
24
  end
25
25
 
26
26
  it "should return an array of Review" do
@@ -28,10 +28,30 @@ describe Rotten::Movie do
28
28
  @movie.reviews.shift.should be_an_instance_of(Rotten::Review)
29
29
  end
30
30
  end
31
+
32
+ context ".dvd_releases" do
33
+ before :each do
34
+ simulate "lists/dvds/new_releases", "movie_openings.json"
35
+ end
36
+
37
+ it "should return an array" do
38
+ Rotten::Movie.dvd_releases.should be_an_instance_of(Array)
39
+ end
40
+ end
41
+
42
+ context ".in_theaters" do
43
+ before :each do
44
+ simulate "lists/movies/in_theaters", "movie_openings.json"
45
+ end
46
+
47
+ it "should return an array" do
48
+ Rotten::Movie.in_theatres.should be_an_instance_of(Array)
49
+ end
50
+ end
31
51
 
32
52
  context ".opening" do
33
53
  before :each do
34
- simulate_movie_openings
54
+ simulate "lists/movies/opening", "movie_openings.json"
35
55
  end
36
56
 
37
57
  it "should return an array" do
@@ -53,7 +73,7 @@ describe Rotten::Movie do
53
73
 
54
74
  context ".search" do
55
75
  before :each do
56
- simulate_movie_search
76
+ simulate "movies/search", "search.json", :q => "There Will Be Blood"
57
77
  end
58
78
 
59
79
  it "should return an array" do
@@ -67,7 +87,7 @@ describe Rotten::Movie do
67
87
 
68
88
  context "when api_key is undefined" do
69
89
  it "should raise error" do
70
- simulate_movie_openings
90
+ simulate "lists/movies/opening", "movie_openings.json"
71
91
  Rotten.api_key = nil
72
92
  lambda{ Rotten::Movie.opening }.should raise_error(Rotten::Api::UndefinedApiKeyError)
73
93
  end
@@ -9,27 +9,11 @@ RSpec.configure do |config|
9
9
  File.join( File.dirname(__FILE__), "fixtures" )
10
10
  end
11
11
 
12
- def simulate_movie_openings
13
- FakeWeb.register_uri(:get, Rotten::Movie.url_for("lists/movies/opening"),
14
- :body => File.read( File.join(fixture_path, "movie_openings.json") ))
12
+ def simulate(path, fixture, options={})
13
+ FakeWeb.register_uri(:get, Rotten::Movie.url_for(path, options),
14
+ :body => File.read( File.join(fixture_path, fixture)) )
15
15
  end
16
16
 
17
- def simulate_movie_search
18
- FakeWeb.register_uri(:get, Rotten::Movie.url_for("movies/search", :q => "There Will Be Blood"),
19
- :body => File.read( File.join(fixture_path, "search.json") ))
20
- end
21
-
22
- def simulate_movie_reviews(movie)
23
- FakeWeb.register_uri(:get, Rotten::Movie.url_for("movies/#{movie.id}/reviews"),
24
- :body => File.read( File.join(fixture_path, "reviews.json") ))
25
- end
26
-
27
- def simulate_full_cast(movie)
28
- FakeWeb.register_uri(:get, Rotten::Movie.url_for("movies/#{movie.id}/cast"),
29
- :body => File.read( File.join(fixture_path, "cast.json") ))
30
- end
31
-
32
-
33
17
  config.before(:each) do
34
18
  Rotten.api_key = "1234567890"
35
19
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
7
+ - 4
8
8
  - 0
9
- version: 0.3.0
9
+ version: 0.4.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - James Cook
@@ -61,12 +61,18 @@ files:
61
61
  - lib/rotten.rb
62
62
  - lib/rotten/actor.rb
63
63
  - lib/rotten/api.rb
64
+ - lib/rotten/cache.rb
64
65
  - lib/rotten/cast.rb
66
+ - lib/rotten/entity.rb
65
67
  - lib/rotten/movie.rb
68
+ - lib/rotten/review.rb
69
+ - lib/rotten/simple_cache.rb
66
70
  - lib/rotten/version.rb
67
71
  - rotten.gemspec
72
+ - spec/cache_spec.rb
68
73
  - spec/fixtures/cast.json
69
74
  - spec/fixtures/movie_openings.json
75
+ - spec/fixtures/reviews.json
70
76
  - spec/fixtures/search.json
71
77
  - spec/movie_spec.rb
72
78
  - spec/spec_helper.rb
@@ -105,8 +111,10 @@ signing_key:
105
111
  specification_version: 3
106
112
  summary: Wrapper for Rotten Tomatoes API
107
113
  test_files:
114
+ - spec/cache_spec.rb
108
115
  - spec/fixtures/cast.json
109
116
  - spec/fixtures/movie_openings.json
117
+ - spec/fixtures/reviews.json
110
118
  - spec/fixtures/search.json
111
119
  - spec/movie_spec.rb
112
120
  - spec/spec_helper.rb