bterlson-reddit 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,6 +15,7 @@ module Reddit
15
15
  @domain = attributes['domain']
16
16
  @author = User.new(attributes['author']) unless attributes['author'].nil?
17
17
  @id = attributes['id']
18
+ # Reddit's created_at timestamps are currently wonky, so this will return the wrong time.
18
19
  @created_at = Time.at(attributes['created']) unless attributes['created'].nil?
19
20
  @saved = attributes['saved']
20
21
  @clicked = attributes['clicked']
@@ -37,8 +38,9 @@ module Reddit
37
38
  end
38
39
 
39
40
  # returns a CommentList of this article's comments.
40
- def comments
41
- return CommentList.new(@id)
41
+ def comments(options = {})
42
+ @comments_list ||= CommentList.new(@id)
43
+ return @comments_list.top_level(options)
42
44
  end
43
45
  end
44
46
  end
@@ -1,5 +1,4 @@
1
1
  module Reddit
2
-
3
2
  # A reddit comment.
4
3
  class Comment
5
4
  attr_reader :body, :name, :ups, :downs, :url, :domain, :author, :id, :created_at, :replies
@@ -21,7 +20,6 @@ module Reddit
21
20
  @replies << Comment.new(reply['data'])
22
21
  end
23
22
  end
24
-
25
23
  end
26
24
 
27
25
  # Returns the score for this comment.
@@ -29,5 +27,9 @@ module Reddit
29
27
  return @ups - @downs
30
28
  end
31
29
 
30
+ # returns a number representing how controversial this comment is
31
+ def controversy_score
32
+ (@ups + @downs).to_f / [score.abs, 1].max
33
+ end
32
34
  end
33
35
  end
@@ -10,15 +10,10 @@ module Reddit
10
10
  end
11
11
 
12
12
  # returns the top level comments for the thread.
13
- def top_level
14
- resources = get_resources(@url)
15
-
16
- comments = []
17
- resources.each do |comment|
18
- comments << Comment.new(comment['data'])
13
+ def top_level(options = {})
14
+ get_resources(@url, :querystring => options[:querystring], :count => options[:count]) do |resource_json|
15
+ comment = Comment.new(resource_json['data'])
19
16
  end
20
-
21
- return comments
22
17
  end
23
18
 
24
19
  private
@@ -26,6 +21,6 @@ module Reddit
26
21
  # forward any method calls to the top level comments array.
27
22
  def method_missing(meth, *args, &block)
28
23
  top_level.send(meth, *args, &block)
29
- end
24
+ end
30
25
  end
31
26
  end
@@ -9,33 +9,37 @@ module Reddit
9
9
  @url = @name.nil? ? BASE_URL : SUBREDDIT_URL.gsub('[subreddit]', @name)
10
10
  end
11
11
 
12
- def hot
13
- articles 'hot'
12
+ def hot(options = {})
13
+ articles 'hot', options
14
14
  end
15
15
 
16
- def top
17
- articles 'top'
16
+ def top(options = {})
17
+ articles 'top', options
18
18
  end
19
19
 
20
- def new
21
- articles 'new'
20
+ def new(options = {})
21
+ options[:querystring] = 'sort=new'
22
+ articles 'new', options
22
23
  end
23
24
 
24
- def controversial
25
- articles 'controversial'
25
+ def rising(options = {})
26
+ options[:querystring] = 'sort=rising'
27
+ articles 'new', options
28
+ end
29
+
30
+ def controversial(options = {})
31
+ articles 'controversial', options
26
32
  end
27
33
 
28
34
  # Returns the articles found in this reddit.
29
- def articles(page = 'hot')
30
- resources = get_resources("#{@url}#{page}/")
31
-
32
- articles = []
33
-
34
- resources.each do |article|
35
- articles << Article.new(article['data'])
35
+ # Options are:
36
+ # Count: Return at least this many articles.
37
+ # Querystring: Querystring to append to resource request
38
+
39
+ def articles(page = 'hot', options = {})
40
+ get_resources("#{@url}#{page}", options) do |resource_json|
41
+ Article.new(resource_json['data'])
36
42
  end
37
-
38
- return articles
39
43
  end
40
44
  end
41
45
  end
@@ -7,22 +7,36 @@ module Reddit
7
7
  private
8
8
 
9
9
  # Grabs the resources at the URL and returns the parsed json.
10
- def get_resources(url)
11
- puts "Getting URL: #{url}"
10
+ def get_resources(url, options = {}, &block)
11
+ querystring = options.delete(:querystring) || ''
12
+ count = options.delete(:count) || 25
12
13
  url = URI.parse(url)
14
+ items = []
15
+ after = ''
13
16
 
14
- res = Net::HTTP.start(url.host, url.port) {|http|
15
- http.get(url.path + ".json")
16
- }
17
+ while items.size < count
18
+ res = Net::HTTP.start(url.host, url.port) {|http|
19
+ http.get("#{url.path}.json?#{querystring}&after=#{after}&limit=#{count - items.size}")
20
+ }
17
21
 
18
- raise SubredditNotFound if res.is_a?(Net::HTTPRedirection)
19
- resources = JSON.parse(res.body, :max_nesting => 0)
22
+ raise SubredditNotFound if res.is_a?(Net::HTTPRedirection)
20
23
 
21
- # comments pages are contained in an array where the first element is the article
22
- # and the second is the actual comments. This is hackish.
23
- resources = resources.last if resources.is_a?(Array)
24
+ resources = JSON.parse(res.body, :max_nesting => 0)
24
25
 
25
- return resources['data']['children']
26
+ # comments pages are contained in an array where the first element is the article
27
+ # and the second is the actual comments. This is hackish.
28
+ resources = resources.last if resources.is_a?(Array)
29
+ resources = resources['data']['children']
30
+ break if resources.size == 0
31
+ resources.each do |resource|
32
+ items << yield(resource)
33
+ end
34
+
35
+ after = items.last.name
36
+ end
37
+
38
+ items
26
39
  end
27
40
  end
41
+
28
42
  end
@@ -2,7 +2,7 @@ module Reddit
2
2
  BASE_URL = "http://www.reddit.com/"
3
3
  PROFILE_URL = BASE_URL + "user/[username]/"
4
4
  SUBREDDIT_URL = BASE_URL + "r/[subreddit]/"
5
- COMMENTS_URL = BASE_URL + "info/[id]/comments/"
5
+ COMMENTS_URL = BASE_URL + "comments/[id]/"
6
6
 
7
7
  # raised when attempting to interact with a subreddit that doesn't exist.
8
8
  class SubredditNotFound < StandardError; end
@@ -11,15 +11,12 @@ module Reddit
11
11
  end
12
12
 
13
13
  # Get the user's comments.
14
- def comments
15
- resources = get_resources(@url)
16
-
17
- comments = []
18
- resources.each do |comment|
19
- comments << Comment.new(comment['data'])
14
+ # Options can include a limit, which sets the number of comments to return.
15
+
16
+ def comments(options = {})
17
+ get_resources("#{@url}comments/", :querystring => options[:querystring], :count => options[:count]) do |resource_json|
18
+ Comment.new(resource_json['data'])
20
19
  end
21
-
22
- return comments
23
20
  end
24
21
  end
25
22
  end
@@ -1,8 +1,8 @@
1
1
  module Reddit #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 2
5
- TINY = 1
4
+ MINOR = 3
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -6,7 +6,7 @@ describe Reddit::Article do
6
6
  end
7
7
 
8
8
  it "should be able to get the article's comments comments" do
9
- Reddit::CommentList.should_receive(:new).with("id").and_return("reddit!")
9
+ Reddit::CommentList.should_receive(:new).with("id").and_return(mock(Reddit::CommentList, :top_level => "reddit!"))
10
10
  @article.comments.should == "reddit!"
11
11
  end
12
12
  end
@@ -10,13 +10,9 @@ describe Reddit::CommentList do
10
10
  end
11
11
 
12
12
  it "should fetch the top level comments" do
13
- @comments_list.should_receive(:get_resources).and_return([
14
- {:type => 't1', :data => {:attribute => 'value'}},
15
- {:type => 't1', :data => {:attribute => 'value2'}}
16
- ])
17
-
18
13
  mock_comment = mock(Reddit::Comment)
19
- Reddit::Comment.should_receive(:new).twice.and_return(mock_comment)
14
+
15
+ @comments_list.should_receive(:get_resources).and_return([mock_comment, mock_comment])
20
16
 
21
17
  @comments_list.top_level.should == [mock_comment, mock_comment]
22
18
  end
@@ -17,18 +17,15 @@ describe Reddit::Reddit do
17
17
  end
18
18
 
19
19
  it "should find the articles" do
20
- @reddit.should_receive(:get_resources).and_return(test_articles)
21
-
22
20
  mock_article = mock(Reddit::Article)
23
- Reddit::Article.should_receive(:new).twice.and_return(mock_article)
24
-
21
+ @reddit.should_receive(:get_resources).and_return([mock_article, mock_article])
25
22
  @reddit.articles.should == [mock_article, mock_article]
26
23
  end
27
24
 
28
25
  it "should find top articles" do
29
26
  mock_article = mock(Reddit::Article)
30
27
 
31
- @reddit.should_receive(:articles).with('top').and_return([mock_article, mock_article])
28
+ @reddit.should_receive(:articles).with('top', {}).and_return([mock_article, mock_article])
32
29
 
33
30
  @reddit.top.should == [mock_article, mock_article]
34
31
  end
@@ -36,15 +33,23 @@ describe Reddit::Reddit do
36
33
  it "should find new articles" do
37
34
  mock_article = mock(Reddit::Article)
38
35
 
39
- @reddit.should_receive(:articles).with('new').and_return([mock_article, mock_article])
36
+ @reddit.should_receive(:articles).with('new', {:querystring => 'sort=new'}).and_return([mock_article, mock_article])
40
37
 
41
38
  @reddit.new.should == [mock_article, mock_article]
42
39
  end
43
40
 
41
+ it "should find rising articles" do
42
+ mock_article = mock(Reddit::Article)
43
+
44
+ @reddit.should_receive(:articles).with('new', {:querystring => 'sort=rising'}).and_return([mock_article, mock_article])
45
+
46
+ @reddit.rising.should == [mock_article, mock_article]
47
+ end
48
+
44
49
  it "should find controversial articles" do
45
50
  mock_article = mock(Reddit::Article)
46
51
 
47
- @reddit.should_receive(:articles).with('controversial').and_return([mock_article, mock_article])
52
+ @reddit.should_receive(:articles).with('controversial', {}).and_return([mock_article, mock_article])
48
53
 
49
54
  @reddit.controversial.should == [mock_article, mock_article]
50
55
  end
@@ -52,7 +57,7 @@ describe Reddit::Reddit do
52
57
  it "should find hot articles" do
53
58
  mock_article = mock(Reddit::Article)
54
59
 
55
- @reddit.should_receive(:articles).with('hot').and_return([mock_article, mock_article])
60
+ @reddit.should_receive(:articles).with('hot', {}).and_return([mock_article, mock_article])
56
61
 
57
62
  @reddit.hot.should == [mock_article, mock_article]
58
63
  end
@@ -12,12 +12,23 @@ describe Reddit::ResourceList, ".get_resources" do
12
12
 
13
13
  it "should get the resources from Reddit" do
14
14
  Net::HTTP.should_receive(:start).and_yield(@http_mock).and_return(@response_mock)
15
- @resource_list.send(:get_resources, "http://reddit.com")
15
+ @resource_list.send(:get_resources, "http://reddit.com", :count => 1) do
16
+ mock('object', :name => "object_name")
17
+ end
18
+ end
19
+
20
+ it "should get the specified number of resources" do
21
+ Net::HTTP.should_receive(:start).exactly(:twice).and_yield(@http_mock).and_return(@response_mock)
22
+ @resource_list.send(:get_resources, "http://reddit.com", :count => 2) do
23
+ mock('object', :name => "object_name")
24
+ end
16
25
  end
17
26
 
18
27
  it "should parse the JSON" do
19
28
  JSON.should_receive(:parse).and_return({'kind' => 'Listing', 'data' => {'children' => [{'data' => {'attribute' => 'value'}}]}})
20
- @resource_list.send(:get_resources, "http://reddit.com")
29
+ @resource_list.send(:get_resources, "http://reddit.com", :count => 1) do
30
+ mock('object', :name => "object_name")
31
+ end
21
32
  end
22
33
 
23
34
  it "should raise an error when the subreddit is not found" do
@@ -10,14 +10,8 @@ describe Reddit::User do
10
10
  end
11
11
 
12
12
  it "should fetch the user's comments" do
13
- @user.should_receive(:get_resources).and_return([
14
- {:type => 't1', :data => {:attribute => 'value'}},
15
- {:type => 't1', :data => {:attribute => 'value2'}}
16
- ])
17
-
18
13
  mock_comment = mock(Reddit::Comment)
19
- Reddit::Comment.should_receive(:new).twice.and_return(mock_comment)
20
-
14
+ @user.should_receive(:get_resources).and_return([mock_comment, mock_comment])
21
15
  @user.comments.should == [mock_comment, mock_comment]
22
16
  end
23
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bterlson-reddit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Terlson
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-06-13 00:00:00 -07:00
12
+ date: 2008-08-13 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -77,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
77
  requirements: []
78
78
 
79
79
  rubyforge_project:
80
- rubygems_version: 1.0.1
80
+ rubygems_version: 1.2.0
81
81
  signing_key:
82
82
  specification_version: 2
83
83
  summary: Interface with the Reddit.com API.
data/README.txt DELETED
@@ -1,66 +0,0 @@
1
- = reddit
2
-
3
- * http://github.com/bterlson/reddit/
4
-
5
- == DESCRIPTION:
6
-
7
- An interface to the reddit API.
8
-
9
- == FEATURES/PROBLEMS:
10
-
11
- * Retreive articles and their comments
12
- * Retreive user pages
13
-
14
- == SYNOPSIS:
15
-
16
- require 'rubygems'
17
- require 'reddit'
18
-
19
- reddit = Reddit::Session.new
20
-
21
- reddit.main.articles.each do |article|
22
- p article.url
23
-
24
- article.comments.each do |comment|
25
- p comment.body
26
- end
27
- end
28
-
29
- p reddit.subreddit("programming").articles[1].author
30
-
31
- reddit.user("radhruin").comments.each do |comment|
32
- p comment.body
33
- end
34
-
35
- == REQUIREMENTS:
36
-
37
- * JSON >= 1.1.2
38
-
39
- == INSTALL:
40
-
41
- * sudo gem install bterlson-reddit --source=http://gems.github.com
42
-
43
- == LICENSE:
44
-
45
- (The MIT License)
46
-
47
- Copyright (c) 2008 FIX
48
-
49
- Permission is hereby granted, free of charge, to any person obtaining
50
- a copy of this software and associated documentation files (the
51
- 'Software'), to deal in the Software without restriction, including
52
- without limitation the rights to use, copy, modify, merge, publish,
53
- distribute, sublicense, and/or sell copies of the Software, and to
54
- permit persons to whom the Software is furnished to do so, subject to
55
- the following conditions:
56
-
57
- The above copyright notice and this permission notice shall be
58
- included in all copies or substantial portions of the Software.
59
-
60
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
61
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
62
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
63
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
64
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
65
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
66
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.