redd 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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,8 +1,8 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Authenticated
4
+ # Methods to interact with multis (groups of subreddits).
4
5
  module Multis
5
-
6
6
  end
7
7
  end
8
8
  end
@@ -1,32 +1,78 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Authenticated
4
+ # Methods for sending and reading private messages
4
5
  module PrivateMessages
6
+ # Block the sender of the message from sending any more.
7
+ #
8
+ # @param message [Redd::Object::PrivateMessage, String] The message
9
+ # whose sender to block.
5
10
  def block_message(message)
6
11
  fullname = extract_fullname(message)
7
12
  post "/api/block", id: fullname
8
13
  end
9
14
 
15
+ # Compose a message to a person or the moderators of a subreddit.
16
+ #
17
+ # @param to [Redd::Object::User, Redd::Object::Subreddit, String] The
18
+ # thing to send a message to.
19
+ # @param subject [String] The subject of the message.
20
+ # @param text [String] The message text.
21
+ # @param captcha [String] A possible captcha result to send if one
22
+ # is required.
23
+ # @param identifier [String] The identifier for the captcha if one
24
+ # is required.
10
25
  def compose_message(to, subject, text, captcha = nil, identifier = nil)
11
- params = {
12
- api_type: "json", to: to.to_s, subject: subject, text: text
13
- }
26
+ params[:to] =
27
+ case to
28
+ when Redd::Object::User
29
+ to.name
30
+ when Redd::Object::Subreddit
31
+ to.display_name
32
+ when String
33
+ to
34
+ end
35
+
36
+ params = {api_type: "json", subject: subject, text: text}
14
37
  params << {captcha: captcha, iden: identifier} if captcha
15
38
 
16
39
  post "/api/compose", params
17
40
  end
18
41
 
42
+ # Mark a message as read.
43
+ #
44
+ # @param message [Redd::Object::PrivateMessage, String] The message
45
+ # to mark as read.
19
46
  def mark_as_read(message)
20
47
  fullname = extract_fullname(message)
21
48
  post "/api/read_message", id: fullname
22
49
  end
23
50
 
51
+ # Mark a message as unread.
52
+ #
53
+ # @param message [Redd::Object::PrivateMessage, String] The message
54
+ # to mark as unread.
24
55
  def mark_as_unread(message)
25
56
  fullname = extract_fullname(message)
26
57
  post "/api/unread_message", id: fullname
27
58
  end
28
59
 
29
- def messages(category = "inbox", params = {})
60
+ # Return a list of a user's private messages.
61
+ #
62
+ # @param category [String] The category of messages to view.
63
+ # @param mark [Boolean] Whether to remove the orangered from the
64
+ # user's inbox.
65
+ # @param params [Hash] A list of params to send with the request.
66
+ # @option params [String] :after Return results after the given
67
+ # fullname.
68
+ # @option params [String] :before Return results before the given
69
+ # fullname.
70
+ # @option params [Integer] :count (0) The number of items already seen
71
+ # in the listing.
72
+ # @option params [1..100] :limit (25) The maximum number of things to
73
+ # return.
74
+ def messages(category = "inbox", mark = false, params = {})
75
+ params[:mark] = mark
30
76
  object_from_response :get, "/message/#{category}.json", params
31
77
  end
32
78
  end
@@ -1,15 +1,38 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Authenticated
4
+ # Methods to interact with subreddits
4
5
  module Subreddits
6
+ # Subscribe to a subreddit.
7
+ #
8
+ # @param subreddit [Redd::Object::Subreddit, String] The subreddit to
9
+ # subscribe to.
5
10
  def subscribe(subreddit)
6
11
  edit_subscription(:sub, subreddit)
7
12
  end
8
13
 
14
+ # Unsubscribe from a subreddit.
15
+ #
16
+ # @param subreddit [Redd::Object::Subreddit, String] The subreddit to
17
+ # unsubscribe from.
9
18
  def unsubscribe(subreddit)
10
19
  edit_subscription(:unsub, subreddit)
11
20
  end
12
21
 
22
+ # Get a listing of subreddits.
23
+ #
24
+ # @param where [:popular, :new, :subscriber, :contributor, :moderator]
25
+ # The order of subreddits to return.
26
+ # @param params [Hash] A list of params to send with the request.
27
+ # @option params [String] :after Return results after the given
28
+ # fullname.
29
+ # @option params [String] :before Return results before the given
30
+ # fullname.
31
+ # @option params [Integer] :count (0) The number of items already seen
32
+ # in the listing.
33
+ # @option params [1..100] :limit (25) The maximum number of things to
34
+ # return.
35
+ # @return [Redd::Object::Listing] A listing of subreddits.
13
36
  def get_subreddits(where = :subscriber, params = {})
14
37
  path =
15
38
  if [:popular, :new].include?(where)
@@ -22,6 +45,11 @@ module Redd
22
45
 
23
46
  private
24
47
 
48
+ # Subscribe or unsubscribe to a subreddit.
49
+ #
50
+ # @param action [:sub, :unsub] The type of action to perform.
51
+ # @param subreddit [Redd::Object::Subreddit, String] The subreddit to
52
+ # perform the action on.
25
53
  def edit_subscription(action, subreddit)
26
54
  fullname = extract_fullname(subreddit)
27
55
  post "/api/subscribe", action: action, sr: fullname
@@ -1,8 +1,8 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Authenticated
4
+ # Methods to interact with other users
4
5
  module Users
5
-
6
6
  end
7
7
  end
8
8
  end
@@ -1,8 +1,8 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Authenticated
4
+ # Methods to interact with wiki pages
4
5
  module Wiki
5
-
6
6
  end
7
7
  end
8
8
  end
@@ -44,14 +44,14 @@ module Redd
44
44
 
45
45
  private
46
46
 
47
- def connection(access_token = @access.access_token)
47
+ def connection
48
48
  @connection ||= Faraday.new(url: api_endpoint) do |faraday|
49
49
  faraday.use Faraday::Request::UrlEncoded
50
50
  faraday.use Redd::Response::RaiseError
51
51
  faraday.use Redd::Response::ParseJson
52
52
  faraday.adapter Faraday.default_adapter
53
53
 
54
- faraday.headers["Authorization"] = "bearer #{access_token}"
54
+ faraday.headers["Authorization"] = "bearer #{@access.access_token}"
55
55
  faraday.headers["User-Agent"] = "Redd/Ruby, v#{Redd::VERSION}"
56
56
  end
57
57
  end
@@ -3,40 +3,73 @@ require "redd/oauth2_access"
3
3
  module Redd
4
4
  module Client
5
5
  class OAuth2
6
+ # Methods for obtaining an access token
6
7
  module Authorization
7
- def auth_url(scope = ["identity"], duration = "temporary", state = "x")
8
+ # Build an authorization url to redirect the user to.
9
+ #
10
+ # @param scopes [Array<String>] The access scopes to request from the
11
+ # user.
12
+ # @param duration [:temporary, :permanent] The duration of your access
13
+ # to the user's account.
14
+ # @param state [String] A random string to check later.
15
+ # @return [String] The url.
16
+ #
17
+ # @note The access tokens from both duration last only an hour, but you
18
+ # also get a refresh token when the duration is permanent.
19
+ # @note You may be tempted to let the state remain "x", but seriously,
20
+ # use this; it helps prevent against CSRF attacks.
21
+ def auth_url(scopes = ["identity"], duration = :temporary, state = "x")
8
22
  path = "https://ssl.reddit.com/api/v1/authorize"
23
+ scope = scopes.is_a?(Array) ? scopes.join(",") : scopes
9
24
  query = {
10
25
  client_id: @client_id,
11
26
  redirect_uri: @redirect_uri,
12
27
  response_type: "code",
13
28
  state: state,
14
- scope: scope.join(","),
29
+ scope: scope,
15
30
  duration: duration
16
31
  }
17
32
  string_query = query.map { |key, value| "#{key}=#{value}" }.join("&")
18
-
19
33
  "#{path}?#{string_query}"
20
34
  end
21
35
 
22
- def request_access_token(code, set_access = true)
36
+ # Request an access token from the code that is sent with the redirect.
37
+ #
38
+ # @param code [String] The code that was sent in the GET request.
39
+ # @param set_access [Boolean] Whether to automatically use this token
40
+ # for all future requests with this client.
41
+ # @return [Redd::OAuth2Access] A package of the necessary information
42
+ # to access the user's information.
43
+ def request_access(code, set_access = true)
23
44
  response = auth_connection.post "/api/v1/access_token",
24
- grant_type: "authorization_code", code: code,
25
- redirect_uri: @redirect_uri
45
+ grant_type: "authorization_code",
46
+ code: code,
47
+ redirect_uri: @redirect_uri
26
48
 
27
49
  access = Redd::OAuth2Access.new(response.body)
28
50
  @access = access if set_access
29
51
  access
30
52
  end
31
53
 
32
- def refresh_access_token(access = nil, set_access = true)
33
- refresh_token = extract_attribute(access, :refresh_token)
54
+ # Obtain a new access token using a refresh token.
55
+ #
56
+ # @param token [Redd::OAuth2Access, String, nil] The refresh token or
57
+ # OAuth2Access. If none is provided, it'll refresh the one the client
58
+ # is currently using.
59
+ # @param set_access [Boolean] Whether to automatically use this token
60
+ # for all future requests with this client.
61
+ # @return [Redd::OAuth2Access] The refreshed information.
62
+ def refresh_access(token = nil, set_access = true)
63
+ refresh_token = extract_attribute(token, :refresh_token)
34
64
  response = auth_connection.post "/api/v1/access_token",
35
- grant_type: "refresh_token", refresh_token: refresh_token
65
+ grant_type: "refresh_token",
66
+ refresh_token: refresh_token
36
67
 
37
- case access
38
- when Redd::OAuth2Access
68
+ case token
69
+ when nil
39
70
  access.refresh(response.body)
71
+ when Redd::OAuth2Access
72
+ token.refresh(response.body)
40
73
  when ::String
41
74
  new_access = Redd::OAuth2Access.new(response.body)
42
75
  @access = new_access if set_access
@@ -1,7 +1,11 @@
1
1
  module Redd
2
2
  module Client
3
3
  class OAuth2
4
+ # Methods to interact with the user logged-in via OAuth2
4
5
  module Identity
6
+ # @return [Redd::Object::User] The logged-in user.
7
+ # @note This overrides the Authenticated class's method, since that
8
+ # method doesn't apply here but does the same thing.
5
9
  def me
6
10
  response = get "/api/v1/me.json"
7
11
  object_from_body kind: "t2", data: response
@@ -1,10 +1,22 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Unauthenticated
4
+ # Methods for managing accounts.
4
5
  module Account
6
+ # Login to the reddit account.
7
+ #
8
+ # @param username [String] The username.
9
+ # @param password [String] The password.
10
+ # @param remember [Boolean] Indicates whether you intend to use the
11
+ # returned cookie for a long time.
12
+ # @param options [Hash] The options to create an instance of
13
+ # {Redd::Client::Authenticated}.
5
14
  def login(username, password, remember = false, options = {})
6
15
  response = post "/api/login",
7
- api_type: "json", user: username, passwd: password, rem: remember
16
+ api_type: "json",
17
+ user: username,
18
+ passwd: password,
19
+ rem: remember
8
20
  data = response[:json][:data]
9
21
 
10
22
  require "redd/client/authenticated"
@@ -1,16 +1,23 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Unauthenticated
4
+ # Methods to get captchas.
5
+ # Many things like sending messages and posting links require captchas.
4
6
  module Captcha
7
+ # @return [Boolean] Whether a captcha is required for some API methods.
5
8
  def needs_captcha?
6
9
  get "/api/needs_captcha.json"
7
10
  end
8
11
 
12
+ # Create a new captcha identifier.
13
+ # @return [String] The identifier.
9
14
  def new_captcha
10
15
  response = get "/api/new_captcha", api_type: "json"
11
16
  response[:json][:data][:iden]
12
17
  end
13
18
 
19
+ # @param identifier [String] The captcha identifier.
20
+ # @return The url for the captcha image.
14
21
  def captcha_url(identifier)
15
22
  "http://www.reddit.com/captcha/#{identifier}.png"
16
23
  end
@@ -2,20 +2,37 @@ module Redd
2
2
  module Client
3
3
  class Unauthenticated
4
4
  module LinksComments
5
+ # @param params [Hash] A hash of parameters to send to reddit.
6
+ # @option params [String] :id The fullname of a thing.
7
+ # @option params [String] :url The url of a thing. If an id is also
8
+ # provided, the id will take precedence.
9
+ # @return [Redd::Object::Submission, Redd::Object::Comment] The object.
10
+ #
5
11
  # @note Reddit does accept a subreddit, but with fullnames and urls, I
6
12
  # assumed that was unnecessary.
7
13
  def get_info(params = {})
8
- object_from_response :get, "/api/info.json", params
14
+ object = object_from_response :get, "/api/info.json", params
15
+ object.first
9
16
  end
10
17
 
18
+ # Get the comments for a submission.
19
+ #
20
+ # @param submission [String, Redd::Object::Submission] The submission
21
+ # to get the comments for.
22
+ # @return [Redd::Object::Listing] A listing of comments.
11
23
  def submission_comments(submission)
12
24
  id = extract_id(submission)
13
25
  comments_from_response :get, "/comments/#{id}.json"
14
26
  end
15
27
 
28
+ # Get the replies for a comment.
29
+ #
30
+ # @param comment [String, Redd::Object::Submission] The comment to get
31
+ # the replies for.
32
+ # @return [Redd::Object::Listing] A listing of comments.
16
33
  def get_replies(comment)
17
34
  replies = comment.attributes[:replies]
18
- return [] unless replies.is_a?(Hash) and replies.has_key?(:kind)
35
+ return [] unless replies.is_a?(Hash) && replies.key?(:kind)
19
36
  object_from_body(replies)
20
37
  end
21
38
 
@@ -30,8 +47,10 @@ module Redd
30
47
  get_info(id: parent_id).first.link_id
31
48
  end
32
49
 
33
- response = post "/api/morechildren", api_type: "json",
34
- link_id: link_id, children: morecomments.children.join(",")
50
+ response = post "/api/morechildren",
51
+ api_type: "json",
52
+ link_id: link_id,
53
+ children: morecomments.children.join(",")
35
54
  comments = response[:json][:data][:things]
36
55
 
37
56
  # No idea how to increase the depth of the comments.
@@ -1,38 +1,56 @@
1
1
  module Redd
2
2
  module Client
3
3
  class Unauthenticated
4
+ # Methods that return a listing
4
5
  module Listing
5
- def by_id(*fullnames)
6
- names = fullnames.join(",")
7
- object_from_response :get, "/by_id/#{names}.json"
6
+ # Get an object based on its id.
7
+ #
8
+ # @param fullname [String] The fullname of a thing.
9
+ # @return [Redd::Object] The object with the id.
10
+ def by_id(fullname)
11
+ object_from_response :get, "/by_id/#{fullname}.json"
8
12
  end
9
13
 
10
- def get_hot(*args)
11
- get_listing(:hot, *args)
12
- end
13
-
14
- def get_new(*args)
15
- get_listing(:new, *args)
16
- end
17
-
18
- def get_random(*args)
19
- get_listing(:random, *args)
20
- end
21
-
22
- def get_top(*args)
23
- get_listing(:top, *args)
24
- end
25
-
26
- def get_controversial(*args)
27
- get_listing(:controversial, *args)
28
- end
29
-
30
- def get_comments(*args)
31
- get_listing(:comments, *args)
14
+ # @!method get_hot
15
+ # @!method get_new
16
+ # @!method get_random
17
+ # @!method get_top
18
+ # @!method get_controversial
19
+ # @!method get_comments
20
+ #
21
+ # Get the appropriate listing.
22
+ # @param subreddit [Redd::Object::Subreddit] The subreddit to query.
23
+ # @param params [Hash] A list of params to send with the request.
24
+ #
25
+ # @see #get_listing
26
+ %w(hot new random top controversial comments).each do |sort|
27
+ define_method :"get_#{sort}" do |subreddit = nil, params = {}|
28
+ get_listing(sort, subreddit, params)
29
+ end
32
30
  end
33
31
 
34
32
  private
35
33
 
34
+ # Get the front page of reddit or a subreddit sorted by type.
35
+ #
36
+ # @param type [:hot, :new, :random, :top, :controversial, :comments]
37
+ # The type of listing to return
38
+ # @param subreddit [Redd::Object::Subreddit, String] The subreddit to
39
+ # query.
40
+ # @param params [Hash] A list of params to send with the request.
41
+ # @option params [String] :after Return results after the given
42
+ # fullname.
43
+ # @option params [String] :before Return results before the given
44
+ # fullname.
45
+ # @option params [Integer] :count (0) The number of items already seen
46
+ # in the listing.
47
+ # @option params [1..100] :limit (25) The maximum number of things to
48
+ # return.
49
+ # @option params [:hour, :day, :week, :month, :year, :all] :t The
50
+ # time period to consider when sorting.
51
+ # @return [Redd::Object::Listing] A listing of submissions or comments.
52
+ #
53
+ # @note The option :t only applies to the top and controversial sorts.
36
54
  def get_listing(type, subreddit = nil, params = {})
37
55
  name = extract_attribute(subreddit, :display_name) if subreddit
38
56