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,32 +1,32 @@
1
- require_relative "base"
2
-
3
- module Redd
4
- module Clients
5
- # The client that doesn't need a user to function.
6
- # @note Of course, that means many editing methods throw an error.
7
- class Userless < Base
8
- # @!attribute [r] client_id
9
- attr_reader :client_id
10
-
11
- # @param [Hash] options The options to create the client with.
12
- # @see Base#initialize
13
- # @see Redd.it
14
- def initialize(client_id, secret, **options)
15
- @client_id = client_id
16
- @secret = secret
17
- super(**options)
18
- end
19
-
20
- # Authorize using the given data.
21
- # @return [Access] The access given by reddit.
22
- def authorize!
23
- response = auth_connection.post(
24
- "/api/v1/access_token",
25
- grant_type: "client_credentials"
26
- )
27
-
28
- @access = Access.new(response.body)
29
- end
30
- end
31
- end
32
- end
1
+ require_relative "base"
2
+
3
+ module Redd
4
+ module Clients
5
+ # The client that doesn't need a user to function.
6
+ # @note Of course, that means many editing methods throw an error.
7
+ class Userless < Base
8
+ # @!attribute [r] client_id
9
+ attr_reader :client_id
10
+
11
+ # @param [Hash] options The options to create the client with.
12
+ # @see Base#initialize
13
+ # @see Redd.it
14
+ def initialize(client_id, secret, **options)
15
+ @client_id = client_id
16
+ @secret = secret
17
+ super(**options)
18
+ end
19
+
20
+ # Authorize using the given data.
21
+ # @return [Access] The access given by reddit.
22
+ def authorize!
23
+ response = auth_connection.post(
24
+ "/api/v1/access_token",
25
+ grant_type: "client_credentials"
26
+ )
27
+
28
+ @access = Access.new(response.body)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,58 +1,58 @@
1
- require "uri"
2
- require_relative "base"
3
-
4
- module Redd
5
- module Clients
6
- # The client for a web-based flow (e.g. "login with reddit")
7
- class Web < Base
8
- # @!attribute [r] client_id
9
- attr_reader :client_id
10
-
11
- # @!attribute [r] redirect_uri
12
- attr_reader :redirect_uri
13
-
14
- # @param [Hash] options The options to create the client with.
15
- # @see Base#initialize
16
- # @see Redd.it
17
- def initialize(client_id, secret, redirect_uri, **options)
18
- @client_id = client_id
19
- @secret = secret
20
- @redirect_uri = redirect_uri
21
- super(**options)
22
- end
23
-
24
- # @param [String] state A random string to double-check later.
25
- # @param [Array<String>] scope The scope to request access to.
26
- # @param [:temporary, :permanent] duration
27
- # @return [String] The url to redirect the user to.
28
- def auth_url(state, scope = ["identity"], duration = :temporary)
29
- query = {
30
- response_type: "code",
31
- client_id: @client_id,
32
- redirect_uri: @redirect_uri,
33
- state: state,
34
- scope: scope.join(","),
35
- duration: duration
36
- }
37
-
38
- url = URI.join(auth_endpoint, "/api/v1/authorize")
39
- url.query = URI.encode_www_form(query)
40
- url.to_s
41
- end
42
-
43
- # Authorize using the code given.
44
- # @param [String] code The code from the get params.
45
- # @return [Access] The access given by reddit.
46
- def authorize!(code)
47
- response = auth_connection.post(
48
- "/api/v1/access_token",
49
- grant_type: "authorization_code",
50
- code: code,
51
- redirect_uri: @redirect_uri
52
- )
53
-
54
- @access = Access.new(response.body)
55
- end
56
- end
57
- end
58
- end
1
+ require "uri"
2
+ require_relative "base"
3
+
4
+ module Redd
5
+ module Clients
6
+ # The client for a web-based flow (e.g. "login with reddit")
7
+ class Web < Base
8
+ # @!attribute [r] client_id
9
+ attr_reader :client_id
10
+
11
+ # @!attribute [r] redirect_uri
12
+ attr_reader :redirect_uri
13
+
14
+ # @param [Hash] options The options to create the client with.
15
+ # @see Base#initialize
16
+ # @see Redd.it
17
+ def initialize(client_id, secret, redirect_uri, **options)
18
+ @client_id = client_id
19
+ @secret = secret
20
+ @redirect_uri = redirect_uri
21
+ super(**options)
22
+ end
23
+
24
+ # @param [String] state A random string to double-check later.
25
+ # @param [Array<String>] scope The scope to request access to.
26
+ # @param [:temporary, :permanent] duration
27
+ # @return [String] The url to redirect the user to.
28
+ def auth_url(state, scope = ["identity"], duration = :temporary)
29
+ query = {
30
+ response_type: "code",
31
+ client_id: @client_id,
32
+ redirect_uri: @redirect_uri,
33
+ state: state,
34
+ scope: scope.join(","),
35
+ duration: duration
36
+ }
37
+
38
+ url = URI.join(auth_endpoint, "/api/v1/authorize")
39
+ url.query = URI.encode_www_form(query)
40
+ url.to_s
41
+ end
42
+
43
+ # Authorize using the code given.
44
+ # @param [String] code The code from the get params.
45
+ # @return [Access] The access given by reddit.
46
+ def authorize!(code)
47
+ response = auth_connection.post(
48
+ "/api/v1/access_token",
49
+ grant_type: "authorization_code",
50
+ code: code,
51
+ redirect_uri: @redirect_uri
52
+ )
53
+
54
+ @access = Access.new(response.body)
55
+ end
56
+ end
57
+ end
58
+ end
data/lib/redd/error.rb CHANGED
@@ -1,151 +1,151 @@
1
- module Redd
2
- # An error from reddit
3
- # TODO: Move Error to an Errors module in next minor version?
4
- class Error < StandardError
5
- attr_reader :code
6
- attr_reader :headers
7
- attr_reader :body
8
-
9
- def initialize(env)
10
- @code = env[:status]
11
- @headers = env[:response_headers]
12
- @body = env[:body]
13
- end
14
-
15
- def self.from_response(env) # rubocop:disable all
16
- status = env[:status]
17
- body = parse_error(env[:body]).to_s
18
- case status
19
- when 200
20
- case body
21
- when /access_denied/i then OAuth2AccessDenied
22
- when /unsupported_response_type/i then InvalidResponseType
23
- when /unsupported_grant_type/i then InvalidGrantType
24
- when /invalid_scope/i then InvalidScope
25
- when /invalid_request/i then InvalidRequest
26
- when /no_text/i then NoTokenGiven
27
- when /invalid_grant/i then ExpiredCode
28
- when /wrong_password/i then InvalidCredentials
29
- when /bad_captcha/i then InvalidCaptcha
30
- when /ratelimit/i then RateLimited
31
- when /quota_filled/i then QuotaFilled
32
- when /bad_css_name/i then InvalidClassName
33
- when /too_old/i then Archived
34
- when /too_much_flair_css/i then TooManyClassNames
35
- when /user_required/i then AuthenticationRequired
36
- end
37
- when 400 then BadRequest
38
- when 401 then InvalidOAuth2Credentials
39
- when 403
40
- if /user_required/i =~ body
41
- AuthenticationRequired
42
- else
43
- PermissionDenied
44
- end
45
- when 404 then NotFound
46
- when 409 then Conflict
47
- when 500 then InternalServerError
48
- when 502 then BadGateway
49
- when 503 then ServiceUnavailable
50
- when 504 then TimedOut
51
- end
52
- end
53
-
54
- def self.parse_error(body) # rubocop:disable all
55
- return body unless body.is_a?(Hash)
56
-
57
- if body.key?(:json) && body[:json].key?(:errors)
58
- body[:json][:errors].first
59
- elsif body.key?(:jquery)
60
- body[:jquery]
61
- elsif body.key?(:error)
62
- body[:error]
63
- elsif body.key?(:code) && body[:code] == "NO_TEXT"
64
- "NO_TEXT"
65
- end
66
- end
67
-
68
- # This item has been archived and can no longer be edited.
69
- Archived = Class.new(Error)
70
-
71
- AuthenticationRequired = Class.new(Error)
72
-
73
- # Bad Gateway. Either a network or a reddit error. Either way, try again.
74
- BadGateway = Class.new(Error)
75
-
76
- BadRequest = Class.new(Error)
77
-
78
- Conflict = Class.new(Error)
79
-
80
- # You already received an access token using this code. The user should
81
- # grant you access again to get a new code.
82
- ExpiredCode = Class.new(Error)
83
-
84
- # There is an issue on reddit's end. Try again.
85
- InternalServerError = Class.new(Error)
86
-
87
- InvalidCaptcha = Class.new(Error)
88
-
89
- InvalidClassName = Class.new(Error)
90
-
91
- # Either your username or your password is wrong.
92
- InvalidCredentials = Class.new(Error)
93
-
94
- InvalidGrantType = Class.new(Error)
95
-
96
- InvalidMultiredditName = Class.new(Error)
97
-
98
- # Your client id or your secret is wrong.
99
- InvalidOAuth2Credentials = Class.new(Error)
100
-
101
- InvalidResponseType = Class.new(Error)
102
-
103
- InvalidRequest = Class.new(Error)
104
-
105
- # You don't have the proper scope to perform this request.
106
- InvalidScope = Class.new(Error)
107
-
108
- # Looks like we didn't get a JSON response. Raise this error.
109
- JSONError = Class.new(Error)
110
-
111
- # Four, oh four! The thing you're looking for wasn't found.
112
- NotFound = Class.new(Error)
113
-
114
- # No access token was given.
115
- NoTokenGiven = Class.new(Error)
116
-
117
- OAuth2AccessDenied = Class.new(Error)
118
-
119
- PermissionDenied = Class.new(Error)
120
-
121
- # Raised when the client needs to wait before making another request
122
- class RateLimited < Error
123
- # @!attribute [r] time
124
- # @return [Integer] the seconds to wait before making another request.
125
- attr_reader :time
126
-
127
- def initialize(env)
128
- super
129
- @time = env[:body][:json][:ratelimit] || 3600
130
- end
131
- end
132
-
133
- # This seems to be a more OAuth2-focused error.
134
- class QuotaFilled < RateLimited
135
- def initialize(env)
136
- super
137
- @time = 3600
138
- end
139
- end
140
-
141
- RequestError = Class.new(Error)
142
-
143
- # Issue on reddit's end. Try again.
144
- ServiceUnavailable = Class.new(Error)
145
-
146
- # The connection timed out. Try again.
147
- TimedOut = Class.new(Error)
148
-
149
- TooManyClassNames = Class.new(Error)
150
- end
151
- end
1
+ module Redd
2
+ # An error from reddit
3
+ # TODO: Move Error to an Errors module in next minor version?
4
+ class Error < StandardError
5
+ attr_reader :code
6
+ attr_reader :headers
7
+ attr_reader :body
8
+
9
+ def initialize(env)
10
+ @code = env[:status]
11
+ @headers = env[:response_headers]
12
+ @body = env[:body]
13
+ end
14
+
15
+ def self.from_response(env) # rubocop:disable all
16
+ status = env[:status]
17
+ body = parse_error(env[:body]).to_s
18
+ case status
19
+ when 200
20
+ case body
21
+ when /access_denied/i then OAuth2AccessDenied
22
+ when /unsupported_response_type/i then InvalidResponseType
23
+ when /unsupported_grant_type/i then InvalidGrantType
24
+ when /invalid_scope/i then InvalidScope
25
+ when /invalid_request/i then InvalidRequest
26
+ when /no_text/i then NoTokenGiven
27
+ when /invalid_grant/i then ExpiredCode
28
+ when /wrong_password/i then InvalidCredentials
29
+ when /bad_captcha/i then InvalidCaptcha
30
+ when /ratelimit/i then RateLimited
31
+ when /quota_filled/i then QuotaFilled
32
+ when /bad_css_name/i then InvalidClassName
33
+ when /too_old/i then Archived
34
+ when /too_much_flair_css/i then TooManyClassNames
35
+ when /user_required/i then AuthenticationRequired
36
+ end
37
+ when 400 then BadRequest
38
+ when 401 then InvalidOAuth2Credentials
39
+ when 403
40
+ if /user_required/i =~ body
41
+ AuthenticationRequired
42
+ else
43
+ PermissionDenied
44
+ end
45
+ when 404 then NotFound
46
+ when 409 then Conflict
47
+ when 500 then InternalServerError
48
+ when 502 then BadGateway
49
+ when 503 then ServiceUnavailable
50
+ when 504 then TimedOut
51
+ end
52
+ end
53
+
54
+ def self.parse_error(body) # rubocop:disable all
55
+ return body unless body.is_a?(Hash)
56
+
57
+ if body.key?(:json) && body[:json].key?(:errors)
58
+ body[:json][:errors].first
59
+ elsif body.key?(:jquery)
60
+ body[:jquery]
61
+ elsif body.key?(:error)
62
+ body[:error]
63
+ elsif body.key?(:code) && body[:code] == "NO_TEXT"
64
+ "NO_TEXT"
65
+ end
66
+ end
67
+
68
+ # This item has been archived and can no longer be edited.
69
+ Archived = Class.new(Error)
70
+
71
+ AuthenticationRequired = Class.new(Error)
72
+
73
+ # Bad Gateway. Either a network or a reddit error. Either way, try again.
74
+ BadGateway = Class.new(Error)
75
+
76
+ BadRequest = Class.new(Error)
77
+
78
+ Conflict = Class.new(Error)
79
+
80
+ # You already received an access token using this code. The user should
81
+ # grant you access again to get a new code.
82
+ ExpiredCode = Class.new(Error)
83
+
84
+ # There is an issue on reddit's end. Try again.
85
+ InternalServerError = Class.new(Error)
86
+
87
+ InvalidCaptcha = Class.new(Error)
88
+
89
+ InvalidClassName = Class.new(Error)
90
+
91
+ # Either your username or your password is wrong.
92
+ InvalidCredentials = Class.new(Error)
93
+
94
+ InvalidGrantType = Class.new(Error)
95
+
96
+ InvalidMultiredditName = Class.new(Error)
97
+
98
+ # Your client id or your secret is wrong.
99
+ InvalidOAuth2Credentials = Class.new(Error)
100
+
101
+ InvalidResponseType = Class.new(Error)
102
+
103
+ InvalidRequest = Class.new(Error)
104
+
105
+ # You don't have the proper scope to perform this request.
106
+ InvalidScope = Class.new(Error)
107
+
108
+ # Looks like we didn't get a JSON response. Raise this error.
109
+ JSONError = Class.new(Error)
110
+
111
+ # Four, oh four! The thing you're looking for wasn't found.
112
+ NotFound = Class.new(Error)
113
+
114
+ # No access token was given.
115
+ NoTokenGiven = Class.new(Error)
116
+
117
+ OAuth2AccessDenied = Class.new(Error)
118
+
119
+ PermissionDenied = Class.new(Error)
120
+
121
+ # Raised when the client needs to wait before making another request
122
+ class RateLimited < Error
123
+ # @!attribute [r] time
124
+ # @return [Integer] the seconds to wait before making another request.
125
+ attr_reader :time
126
+
127
+ def initialize(env)
128
+ super
129
+ @time = env[:body][:json][:ratelimit] || 3600
130
+ end
131
+ end
132
+
133
+ # This seems to be a more OAuth2-focused error.
134
+ class QuotaFilled < RateLimited
135
+ def initialize(env)
136
+ super
137
+ @time = 3600
138
+ end
139
+ end
140
+
141
+ RequestError = Class.new(Error)
142
+
143
+ # Issue on reddit's end. Try again.
144
+ ServiceUnavailable = Class.new(Error)
145
+
146
+ # The connection timed out. Try again.
147
+ TimedOut = Class.new(Error)
148
+
149
+ TooManyClassNames = Class.new(Error)
150
+ end
151
+ end