redd 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -12
  3. data/lib/redd.rb +0 -12
  4. data/lib/redd/base.rb +10 -6
  5. data/lib/redd/client/authenticated.rb +2 -1
  6. data/lib/redd/client/authenticated/account.rb +2 -0
  7. data/lib/redd/client/authenticated/apps.rb +1 -0
  8. data/lib/redd/client/authenticated/flair.rb +33 -7
  9. data/lib/redd/client/authenticated/gold.rb +1 -0
  10. data/lib/redd/client/authenticated/links_comments.rb +86 -10
  11. data/lib/redd/client/authenticated/live.rb +1 -0
  12. data/lib/redd/client/authenticated/moderation.rb +65 -16
  13. data/lib/redd/client/authenticated/multis.rb +1 -1
  14. data/lib/redd/client/authenticated/private_messages.rb +50 -4
  15. data/lib/redd/client/authenticated/subreddits.rb +28 -0
  16. data/lib/redd/client/authenticated/users.rb +1 -1
  17. data/lib/redd/client/authenticated/wiki.rb +1 -1
  18. data/lib/redd/client/oauth2.rb +2 -2
  19. data/lib/redd/client/oauth2/authorization.rb +44 -11
  20. data/lib/redd/client/oauth2/identity.rb +4 -0
  21. data/lib/redd/client/unauthenticated/account.rb +13 -1
  22. data/lib/redd/client/unauthenticated/captcha.rb +7 -0
  23. data/lib/redd/client/unauthenticated/links_comments.rb +23 -4
  24. data/lib/redd/client/unauthenticated/listing.rb +43 -25
  25. data/lib/redd/client/unauthenticated/live.rb +1 -0
  26. data/lib/redd/client/unauthenticated/moderation.rb +9 -1
  27. data/lib/redd/client/unauthenticated/subreddits.rb +30 -0
  28. data/lib/redd/client/unauthenticated/utilities.rb +7 -4
  29. data/lib/redd/client/unauthenticated/wiki.rb +18 -4
  30. data/lib/redd/error.rb +5 -3
  31. data/lib/redd/oauth2_access.rb +21 -3
  32. data/lib/redd/object/more_comments.rb +1 -0
  33. data/lib/redd/object/private_message.rb +2 -1
  34. data/lib/redd/object/submission.rb +4 -0
  35. data/lib/redd/object/user.rb +1 -0
  36. data/lib/redd/response/raise_error.rb +2 -1
  37. data/lib/redd/thing/editable.rb +1 -0
  38. data/lib/redd/thing/hideable.rb +1 -0
  39. data/lib/redd/thing/inboxable.rb +1 -0
  40. data/lib/redd/thing/messageable.rb +2 -8
  41. data/lib/redd/thing/moderatable.rb +1 -0
  42. data/lib/redd/thing/reportable.rb +1 -0
  43. data/lib/redd/thing/saveable.rb +1 -0
  44. data/lib/redd/thing/voteable.rb +1 -1
  45. data/lib/redd/version.rb +1 -1
  46. data/spec/redd/client/unauthenticated_spec.rb +1 -1
  47. data/spec/redd/rate_limit_spec.rb +5 -5
  48. data/spec/redd_spec.rb +1 -1
  49. data/spec/spec_helper.rb +1 -1
  50. metadata +2 -3
  51. data/github/redd.png +0 -0
@@ -1,6 +1,7 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Unauthenticated
4
+ # Methods to interact with /r/live threads
4
5
  module Live
5
6
  end
6
7
  end
@@ -1,14 +1,22 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Unauthenticated
4
+ # Methods that deal with subreddit styles
4
5
  module Moderation
6
+ # @param subreddit [Redd::Object::Subreddit, String] The subreddit to
7
+ # query.
8
+ # @return [String] The url for the subreddit's css stylesheet.
5
9
  def stylesheet_url(subreddit = nil)
10
+ name = extract_attribute(subreddit, :display_name)
6
11
  path = "/stylesheet"
7
- path = path.prepend("/r/#{subreddit}") if subreddit
12
+ path = path.prepend("/r/#{name}") if subreddit
8
13
 
9
14
  get(path).headers[:location]
10
15
  end
11
16
 
17
+ # @param subreddit [Redd::Object::Subreddit, String] The subreddit to
18
+ # query.
19
+ # @return [String] The css stylesheet for the subreddit.
12
20
  def stylesheet(subreddit = nil)
13
21
  get stylesheet_url(subreddit)
14
22
  end
@@ -1,15 +1,45 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Unauthenticated
4
+ # Methods that deal with subreddits
4
5
  module Subreddits
6
+ # Return a Subreddit object from the title of a subreddit.
7
+ # @param title [String] The name of the subreddit.
8
+ # @return [Redd::Object::Subreddit]
5
9
  def subreddit(title)
6
10
  object_from_response :get, "/r/#{title}/about.json"
7
11
  end
8
12
 
13
+ # Get a list of subreddits sorted by the given parameter.
14
+ # @param where [:subscriber, :contributor, :moderator, :popular, :new]
15
+ # The type of subreddits to look for.
16
+ # @param params [Hash] A hash of parameters to send with the request.
17
+ # @option params [String] :after Return results after the given
18
+ # fullname.
19
+ # @option params [String] :before Return results before the given
20
+ # fullname.
21
+ # @option params [Integer] :count (0) The number of items already seen
22
+ # in the listing.
23
+ # @option params [1..100] :limit (25) The maximum number of things to
24
+ # return.
25
+ # @return [Redd::Object::Listing] A listing of subreddits.
9
26
  def get_subreddits(where = :popular, params = {})
10
27
  object_from_response :get, "/subreddits/#{where}.json", params
11
28
  end
12
29
 
30
+ # Look for subreddits matching the given query.
31
+ #
32
+ # @param query [String] The search query.
33
+ # @param params [Hash] A hash of parameters to send with the request.
34
+ # @option params [String] :after Return results after the given
35
+ # fullname.
36
+ # @option params [String] :before Return results before the given
37
+ # fullname.
38
+ # @option params [Integer] :count (0) The number of items already seen
39
+ # in the listing.
40
+ # @option params [1..100] :limit (25) The maximum number of things to
41
+ # return.
42
+ # @return [Redd::Object::Listing] A listing of subreddits.
13
43
  def search_subreddits(query, params = {})
14
44
  params << {q: query}
15
45
  object_from_response :get, "/subreddits/search.json", params
@@ -11,6 +11,7 @@ require "redd/object/wiki_page"
11
11
  module Redd
12
12
  module Client
13
13
  class Unauthenticated
14
+ # Non-API methods that make life easier
14
15
  module Utilities
15
16
  def comment_stream(*args, &block)
16
17
  submission_stream(:comments, *args, &block)
@@ -23,7 +24,7 @@ module Redd
23
24
  objects = get_listing(listing, subreddit, params)
24
25
  unless objects.empty?
25
26
  # Run the loop for each of the new comments accessed.
26
- # I should probably add it to some sort of Set to avoid duplicates.
27
+ # I should probably add it to a Set to avoid duplicates.
27
28
  objects.reverse_each { |object| block.call(object) }
28
29
  # Set the latest comment.
29
30
  params[:before] = objects.first.fullname
@@ -38,7 +39,7 @@ module Redd
38
39
  when ::String
39
40
  object
40
41
  else
41
- object.send(attribute)
42
+ object.send(attribute)
42
43
  end
43
44
  end
44
45
 
@@ -50,7 +51,8 @@ module Redd
50
51
  extract_attribute(object, :id)
51
52
  end
52
53
 
53
- def object_from_kind(kind) # rubocop:disable Style/MethodLength
54
+ # rubocop:disable Style/MethodLength, Style/CyclomaticComplexity
55
+ def object_from_kind(kind)
54
56
  case kind
55
57
  when "Listing"
56
58
  Redd::Object::Listing
@@ -72,6 +74,7 @@ module Redd
72
74
  Redd::Thing
73
75
  end
74
76
  end
77
+ # rubocop:enable Style/MethodLength, Style/CyclomaticComplexity
75
78
 
76
79
  def objects_from_listing(thing)
77
80
  thing[:data][:children].map do |child|
@@ -80,7 +83,7 @@ module Redd
80
83
  end
81
84
 
82
85
  def object_from_body(body)
83
- return nil unless body.is_a?(Hash) && body.has_key?(:kind)
86
+ return nil unless body.is_a?(Hash) && body.key?(:kind)
84
87
  object = object_from_kind(body[:kind])
85
88
 
86
89
  if object == Redd::Object::Listing
@@ -1,17 +1,31 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Unauthenticated
4
+ # Methods to interact with subreddit wikis
4
5
  module Wiki
6
+ # Get a list of pages in the subreddit wiki.
7
+ # @param subreddit [Redd::Object::Subreddit, String] The subreddit to
8
+ # look in.
9
+ # @return [Array] An array of wikipage titles.
5
10
  def get_wikipages(subreddit = nil)
11
+ name = extract_attribute(subreddit, :display_name)
12
+
6
13
  path = "/wiki/pages.json"
7
- path.prepend("/r/#{subreddit}") if subreddit
14
+ path.prepend("/r/#{name}") if subreddit
8
15
  get(path)[:data]
9
16
  end
10
17
 
11
- def wikipage(page, subreddit = nil, params = {})
18
+ # Get a wiki page.
19
+ # @param page [String] The title of the wiki page.
20
+ # @param subreddit [Redd::Object::Subreddit, String] The subreddit to
21
+ # look in.
22
+ # @return [Redd::Object::WikiPage] A wiki page.
23
+ def wikipage(page, subreddit = nil)
24
+ name = extract_attribute(subreddit, :display_name)
25
+
12
26
  path = "/wiki/#{page}.json"
13
- path.prepend("/r/#{subreddit}") if subreddit
14
- object_from_response :get, path, params
27
+ path.prepend("/r/#{name}") if subreddit
28
+ object_from_response :get, path
15
29
  end
16
30
  end
17
31
  end
@@ -1,6 +1,6 @@
1
1
  module Redd
2
+ # An error from reddit
2
3
  class Error < StandardError
3
-
4
4
  attr_reader :code
5
5
  attr_reader :headers
6
6
  attr_reader :body
@@ -12,8 +12,8 @@ module Redd
12
12
  end
13
13
 
14
14
  class << self
15
- # @note I ripped off RedditKit.rb :|
16
- def from_response(response) # rubocop:disable Style/CyclomaticComplexity Style/MethodLength
15
+ # rubocop:disable Style/CyclomaticComplexity, Style/MethodLength
16
+ def from_response(response)
17
17
  status = response[:status]
18
18
  body = parse_error(response[:body]).to_s
19
19
  case status
@@ -57,6 +57,7 @@ module Redd
57
57
  Redd::Error::TimedOut
58
58
  end
59
59
  end
60
+ # rubocop:enable Style/CyclomaticComplexity, Style/MethodLength
60
61
 
61
62
  def parse_error(body)
62
63
  return nil unless body.is_a?(Hash)
@@ -89,6 +90,7 @@ module Redd
89
90
 
90
91
  class PermissionDenied < Error; end
91
92
 
93
+ # Raised when the client needs to wait before making another request
92
94
  class RateLimited < Error
93
95
  attr_reader :time
94
96
 
@@ -1,17 +1,29 @@
1
1
  require "multi_json"
2
2
 
3
3
  module Redd
4
+ # A container for the client's access to their account via OAuth2
4
5
  class OAuth2Access
6
+ # @!attribute [r] access_token
7
+ # @return [String] The access token used to access the users account.
5
8
  attr_reader :access_token
6
9
 
10
+ # @!attribute [r] refresh_token
11
+ # @return [String, nil] The refresh token, if the access was permanent.
7
12
  attr_reader :refresh_token
8
13
 
14
+ # @!attribute [r] scope
15
+ # @return [Array] The scope that the client is allowed to access.
9
16
  attr_reader :scope
10
17
 
18
+ # @!attribute [r] duration
19
+ # @return [Symbol] Time the client is given access (temporary/permanent)
11
20
  attr_reader :duration
12
21
 
22
+ # @!attribute [r] expires_at
23
+ # @return [Time] The time when the access token expires.
13
24
  attr_reader :expires_at
14
25
 
26
+ # @param response [String] The response body containing the required info.
15
27
  def initialize(response)
16
28
  @access_token = response[:access_token]
17
29
  @refresh_token = response[:refresh_token]
@@ -20,21 +32,25 @@ module Redd
20
32
  @expires_at =
21
33
  if response[:expires_at]
22
34
  Time.at(response[:expires_at])
23
- else
35
+ else
24
36
  Time.now + response[:expires_in]
25
37
  end
26
38
  end
27
39
 
40
+ # Refresh the object with the new response.
41
+ # This happens when a new access token is requested using a request token.
42
+ # @param response [Hash] The new response body.
28
43
  def refresh(response)
29
44
  @access_token = response[:access_token]
30
45
  @expires_at = Time.now + response[:expires_in]
31
- self
32
46
  end
33
47
 
48
+ # @return [Boolean] Whether the access has expired.
34
49
  def expired?
35
50
  Time.now > @expires_at
36
51
  end
37
52
 
53
+ # @return [String] A JSON representation of the data that can be loaded later.
38
54
  def to_json
39
55
  MultiJson.dump(
40
56
  access_token: @access_token,
@@ -44,9 +60,11 @@ module Redd
44
60
  )
45
61
  end
46
62
 
63
+ # Create a new instance of the class from the JSON returned from #to_json
64
+ # @return [OAuth2Access]
47
65
  def self.from_json(json)
48
66
  hash = MultiJson.load(json, symbolize_keys: true)
49
67
  new(hash)
50
68
  end
51
69
  end
52
- end
70
+ end
@@ -1,5 +1,6 @@
1
1
  module Redd
2
2
  module Object
3
+ # The model for a morecomments object
3
4
  class MoreComments < Redd::Base
4
5
  attr_reader :count
5
6
  attr_reader :parent_id
@@ -2,6 +2,7 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  module Object
5
+ # The model for private messages
5
6
  class PrivateMessage < Redd::Thing
6
7
  require "redd/thing/inboxable"
7
8
 
@@ -20,7 +21,7 @@ module Redd
20
21
  attr_reader :author
21
22
 
22
23
  alias_method :from, :author
23
- alias_method :to, :author
24
+ alias_method :to, :dest
24
25
 
25
26
  def created
26
27
  @created ||= Time.at(@attributes[:created_utc])
@@ -60,6 +60,10 @@ module Redd
60
60
  alias_method :self?, :is_self
61
61
  alias_method :comments_count, :num_comments
62
62
 
63
+ def subreddit_name
64
+ @subreddit_name ||= @attributes[:subreddit]
65
+ end
66
+
63
67
  def subreddit
64
68
  @subreddit ||= client.subreddit(@attributes[:subreddit])
65
69
  end
@@ -2,6 +2,7 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  module Object
5
+ # The model for a reddit user
5
6
  class User < Redd::Thing
6
7
  require "redd/thing/messageable"
7
8
 
@@ -8,7 +8,8 @@ module Redd
8
8
  # @param faraday
9
9
  def call(faraday)
10
10
  @app.call(faraday).on_complete do |env|
11
- if error = Redd::Error.from_response(env)
11
+ error = Redd::Error.from_response(env)
12
+ if error
12
13
  if error == Redd::Error::RateLimited
13
14
  time = env.body[:json][:ratelimit]
14
15
  fail error.new(env, time)
@@ -2,6 +2,7 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  class Thing
5
+ # A Redd::Object that can be edited
5
6
  module Editable
6
7
  def delete
7
8
  client.delete(self)
@@ -2,6 +2,7 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  class Thing
5
+ # A Redd::Object that can be hidden
5
6
  module Hideable
6
7
  def hide
7
8
  client.hide(self)
@@ -2,6 +2,7 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  class Thing
5
+ # A Redd::Object that can be added to one's inbox
5
6
  module Inboxable
6
7
  def mark_as_read
7
8
  client.mark_as_read(self)
@@ -2,16 +2,10 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  class Thing
5
+ # A Redd::Object that can be sent a message
5
6
  module Messageable
6
7
  def send_message(subject, text, captcha = nil, identifier = nil)
7
- to = case self
8
- when Redd::Object::Subreddit
9
- "/r/" + display_name
10
- when Redd::Object::User
11
- name
12
- end
13
-
14
- client.send_message(to, subject, text, captcha, identifier)
8
+ client.send_message(self, subject, text, captcha, identifier)
15
9
  end
16
10
  end
17
11
  end
@@ -2,6 +2,7 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  class Thing
5
+ # A Redd::Object that can be moderated
5
6
  module Moderatable
6
7
  def approve
7
8
  client.approve(self)
@@ -2,6 +2,7 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  class Thing
5
+ # A Redd::Object that can be reported to the mods
5
6
  module Reportable
6
7
  def report
7
8
  client.report(self)
@@ -2,6 +2,7 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  class Thing
5
+ # A Redd::Object that can be saved
5
6
  module Saveable
6
7
  def save(category = nil)
7
8
  client.save(self, category)
@@ -2,6 +2,7 @@ require "redd/thing"
2
2
 
3
3
  module Redd
4
4
  class Thing
5
+ # A Redd::Object that can be voted on
5
6
  module Voteable
6
7
  def upvote
7
8
  client.upvote(self)
@@ -16,7 +17,6 @@ module Redd
16
17
  end
17
18
 
18
19
  alias_method :clear_vote, :unvote
19
-
20
20
  end
21
21
  end
22
22
  end
@@ -1,5 +1,5 @@
1
1
  # The main Redd module.
2
2
  module Redd
3
3
  # The semantic version number for Redd.
4
- VERSION = "0.4.3"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -12,4 +12,4 @@ describe Redd::Client::Unauthenticated, :vcr do
12
12
  expect(newclient.user_agent).to eq("SPEC_USERAGENT")
13
13
  expect(newclient.api_endpoint).to eq("SPEC_ENDPOINT.COM")
14
14
  end
15
- end
15
+ end
@@ -2,19 +2,19 @@ describe Redd::RateLimit do
2
2
  let(:rate_limit) { Redd::RateLimit.new }
3
3
 
4
4
  it "waits two seconds between consecutive requests" do
5
- rate_limit.after_limit { }
5
+ rate_limit.after_limit {}
6
6
  start_time = Time.now
7
- rate_limit.after_limit { }
7
+ rate_limit.after_limit {}
8
8
  end_time = Time.now
9
9
 
10
10
  expect(end_time - start_time).to be_within(0.1).of(2)
11
11
  end
12
12
 
13
13
  it "doesn't wait if two seconds have passed since last request" do
14
- rate_limit.after_limit { }
14
+ rate_limit.after_limit {}
15
15
  sleep(2)
16
16
  start_time = Time.now
17
- rate_limit.after_limit { }
17
+ rate_limit.after_limit {}
18
18
  end_time = Time.now
19
19
 
20
20
  expect(end_time - start_time).to be_within(0.1).of(0)
@@ -22,7 +22,7 @@ describe Redd::RateLimit do
22
22
 
23
23
  it "stores the time the last request was made" do
24
24
  time = Time.now
25
- rate_limit.after_limit { }
25
+ rate_limit.after_limit {}
26
26
 
27
27
  expect(rate_limit.last_request_time).to be_within(0.1).of(time)
28
28
  end