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.
- checksums.yaml +4 -4
- data/README.md +7 -12
- data/lib/redd.rb +0 -12
- data/lib/redd/base.rb +10 -6
- data/lib/redd/client/authenticated.rb +2 -1
- data/lib/redd/client/authenticated/account.rb +2 -0
- data/lib/redd/client/authenticated/apps.rb +1 -0
- data/lib/redd/client/authenticated/flair.rb +33 -7
- data/lib/redd/client/authenticated/gold.rb +1 -0
- data/lib/redd/client/authenticated/links_comments.rb +86 -10
- data/lib/redd/client/authenticated/live.rb +1 -0
- data/lib/redd/client/authenticated/moderation.rb +65 -16
- data/lib/redd/client/authenticated/multis.rb +1 -1
- data/lib/redd/client/authenticated/private_messages.rb +50 -4
- data/lib/redd/client/authenticated/subreddits.rb +28 -0
- data/lib/redd/client/authenticated/users.rb +1 -1
- data/lib/redd/client/authenticated/wiki.rb +1 -1
- data/lib/redd/client/oauth2.rb +2 -2
- data/lib/redd/client/oauth2/authorization.rb +44 -11
- data/lib/redd/client/oauth2/identity.rb +4 -0
- data/lib/redd/client/unauthenticated/account.rb +13 -1
- data/lib/redd/client/unauthenticated/captcha.rb +7 -0
- data/lib/redd/client/unauthenticated/links_comments.rb +23 -4
- data/lib/redd/client/unauthenticated/listing.rb +43 -25
- data/lib/redd/client/unauthenticated/live.rb +1 -0
- data/lib/redd/client/unauthenticated/moderation.rb +9 -1
- data/lib/redd/client/unauthenticated/subreddits.rb +30 -0
- data/lib/redd/client/unauthenticated/utilities.rb +7 -4
- data/lib/redd/client/unauthenticated/wiki.rb +18 -4
- data/lib/redd/error.rb +5 -3
- data/lib/redd/oauth2_access.rb +21 -3
- data/lib/redd/object/more_comments.rb +1 -0
- data/lib/redd/object/private_message.rb +2 -1
- data/lib/redd/object/submission.rb +4 -0
- data/lib/redd/object/user.rb +1 -0
- data/lib/redd/response/raise_error.rb +2 -1
- data/lib/redd/thing/editable.rb +1 -0
- data/lib/redd/thing/hideable.rb +1 -0
- data/lib/redd/thing/inboxable.rb +1 -0
- data/lib/redd/thing/messageable.rb +2 -8
- data/lib/redd/thing/moderatable.rb +1 -0
- data/lib/redd/thing/reportable.rb +1 -0
- data/lib/redd/thing/saveable.rb +1 -0
- data/lib/redd/thing/voteable.rb +1 -1
- data/lib/redd/version.rb +1 -1
- data/spec/redd/client/unauthenticated_spec.rb +1 -1
- data/spec/redd/rate_limit_spec.rb +5 -5
- data/spec/redd_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +2 -3
- data/github/redd.png +0 -0
@@ -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/#{
|
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
|
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
|
-
|
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
|
-
|
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.
|
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/#{
|
14
|
+
path.prepend("/r/#{name}") if subreddit
|
8
15
|
get(path)[:data]
|
9
16
|
end
|
10
17
|
|
11
|
-
|
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/#{
|
14
|
-
object_from_response :get, path
|
27
|
+
path.prepend("/r/#{name}") if subreddit
|
28
|
+
object_from_response :get, path
|
15
29
|
end
|
16
30
|
end
|
17
31
|
end
|
data/lib/redd/error.rb
CHANGED
@@ -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
|
-
#
|
16
|
-
def from_response(response)
|
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
|
|
data/lib/redd/oauth2_access.rb
CHANGED
@@ -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
|
@@ -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, :
|
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
|
data/lib/redd/object/user.rb
CHANGED
@@ -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
|
-
|
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)
|
data/lib/redd/thing/editable.rb
CHANGED
data/lib/redd/thing/hideable.rb
CHANGED
data/lib/redd/thing/inboxable.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/redd/thing/saveable.rb
CHANGED
data/lib/redd/thing/voteable.rb
CHANGED
data/lib/redd/version.rb
CHANGED
@@ -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
|