Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

* Improved get_resources, simplifying its use.

* Can now retrieve n number of comments or articles by specifying :count when retrieving them, assuming that many exist.
* Fixed new to not retreive upcoming articles, and added a method to access upcoming articles.
* Added a method to calculate a comments controversy score.
  • Loading branch information...
commit 3c9f45d84d5b64e7e82876072351288169702926 1 parent 5061235
@bterlson bterlson authored
View
6 lib/reddit/article.rb
@@ -15,6 +15,7 @@ def initialize(attributes)
@domain = attributes['domain']
@author = User.new(attributes['author']) unless attributes['author'].nil?
@id = attributes['id']
+ # Reddit's created_at timestamps are currently wonky, so this will return the wrong time.
@created_at = Time.at(attributes['created']) unless attributes['created'].nil?
@saved = attributes['saved']
@clicked = attributes['clicked']
@@ -37,8 +38,9 @@ def hidden?
end
# returns a CommentList of this article's comments.
- def comments
- return CommentList.new(@id)
+ def comments(options = {})
+ @comments_list ||= CommentList.new(@id)
+ return @comments_list.top_level(options)
end
end
end
View
6 lib/reddit/comment.rb
@@ -1,5 +1,4 @@
module Reddit
-
# A reddit comment.
class Comment
attr_reader :body, :name, :ups, :downs, :url, :domain, :author, :id, :created_at, :replies
@@ -21,7 +20,6 @@ def initialize(attributes)
@replies << Comment.new(reply['data'])
end
end
-
end
# Returns the score for this comment.
@@ -29,5 +27,9 @@ def score
return @ups - @downs
end
+ # returns a number representing how controversial this comment is
+ def controversy_score
+ (@ups + @downs).to_f / [score.abs, 1].max
+ end
end
end
View
13 lib/reddit/comment_list.rb
@@ -10,15 +10,10 @@ def initialize(article_id)
end
# returns the top level comments for the thread.
- def top_level
- resources = get_resources(@url)
-
- comments = []
- resources.each do |comment|
- comments << Comment.new(comment['data'])
+ def top_level(options = {})
+ get_resources(@url, :querystring => options[:querystring], :count => options[:count]) do |resource_json|
+ comment = Comment.new(resource_json['data'])
end
-
- return comments
end
private
@@ -26,6 +21,6 @@ def top_level
# forward any method calls to the top level comments array.
def method_missing(meth, *args, &block)
top_level.send(meth, *args, &block)
- end
+ end
end
end
View
38 lib/reddit/reddit.rb
@@ -9,37 +9,37 @@ def initialize(name = nil)
@url = @name.nil? ? BASE_URL : SUBREDDIT_URL.gsub('[subreddit]', @name)
end
- def hot
- articles 'hot'
+ def hot(options = {})
+ articles 'hot', options
end
- def top
- articles 'top'
+ def top(options = {})
+ articles 'top', options
end
- def new
- articles 'new', 'sort=new'
+ def new(options = {})
+ options[:querystring] = 'sort=new'
+ articles 'new', options
end
- def rising
- articles 'new', 'sort=upcoming'
+ def rising(options = {})
+ options[:querystring] = 'sort=rising'
+ articles 'new', options
end
- def controversial
- articles 'controversial'
+ def controversial(options = {})
+ articles 'controversial', options
end
# Returns the articles found in this reddit.
- def articles(page = 'hot', querystring = '')
- resources = get_resources("#{@url}#{page}/", querystring)
-
- articles = []
-
- resources.each do |article|
- articles << Article.new(article['data'])
+ # Options are:
+ # Count: Return at least this many articles.
+ # Querystring: Querystring to append to resource request
+
+ def articles(page = 'hot', options = {})
+ get_resources("#{@url}#{page}", options) do |resource_json|
+ Article.new(resource_json['data'])
end
-
- return articles
end
end
end
View
35 lib/reddit/resource_list.rb
@@ -7,21 +7,36 @@ class ResourceList
private
# Grabs the resources at the URL and returns the parsed json.
- def get_resources(url, querystring = '')
+ def get_resources(url, options = {}, &block)
+ querystring = options.delete(:querystring) || ''
+ count = options.delete(:count) || 25
url = URI.parse(url)
+ items = []
+ after = ''
- res = Net::HTTP.start(url.host, url.port) {|http|
- http.get("#{url.path}.json?#{querystring}")
- }
+ while items.size < count
+ res = Net::HTTP.start(url.host, url.port) {|http|
+ http.get("#{url.path}.json?#{querystring}&after=#{after}&limit=#{count - items.size}")
+ }
- raise SubredditNotFound if res.is_a?(Net::HTTPRedirection)
- resources = JSON.parse(res.body, :max_nesting => 0)
+ raise SubredditNotFound if res.is_a?(Net::HTTPRedirection)
- # comments pages are contained in an array where the first element is the article
- # and the second is the actual comments. This is hackish.
- resources = resources.last if resources.is_a?(Array)
+ resources = JSON.parse(res.body, :max_nesting => 0)
- return resources['data']['children']
+ # comments pages are contained in an array where the first element is the article
+ # and the second is the actual comments. This is hackish.
+ resources = resources.last if resources.is_a?(Array)
+ resources = resources['data']['children']
+ break if resources.size == 0
+ resources.each do |resource|
+ items << yield(resource)
+ end
+
+ after = items.last.name
+ end
+
+ items
end
end
+
end
View
13 lib/reddit/user.rb
@@ -11,15 +11,12 @@ def initialize(name)
end
# Get the user's comments.
- def comments
- resources = get_resources(@url)
-
- comments = []
- resources.each do |comment|
- comments << Comment.new(comment['data'])
+ # Options can include a limit, which sets the number of comments to return.
+
+ def comments(options = {})
+ get_resources("#{@url}comments/", :querystring => options[:querystring], :count => options[:count]) do |resource_json|
+ Comment.new(resource_json['data'])
end
-
- return comments
end
end
end
View
2  spec/article_spec.rb
@@ -6,7 +6,7 @@
end
it "should be able to get the article's comments comments" do
- Reddit::CommentList.should_receive(:new).with("id").and_return("reddit!")
+ Reddit::CommentList.should_receive(:new).with("id").and_return(mock(Reddit::CommentList, :top_level => "reddit!"))
@article.comments.should == "reddit!"
end
end
View
8 spec/comment_list_spec.rb
@@ -10,13 +10,9 @@
end
it "should fetch the top level comments" do
- @comments_list.should_receive(:get_resources).and_return([
- {:type => 't1', :data => {:attribute => 'value'}},
- {:type => 't1', :data => {:attribute => 'value2'}}
- ])
-
mock_comment = mock(Reddit::Comment)
- Reddit::Comment.should_receive(:new).twice.and_return(mock_comment)
+
+ @comments_list.should_receive(:get_resources).and_return([mock_comment, mock_comment])
@comments_list.top_level.should == [mock_comment, mock_comment]
end
View
21 spec/reddit_spec.rb
@@ -17,18 +17,15 @@ def test_articles
end
it "should find the articles" do
- @reddit.should_receive(:get_resources).and_return(test_articles)
-
mock_article = mock(Reddit::Article)
- Reddit::Article.should_receive(:new).twice.and_return(mock_article)
-
+ @reddit.should_receive(:get_resources).and_return([mock_article, mock_article])
@reddit.articles.should == [mock_article, mock_article]
end
it "should find top articles" do
mock_article = mock(Reddit::Article)
- @reddit.should_receive(:articles).with('top').and_return([mock_article, mock_article])
+ @reddit.should_receive(:articles).with('top', {}).and_return([mock_article, mock_article])
@reddit.top.should == [mock_article, mock_article]
end
@@ -36,15 +33,23 @@ def test_articles
it "should find new articles" do
mock_article = mock(Reddit::Article)
- @reddit.should_receive(:articles).with('new').and_return([mock_article, mock_article])
+ @reddit.should_receive(:articles).with('new', {:querystring => 'sort=new'}).and_return([mock_article, mock_article])
@reddit.new.should == [mock_article, mock_article]
end
+ it "should find rising articles" do
+ mock_article = mock(Reddit::Article)
+
+ @reddit.should_receive(:articles).with('new', {:querystring => 'sort=rising'}).and_return([mock_article, mock_article])
+
+ @reddit.rising.should == [mock_article, mock_article]
+ end
+
it "should find controversial articles" do
mock_article = mock(Reddit::Article)
- @reddit.should_receive(:articles).with('controversial').and_return([mock_article, mock_article])
+ @reddit.should_receive(:articles).with('controversial', {}).and_return([mock_article, mock_article])
@reddit.controversial.should == [mock_article, mock_article]
end
@@ -52,7 +57,7 @@ def test_articles
it "should find hot articles" do
mock_article = mock(Reddit::Article)
- @reddit.should_receive(:articles).with('hot').and_return([mock_article, mock_article])
+ @reddit.should_receive(:articles).with('hot', {}).and_return([mock_article, mock_article])
@reddit.hot.should == [mock_article, mock_article]
end
View
15 spec/resource_list_spec.rb
@@ -12,12 +12,23 @@
it "should get the resources from Reddit" do
Net::HTTP.should_receive(:start).and_yield(@http_mock).and_return(@response_mock)
- @resource_list.send(:get_resources, "http://reddit.com")
+ @resource_list.send(:get_resources, "http://reddit.com", :count => 1) do
+ mock('object', :name => "object_name")
+ end
+ end
+
+ it "should get the specified number of resources" do
+ Net::HTTP.should_receive(:start).exactly(:twice).and_yield(@http_mock).and_return(@response_mock)
+ @resource_list.send(:get_resources, "http://reddit.com", :count => 2) do
+ mock('object', :name => "object_name")
+ end
end
it "should parse the JSON" do
JSON.should_receive(:parse).and_return({'kind' => 'Listing', 'data' => {'children' => [{'data' => {'attribute' => 'value'}}]}})
- @resource_list.send(:get_resources, "http://reddit.com")
+ @resource_list.send(:get_resources, "http://reddit.com", :count => 1) do
+ mock('object', :name => "object_name")
+ end
end
it "should raise an error when the subreddit is not found" do
View
8 spec/user_spec.rb
@@ -10,14 +10,8 @@
end
it "should fetch the user's comments" do
- @user.should_receive(:get_resources).and_return([
- {:type => 't1', :data => {:attribute => 'value'}},
- {:type => 't1', :data => {:attribute => 'value2'}}
- ])
-
mock_comment = mock(Reddit::Comment)
- Reddit::Comment.should_receive(:new).twice.and_return(mock_comment)
-
+ @user.should_receive(:get_resources).and_return([mock_comment, mock_comment])
@user.comments.should == [mock_comment, mock_comment]
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.