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