redd 0.7.8 → 0.7.9

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 (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