redd 0.7.8 → 0.7.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +34 -34
  3. data/.rspec +3 -3
  4. data/.rubocop.yml +5 -5
  5. data/.travis.yml +9 -9
  6. data/LICENSE.md +22 -22
  7. data/README.md +143 -143
  8. data/Rakefile +5 -5
  9. data/RedditKit.LICENSE.md +8 -8
  10. data/lib/redd.rb +50 -50
  11. data/lib/redd/access.rb +76 -76
  12. data/lib/redd/clients/base.rb +181 -181
  13. data/lib/redd/clients/base/account.rb +20 -20
  14. data/lib/redd/clients/base/identity.rb +22 -22
  15. data/lib/redd/clients/base/none.rb +27 -27
  16. data/lib/redd/clients/base/privatemessages.rb +33 -33
  17. data/lib/redd/clients/base/read.rb +113 -113
  18. data/lib/redd/clients/base/stream.rb +81 -81
  19. data/lib/redd/clients/base/submit.rb +19 -19
  20. data/lib/redd/clients/base/utilities.rb +104 -104
  21. data/lib/redd/clients/base/wikiread.rb +33 -33
  22. data/lib/redd/clients/installed.rb +56 -56
  23. data/lib/redd/clients/script.rb +41 -41
  24. data/lib/redd/clients/userless.rb +32 -32
  25. data/lib/redd/clients/web.rb +58 -58
  26. data/lib/redd/error.rb +151 -151
  27. data/lib/redd/objects/base.rb +39 -39
  28. data/lib/redd/objects/comment.rb +22 -22
  29. data/lib/redd/objects/labeled_multi.rb +13 -13
  30. data/lib/redd/objects/listing.rb +29 -29
  31. data/lib/redd/objects/more_comments.rb +11 -10
  32. data/lib/redd/objects/private_message.rb +28 -28
  33. data/lib/redd/objects/submission.rb +139 -139
  34. data/lib/redd/objects/subreddit.rb +330 -319
  35. data/lib/redd/objects/thing.rb +26 -26
  36. data/lib/redd/objects/thing/editable.rb +22 -22
  37. data/lib/redd/objects/thing/hideable.rb +18 -18
  38. data/lib/redd/objects/thing/inboxable.rb +25 -25
  39. data/lib/redd/objects/thing/messageable.rb +34 -34
  40. data/lib/redd/objects/thing/moderatable.rb +43 -43
  41. data/lib/redd/objects/thing/refreshable.rb +14 -14
  42. data/lib/redd/objects/thing/saveable.rb +21 -21
  43. data/lib/redd/objects/thing/votable.rb +33 -33
  44. data/lib/redd/objects/user.rb +52 -52
  45. data/lib/redd/objects/wiki_page.rb +15 -15
  46. data/lib/redd/rate_limit.rb +88 -88
  47. data/lib/redd/response/parse_json.rb +18 -18
  48. data/lib/redd/response/raise_error.rb +16 -16
  49. data/lib/redd/version.rb +4 -4
  50. data/redd.gemspec +31 -31
  51. data/spec/redd/objects/base_spec.rb +1 -1
  52. data/spec/redd/response/raise_error_spec.rb +11 -11
  53. data/spec/redd_spec.rb +5 -5
  54. data/spec/spec_helper.rb +71 -71
  55. metadata +21 -21
@@ -1,20 +1,20 @@
1
- module Redd
2
- module Clients
3
- class Base
4
- # Methods that require the "account" scope
5
- module Account
6
- # Edit some user preferences
7
- # @param [Hash] changed_prefs The preferences to override.
8
- # @return [Objects::Base] A Hashie-style container of the new prefs.
9
- # @see https://www.reddit.com/dev/api/oauth#PATCH_api_v1_me_prefs
10
- def edit_my_prefs(changed_prefs)
11
- response = connection.patch do |req|
12
- req.url "/api/v1/me/prefs"
13
- req.body = MultiJson.dump(changed_prefs)
14
- end
15
- Objects::Base.new(self, response.body)
16
- end
17
- end
18
- end
19
- end
20
- end
1
+ module Redd
2
+ module Clients
3
+ class Base
4
+ # Methods that require the "account" scope
5
+ module Account
6
+ # Edit some user preferences
7
+ # @param [Hash] changed_prefs The preferences to override.
8
+ # @return [Objects::Base] A Hashie-style container of the new prefs.
9
+ # @see https://www.reddit.com/dev/api/oauth#PATCH_api_v1_me_prefs
10
+ def edit_my_prefs(changed_prefs)
11
+ response = connection.patch do |req|
12
+ req.url "/api/v1/me/prefs"
13
+ req.body = MultiJson.dump(changed_prefs)
14
+ end
15
+ Objects::Base.new(self, response.body)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,22 +1,22 @@
1
- module Redd
2
- module Clients
3
- class Base
4
- # Methods that require the "identity" scope
5
- module Identity
6
- # @return [Objects::User] The logged-in user.
7
- def me
8
- response = get("/api/v1/me")
9
- object_from_body(kind: "t2", data: response.body)
10
- end
11
-
12
- # @return [Objects::Base] Your current preferences.
13
- # @see https://www.reddit.com/dev/api/oauth#GET_api_v1_me_prefs
14
- def my_prefs
15
- response = get("/api/v1/me/prefs")
16
- # Basically an uneditable mashie.
17
- Objects::Base.new(self, response.body)
18
- end
19
- end
20
- end
21
- end
22
- end
1
+ module Redd
2
+ module Clients
3
+ class Base
4
+ # Methods that require the "identity" scope
5
+ module Identity
6
+ # @return [Objects::User] The logged-in user.
7
+ def me
8
+ response = get("/api/v1/me")
9
+ object_from_body(kind: "t2", data: response.body)
10
+ end
11
+
12
+ # @return [Objects::Base] Your current preferences.
13
+ # @see https://www.reddit.com/dev/api/oauth#GET_api_v1_me_prefs
14
+ def my_prefs
15
+ response = get("/api/v1/me/prefs")
16
+ # Basically an uneditable mashie.
17
+ Objects::Base.new(self, response.body)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,27 +1,27 @@
1
- module Redd
2
- module Clients
3
- class Base
4
- # Methods that don't require any scope.
5
- module None
6
- # @return [Boolean] Whether a captcha is required for some API methods.
7
- def needs_captcha?
8
- get("/api/needs_captcha.json").body
9
- end
10
-
11
- # Create a new captcha identifier.
12
- # @return [String] The identifier.
13
- # @todo Maybe create some kind of set_captcha!(...) method for the
14
- # client to send automatically with the next response.
15
- def new_captcha
16
- post("/api/new_captcha").body[:json][:data][:iden]
17
- end
18
-
19
- # @param iden [String] The captcha identifier.
20
- # @return The url for the captcha image.
21
- def captcha_url(iden)
22
- "http://www.reddit.com/captcha/#{iden}.png"
23
- end
24
- end
25
- end
26
- end
27
- end
1
+ module Redd
2
+ module Clients
3
+ class Base
4
+ # Methods that don't require any scope.
5
+ module None
6
+ # @return [Boolean] Whether a captcha is required for some API methods.
7
+ def needs_captcha?
8
+ get("/api/needs_captcha.json").body
9
+ end
10
+
11
+ # Create a new captcha identifier.
12
+ # @return [String] The identifier.
13
+ # @todo Maybe create some kind of set_captcha!(...) method for the
14
+ # client to send automatically with the next response.
15
+ def new_captcha
16
+ post("/api/new_captcha").body[:json][:data][:iden]
17
+ end
18
+
19
+ # @param iden [String] The captcha identifier.
20
+ # @return The url for the captcha image.
21
+ def captcha_url(iden)
22
+ "http://www.reddit.com/captcha/#{iden}.png"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,33 +1,33 @@
1
- module Redd
2
- module Clients
3
- class Base
4
- # Methods that require the "privatemessages" scope
5
- module Privatemessages
6
- # Return a listing of a user's private messages.
7
- #
8
- # @param category ["inbox", "unread", "sent"] The category of messages
9
- # to view.
10
- # @param mark [Boolean] Whether to remove the orangered from the
11
- # user's inbox.
12
- # @param params [Hash] A list of params to send with the request.
13
- # @option params [String] :after Return results after the given
14
- # fullname.
15
- # @option params [String] :before Return results before the given
16
- # fullname.
17
- # @option params [Integer] :count (0) The number of items already seen
18
- # in the listing.
19
- # @option params [1..100] :limit (25) The maximum number of things to
20
- # return.
21
- def my_messages(category = "inbox", mark = false, params = {})
22
- params[:mark] = mark
23
- request_object(:get, "/message/#{category}.json", params)
24
- end
25
-
26
- # Mark all messages as read.
27
- def read_all_messages
28
- post("/api/read_all_messages")
29
- end
30
- end
31
- end
32
- end
33
- end
1
+ module Redd
2
+ module Clients
3
+ class Base
4
+ # Methods that require the "privatemessages" scope
5
+ module Privatemessages
6
+ # Return a listing of a user's private messages.
7
+ #
8
+ # @param category ["inbox", "unread", "sent"] The category of messages
9
+ # to view.
10
+ # @param mark [Boolean] Whether to remove the orangered from the
11
+ # user's inbox.
12
+ # @param params [Hash] A list of params to send with the request.
13
+ # @option params [String] :after Return results after the given
14
+ # fullname.
15
+ # @option params [String] :before Return results before the given
16
+ # fullname.
17
+ # @option params [Integer] :count (0) The number of items already seen
18
+ # in the listing.
19
+ # @option params [1..100] :limit (25) The maximum number of things to
20
+ # return.
21
+ def my_messages(category = "inbox", mark = false, params = {})
22
+ params[:mark] = mark
23
+ request_object(:get, "/message/#{category}.json", params)
24
+ end
25
+
26
+ # Mark all messages as read.
27
+ def read_all_messages
28
+ post("/api/read_all_messages")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,113 +1,113 @@
1
- module Redd
2
- module Clients
3
- class Base
4
- # Methods that require the "read" scope
5
- module Read
6
- # @param [Array<String>] fnames A list of fullnames.
7
- # @return [Objects::Listing<Objects::Thing>] A listing of things with
8
- # the fullname.
9
- def from_fullname(*fnames)
10
- names = fnames.join(",")
11
- request_object(:get, "/api/info", id: names)
12
- end
13
-
14
- # @param [String] url The url of the thing.
15
- # @return [Objects::Thing] The thing.
16
- def from_url(url)
17
- request_object(:get, "/api/info", url: url).first
18
- end
19
-
20
- # @param [String] name The username.
21
- # @return [Objects::User] The user.
22
- def user_from_name(name)
23
- request_object(:get, "/user/#{name}/about.json")
24
- end
25
-
26
- # @param [String] name The subreddit's display name.
27
- # @return [Objects::Subreddit] The subreddit if found.
28
- def subreddit_from_name(name)
29
- request_object(:get, "/r/#{name}/about.json")
30
- end
31
-
32
- # Fetch a list of multis belonging to the user.
33
- def my_multis
34
- multis = get("/api/multi/mine").body
35
- multis.map { |thing| object_from_body(thing) }
36
- end
37
-
38
- # Fetch an individual multi from its path.
39
- # @param [String] path The multi's path.
40
- # @return [Objects::LabeledMulti]
41
- def multi_from_path(path)
42
- without_slash = path.gsub(/^\//, "")
43
- request_object(:get, "/api/multi/" + without_slash)
44
- end
45
-
46
- # @!method get_hot(subreddit = nil, **params)
47
- # @!method get_new(subreddit = nil, **params)
48
- # @!method get_top(subreddit = nil, **params)
49
- # @!method get_controversial(subreddit = nil, **params)
50
- # @!method get_comments(subreddit = nil, **params)
51
- #
52
- # Get the appropriate listing.
53
- # @param subreddit [Objects::Subreddit, String] The subreddit to query.
54
- # @param params [Hash] A list of params to send with the request.
55
- # @option params [String] :after Return results after the given
56
- # fullname.
57
- # @option params [String :before Return results before the given
58
- # fullname.
59
- # @option params [Integer] :count The number of items already seen in
60
- # the listing.
61
- # @option params [1..100] :limit The maximum number of things to
62
- # return.
63
- # @option params [:hour, :day, :week, :month, :year, :all] :t The
64
- # time period to consider when sorting.
65
- #
66
- # @note The option :t only applies to the top and controversial sorts.
67
- # @return [Objects::Listing<Objects::Thing>]
68
- # @todo Move all listing methods into a helper?
69
- %w(hot new top controversial comments).each do |sort|
70
- define_method :"get_#{sort}" do |subreddit = nil, **params|
71
- srname = property(subreddit, :display_name) if subreddit
72
- path = "/#{sort}.json"
73
- path = path.prepend("/r/#{srname}") if subreddit
74
- request_object(:get, path, params)
75
- end
76
- end
77
-
78
- # Search.
79
- # @param query [String] The query string.
80
- # @param subreddit [Objects::Subreddit, String] The subreddit to query.
81
- # @param params [Hash] A list of params to send with the request.
82
- # @option params [String] :after Return results after the given
83
- # fullname.
84
- # @option params [String] :before Return results before the given
85
- # fullname.
86
- # @option params [Integer] :count The number of items already seen in
87
- # the listing.
88
- # @option params [1..100] :limit The maximum number of things to
89
- # return.
90
- # @option params [:cloudsearch, :lucene, :plain] :syntax The type of
91
- # syntax to use.
92
- # @option params [:relevance, :new, :hot, :top, :comments] :sort The
93
- # way to sort the results.
94
- # @option params [:hour, :day, :week, :month, :year, :all] :t The
95
- # time period to consider when sorting.
96
- #
97
- # @note The option :t only applies to the top and controversial sorts.
98
- # @return [Objects::Listing<Objects::Thing>]
99
- def search(query, subreddit = nil, **params)
100
- path = "/search.json"
101
- params[:q] = query
102
- if subreddit
103
- params[:restrict_sr] = true
104
- srname = property(subreddit, :display_name)
105
- path = path.prepend("/r/#{srname}")
106
- end
107
-
108
- request_object(:get, path, params)
109
- end
110
- end
111
- end
112
- end
113
- end
1
+ module Redd
2
+ module Clients
3
+ class Base
4
+ # Methods that require the "read" scope
5
+ module Read
6
+ # @param [Array<String>] fnames A list of fullnames.
7
+ # @return [Objects::Listing<Objects::Thing>] A listing of things with
8
+ # the fullname.
9
+ def from_fullname(*fnames)
10
+ names = fnames.join(",")
11
+ request_object(:get, "/api/info", id: names)
12
+ end
13
+
14
+ # @param [String] url The url of the thing.
15
+ # @return [Objects::Thing] The thing.
16
+ def from_url(url)
17
+ request_object(:get, "/api/info", url: url).first
18
+ end
19
+
20
+ # @param [String] name The username.
21
+ # @return [Objects::User] The user.
22
+ def user_from_name(name)
23
+ request_object(:get, "/user/#{name}/about.json")
24
+ end
25
+
26
+ # @param [String] name The subreddit's display name.
27
+ # @return [Objects::Subreddit] The subreddit if found.
28
+ def subreddit_from_name(name)
29
+ request_object(:get, "/r/#{name}/about.json")
30
+ end
31
+
32
+ # Fetch a list of multis belonging to the user.
33
+ def my_multis
34
+ multis = get("/api/multi/mine").body
35
+ multis.map { |thing| object_from_body(thing) }
36
+ end
37
+
38
+ # Fetch an individual multi from its path.
39
+ # @param [String] path The multi's path.
40
+ # @return [Objects::LabeledMulti]
41
+ def multi_from_path(path)
42
+ without_slash = path.gsub(/^\//, "")
43
+ request_object(:get, "/api/multi/" + without_slash)
44
+ end
45
+
46
+ # @!method get_hot(subreddit = nil, **params)
47
+ # @!method get_new(subreddit = nil, **params)
48
+ # @!method get_top(subreddit = nil, **params)
49
+ # @!method get_controversial(subreddit = nil, **params)
50
+ # @!method get_comments(subreddit = nil, **params)
51
+ #
52
+ # Get the appropriate listing.
53
+ # @param subreddit [Objects::Subreddit, String] The subreddit to query.
54
+ # @param params [Hash] A list of params to send with the request.
55
+ # @option params [String] :after Return results after the given
56
+ # fullname.
57
+ # @option params [String :before Return results before the given
58
+ # fullname.
59
+ # @option params [Integer] :count The number of items already seen in
60
+ # the listing.
61
+ # @option params [1..100] :limit The maximum number of things to
62
+ # return.
63
+ # @option params [:hour, :day, :week, :month, :year, :all] :t The
64
+ # time period to consider when sorting.
65
+ #
66
+ # @note The option :t only applies to the top and controversial sorts.
67
+ # @return [Objects::Listing<Objects::Thing>]
68
+ # @todo Move all listing methods into a helper?
69
+ %w(hot new top controversial comments).each do |sort|
70
+ define_method :"get_#{sort}" do |subreddit = nil, **params|
71
+ srname = property(subreddit, :display_name) if subreddit
72
+ path = "/#{sort}.json"
73
+ path = path.prepend("/r/#{srname}") if subreddit
74
+ request_object(:get, path, params)
75
+ end
76
+ end
77
+
78
+ # Search.
79
+ # @param query [String] The query string.
80
+ # @param subreddit [Objects::Subreddit, String] The subreddit to query.
81
+ # @param params [Hash] A list of params to send with the request.
82
+ # @option params [String] :after Return results after the given
83
+ # fullname.
84
+ # @option params [String] :before Return results before the given
85
+ # fullname.
86
+ # @option params [Integer] :count The number of items already seen in
87
+ # the listing.
88
+ # @option params [1..100] :limit The maximum number of things to
89
+ # return.
90
+ # @option params [:cloudsearch, :lucene, :plain] :syntax The type of
91
+ # syntax to use.
92
+ # @option params [:relevance, :new, :hot, :top, :comments] :sort The
93
+ # way to sort the results.
94
+ # @option params [:hour, :day, :week, :month, :year, :all] :t The
95
+ # time period to consider when sorting.
96
+ #
97
+ # @note The option :t only applies to the top and controversial sorts.
98
+ # @return [Objects::Listing<Objects::Thing>]
99
+ def search(query, subreddit = nil, **params)
100
+ path = "/search.json"
101
+ params[:q] = query
102
+ if subreddit
103
+ params[:restrict_sr] = true
104
+ srname = property(subreddit, :display_name)
105
+ path = path.prepend("/r/#{srname}")
106
+ end
107
+
108
+ request_object(:get, path, params)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -1,81 +1,81 @@
1
- require "set"
2
-
3
- module Redd
4
- module Clients
5
- class Base
6
- # Methods that stream delicious content into your bot's lazy mouth.
7
- module Stream
8
- # A class similar to PRAW's implementation of a BoundedSet.
9
- class PRAWBoundedQueueSet < Set
10
- def initialize(max, *args, &block)
11
- @max = max
12
- @queue = []
13
- super(*args, &block)
14
- end
15
-
16
- # Add an element to the front if it isn't already in the queue.
17
- # @param element
18
- # @return [PRAWBoundedQueueSet] self
19
- def enqueue(element)
20
- @queue.push(element) if add?(element)
21
- dequeue! if size > @max
22
- self
23
- end
24
- alias_method :enq, :enqueue
25
-
26
- # Add an element to the front if it isn't already in the queue.
27
- # @param element
28
- # @return [Boolean] Whether the element was added to the queue.
29
- def enqueue?(element)
30
- added = add?(element)
31
- if added
32
- @queue.push(element)
33
- dequeue if size > @max
34
- end
35
- added
36
- end
37
- alias_method :enq?, :enqueue?
38
-
39
- # Remove the last element of the queue.
40
- # @return The removed element.
41
- def dequeue
42
- element = @queue.shift
43
- delete(element)
44
- element
45
- end
46
- alias_method :deq, :dequeue
47
- end
48
-
49
- # Stream the results of a method call to the given block.
50
- # @param [Symbol] meth A method that returns a listing and has a
51
- # keyword parameter named `:before`.
52
- # @param [Array] args The arguments supplied to the method.
53
- # @param [Hash] kwargs The keyword arguments supplied to the method.
54
- # @yield An element of the returned listing.
55
- def stream(meth = :get_new, *args, **kwargs)
56
- bset = PRAWBoundedQueueSet.new(10)
57
- before = ""
58
- loop do
59
- begin
60
- # Get the latest comments from the subreddit.
61
- params = kwargs.merge(before: before)
62
- listing = send(meth, *args, **params)
63
- # Run the loop for each of the item in the listing
64
- listing.reverse_each do |thing|
65
- yield thing if bset.enqueue?(thing.fullname)
66
- end
67
- # Set the latest comment.
68
- before = listing.first.fullname unless listing.empty?
69
- rescue Redd::Error::RateLimited => error
70
- # If this error pops up, you probably have an issue with your bot.
71
- sleep(error.time)
72
- rescue Redd::Error => error
73
- # 5-something errors are usually errors on reddit's end.
74
- raise error unless (500...600).include?(error.code)
75
- end
76
- end
77
- end
78
- end # <- See, this is why I sometimes prefer Python.
79
- end # <- Thank god for code folding.
80
- end
81
- end
1
+ require "set"
2
+
3
+ module Redd
4
+ module Clients
5
+ class Base
6
+ # Methods that stream delicious content into your bot's lazy mouth.
7
+ module Stream
8
+ # A class similar to PRAW's implementation of a BoundedSet.
9
+ class PRAWBoundedQueueSet < Set
10
+ def initialize(max, *args, &block)
11
+ @max = max
12
+ @queue = []
13
+ super(*args, &block)
14
+ end
15
+
16
+ # Add an element to the front if it isn't already in the queue.
17
+ # @param element
18
+ # @return [PRAWBoundedQueueSet] self
19
+ def enqueue(element)
20
+ @queue.push(element) if add?(element)
21
+ dequeue! if size > @max
22
+ self
23
+ end
24
+ alias_method :enq, :enqueue
25
+
26
+ # Add an element to the front if it isn't already in the queue.
27
+ # @param element
28
+ # @return [Boolean] Whether the element was added to the queue.
29
+ def enqueue?(element)
30
+ added = add?(element)
31
+ if added
32
+ @queue.push(element)
33
+ dequeue if size > @max
34
+ end
35
+ added
36
+ end
37
+ alias_method :enq?, :enqueue?
38
+
39
+ # Remove the last element of the queue.
40
+ # @return The removed element.
41
+ def dequeue
42
+ element = @queue.shift
43
+ delete(element)
44
+ element
45
+ end
46
+ alias_method :deq, :dequeue
47
+ end
48
+
49
+ # Stream the results of a method call to the given block.
50
+ # @param [Symbol] meth A method that returns a listing and has a
51
+ # keyword parameter named `:before`.
52
+ # @param [Array] args The arguments supplied to the method.
53
+ # @param [Hash] kwargs The keyword arguments supplied to the method.
54
+ # @yield An element of the returned listing.
55
+ def stream(meth = :get_new, *args, **kwargs)
56
+ bset = PRAWBoundedQueueSet.new(10)
57
+ before = ""
58
+ loop do
59
+ begin
60
+ # Get the latest comments from the subreddit.
61
+ params = kwargs.merge(before: before)
62
+ listing = send(meth, *args, **params)
63
+ # Run the loop for each of the item in the listing
64
+ listing.reverse_each do |thing|
65
+ yield thing if bset.enqueue?(thing.fullname)
66
+ end
67
+ # Set the latest comment.
68
+ before = listing.first.fullname unless listing.empty?
69
+ rescue Redd::Error::RateLimited => error
70
+ # If this error pops up, you probably have an issue with your bot.
71
+ sleep(error.time)
72
+ rescue Redd::Error => error
73
+ # 5-something errors are usually errors on reddit's end.
74
+ raise error unless (500...600).include?(error.code)
75
+ end
76
+ end
77
+ end
78
+ end # <- See, this is why I sometimes prefer Python.
79
+ end # <- Thank god for code folding.
80
+ end
81
+ end