redd 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b44594ffd55f136e44b2ec3ee48fa04b2d69c611
4
- data.tar.gz: ed0efe9a7f3cf79b22aae8a3a8942cf1b6fc8699
3
+ metadata.gz: 6760b565561bde890fe1595ebda87ada31bae326
4
+ data.tar.gz: 7bccd9ea39fb2fa9d8201648d2c6164cab2791f6
5
5
  SHA512:
6
- metadata.gz: b7903c63b7044e3f4abb504d9c9ec93f1360622e744c4e88ec282d9bdf4438a448ed8b2c4810ee7861a45b32b2a6eef3f81e74b51e17885aac0c1f977bf97381
7
- data.tar.gz: 5f4142ff913b834502cbb0fe5d114c19a69c2cba1e7de735383baac3923040c4bc9e51302b5f183ef91532d7681d740968e346e9f51f846a30324ecb6f05a7cd
6
+ metadata.gz: 24762a4de14370f0d6cb4b9a79150c8d8db6f86a290d06edb82034e664f2b878cb48c37bf4a046fe5f03b23623bd8c6af2008ca9687154596da56bf34d522072
7
+ data.tar.gz: ba5116ceaa492bdefb12dcd626597fdf9989b301dcc66154240f844b38163cc944eb682290f0282bd9118785dd7919a1d87c1b343ab5071a3f4edf4e7847cc88
data/README.md CHANGED
@@ -1,16 +1,19 @@
1
1
  <p align="center">
2
2
  <img src="https://i.imgur.com/2JfE4M1.png" alt="redd"><br>
3
- <a href="http://badge.fury.io/rb/redd"><img src="https://badge.fury.io/rb/redd.svg" alt="Gem Version" height="18"></a>
4
- <a href="https://travis-ci.org/avidw/redd"><img src="https://travis-ci.org/avidw/redd.svg?branch=master" alt="Build Status"></a>
3
+ <a href="https://rubygems.org/gems/redd"><img src="http://img.shields.io/gem/v/redd.svg?style=flat-square" alt="Gem Version"></a>
4
+ <a href="https://travis-ci.org/avidw/redd"><img src="http://img.shields.io/travis/avidw/redd.svg?style=flat-square" alt="Build Status"></a>
5
+ <a href="https://rubygems.org/gems/redd"><img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="MIT License"></a>
6
+ <a href="https://rubygems.org/gems/redd"><img src="http://img.shields.io/gem/dt/redd.svg?style=flat-square" alt="Gem Downloads"></a>
5
7
  </p>
6
8
 
7
9
  **redd** is an API wrapper for [reddit](http://reddit.com/dev/api) written in ruby that focuses on being *simple and extensible*.
8
- Check out the latest documentation on [RubyDoc](http://rubydoc.info/github/avidw/redd/master/frames).
10
+ **Check out the latest documentation on [RubyDoc](http://rubydoc.info/github/avidw/redd/master/frames).**
9
11
 
10
12
  ---
11
13
 
12
14
  <p align="center">
13
15
  <a href="#getting-started">Getting Started</a> |
16
+ <a href="#oauth2">OAuth2</a> |
14
17
  <a href="#extending-redd">Extending Redd</a> |
15
18
  <a href="#supported-rubies">Supported Rubies</a> |
16
19
  <a href="#copyright">Copyright</a>
@@ -23,6 +26,7 @@ Ruby and redd make creating reddit bots accessible and fun. To demonstrate, let'
23
26
 
24
27
  1. **Installing**
25
28
  You can either install the gem directly by running `gem install redd` or by placing the gem into your `Gemfile` and running `bundle install`.
29
+
26
30
  ```ruby
27
31
  source "https://rubygems.org"
28
32
  gem "redd"
@@ -33,84 +37,189 @@ Ruby and redd make creating reddit bots accessible and fun. To demonstrate, let'
33
37
 
34
38
  2. **Setting Up**
35
39
  Let's load up redd and create a client for us to work with. (The username and password aren't real!)
40
+
36
41
  ```ruby
37
42
  require "redd"
38
43
  #=> true
39
44
 
40
- r = Redd.client "HelloWorldBot", "hunter2",
41
- user_agent: "HelloWorldBot v1.0 by /u/you"
45
+ r = Redd::Client::Authenticated.new_from_credentials "HelloWorldBot", "hunter2", user_agent: "HelloWorldBot v1.0 by /u/you"
42
46
  # => #<Redd::Client::Authenticated:0xY4D4y4D4y4dA ...
43
47
  ```
44
48
 
45
49
  3. **Scouting**
46
- Redd has a really cool method similar to praw's `helpers.comment_stream` that "streams" comments to you while avoiding duplicates. You won't have to take care of rate-limiting either; Redd `sleep`s after requests to avoid ratelimit errors. If you want to write a rate limiting class yourself, take a look at `lib/redd/rate_limit.rb`
50
+ Redd has a really cool method similar to praw's `helpers.comment_stream` that "streams" comments to you while avoiding duplicates. You won't have to take care of rate-limiting either; Redd `sleep`s after requests to avoid ratelimit errors. If you want to write a rate limiting class yourself, take a look at [`lib/redd/rate_limit.rb`](https://github.com/avidw/redd/blob/master/lib/redd/rate_limit.rb#L2-L23)
51
+
47
52
  ```ruby
48
53
  r.comment_stream "test" do |comment|
49
- comment.reply "World!" if comment.body =~ /^Hello\?$/i
54
+ comment.reply "World!" if comment.body =~ /^Hello\?$/i
50
55
  end
51
56
  ```
52
57
 
53
58
  4. **Just in Case**
54
59
  It's also a good idea to escape some common errors from reddit in case they happen:
60
+
55
61
  ```ruby
56
62
  begin
57
- r.comment_stream "test" do |comment|
58
- comment.reply "World!" if comment.body =~ /^Hello\?$/i
59
- end
60
- rescue Redd::Error::RateLimited => e
61
- time_left = e.time
62
- sleep(time_left)
63
- rescue Redd::Error => e
64
- status = e.code
65
- # 5-something errors are usually errors on reddit's end.
66
- raise e unless (500...600).include?(status)
63
+ r.comment_stream "test" do |comment|
64
+ comment.reply "World!" if comment.body =~ /^Hello\?$/i
65
+ end
66
+ rescue Redd::Error::RateLimited => e
67
+ time_left = e.time
68
+ sleep(time_left)
69
+ rescue Redd::Error => e
70
+ status = e.code
71
+ # 5-something errors are usually errors on reddit's end.
72
+ raise e unless (500...600).include?(status)
67
73
  end
68
74
  ```
69
75
 
76
+ ## OAuth2
77
+ Redd also provides a wrapper to connect to reddit via OAuth2. The client's methods are similar to the authenticated client, given that you have the required scopes. Refer to [reddit's api](https://www.reddit.com/dev/api/oauth) for the various scopes. Getting it running is really simple and can even be used to integrate reddit's features into a [**Rails**](https://github.com/rails/rails) application. Another plus is that logging in via OAuth2 lets you make twice as many requests without hitting a rate limit (1/second). Let's try logging into reddit with [**sinatra**](http://www.sinatrarb.com/).
78
+
79
+ The first thing you need to do is to create an OAuth2 application in reddit [**here**](https://ssl.reddit.com/prefs/apps). For more information, refer to [**"Getting Started"**](https://github.com/reddit/reddit/wiki/OAuth2#getting-started) on reddit's wiki.
80
+
81
+ Note: Although I enter the client id and secret in the code directly, I recommend you store them in environment variables or a **`.env`** file and load it with [**dotenv**](https://github.com/bkeepers/dotenv).
82
+
83
+ ```ruby
84
+ # config.ru
85
+
86
+ require "./connect_to_reddit"
87
+ run ConnectToReddit
88
+ ```
89
+
90
+ ```ruby
91
+ # connect_to_reddit.rb
92
+
93
+ require "sinatra/base"
94
+ require "redd"
95
+
96
+ class ConnectToReddit < Sinatra::Base
97
+ configure do
98
+ enable :sessions
99
+
100
+ # If you're on Rails, you can replace the fixed url with a named one (e.g. redirect_url).
101
+ set :client, Redd::Client::OAuth2.new("sa_xTDcJ3dWz0w", "very-sensitive-secret", "http://localhost:8080/auth/reddit/redirect")
102
+ end
103
+
104
+ get "/auth/reddit" do
105
+ # Make use of the state!
106
+ # SecureRandom, which is included in Ruby, helps create a url-safe random string.
107
+ state = SecureRandom.urlsafe_base64
108
+ session[:state] = state
109
+ redirect settings.client.auth_url(["identity"], :temporary, state)
110
+ end
111
+
112
+ get "/auth/reddit/redirect" do
113
+ raise "Your state doesn't match!" unless session[:state] == params[:state]
114
+
115
+ # access is a Redd::OAuth2Access object.
116
+ access = settings.client.request_access(params[:code])
117
+ me = settings.client.with_access(access) { |client| client.me }
118
+
119
+ # Now use the Redd::Object::User object to create a user, maybe assign some
120
+ # sort of token to remember their session.
121
+ redirect to("/success")
122
+ end
123
+ end
124
+ ```
125
+
126
+ Now let's run the application:
127
+
128
+ ```shell
129
+ $ rackup -p 8080
130
+ ```
131
+
132
+ #### Remember Me
133
+ If you want longer control of users' accounts for background tasks like auto-saving to a users' account behind the scenes or not have to ask your user to go through reddit every time, you can choose to have a permanent access by changing the second parameter of `auth_url`.
134
+
135
+ ```ruby
136
+ client = Redd::Client::OAuth2.new("sa_xTDcJ3dWz0w", "very-sensitive-secret", "http://localhost:8080/auth/reddit/redirect")
137
+ state = SecureRandom.urlsafe_base64
138
+ auth_url = client.auth_url(["identity"], :permanent, state)
139
+ ```
140
+
141
+ The access will still only last one hour, but you can refresh the access whenever you want.
142
+
143
+ ```ruby
144
+ access = client.request_access(params[:code])
145
+
146
+ # 1 hour or more later
147
+ client.refresh_access(access) if access.expired?
148
+ ```
149
+
150
+ Now if you are running a web application, you can't just store access tokens in memory. `Redd::OAuth2Access` offers a couple of methods for serializing the access to JSON and retrieving it.
151
+
152
+ ```ruby
153
+ json = access.to_json
154
+ current_user.update!(access: json) # Rails
155
+ redis.set("some-token", json) # Redis
156
+
157
+ # After some time
158
+ access = Redd::OAuth2Access.from_json(current_user.access)
159
+ client.with_access(access) do |authenticated_client|
160
+ authenticated_client.do_whatever_redd_client_can_do
161
+ end
162
+ ```
163
+
164
+ #### Who, me?
165
+ You can also revoke access tokens after the user has logged out to make sure the tokens can't be used for malicious purposes.
166
+
167
+ ```ruby
168
+ also_revoke_refresh_token = true
169
+ client.revoke_access(access, also_revoke_refresh_token)
170
+ ```
171
+
70
172
  ## Extending Redd
71
173
  Extending any ruby library, including redd is incredibly easy. Let's try this out by adding a gilding extension. Reddit provides an api to be able to gild posts and comments, given that you have "creddits".
72
174
 
73
175
  1. Let's start by creating a module for the methods to live in.
176
+
74
177
  ```ruby
75
178
  module MyGildingExtension
76
179
  end
77
180
  ```
78
181
 
79
182
  2. Let's add a method to gild a thing, using the [reddit api](http://www.reddit.com/dev/api#section_gold) and following the conventions.
183
+
80
184
  ```ruby
81
185
  module MyGildingExtension
82
- def gild(thing)
83
- # Redd::Client::Unauthenticated::Utilities has some pretty helpful
84
- # methods.
85
- fullname = extract_fullname(thing)
86
-
87
- # We're using post instead of object_from_response, because we don't
88
- # expect any object from the response.
89
- post "/api/v1/gold/gild/#{fullname}"
90
- end
186
+ def gild(thing)
187
+ # Redd::Client::Unauthenticated::Utilities has some pretty helpful
188
+ # methods.
189
+ fullname = extract_fullname(thing)
190
+
191
+ # We're using post instead of object_from_response, because we don't
192
+ # expect any object from the response.
193
+ post "/api/v1/gold/gild/#{fullname}"
194
+ end
91
195
  end
92
196
  ```
93
197
 
94
198
  3. Let's add the method to the Authenticated client. You can also add it to the Unauthenticated client, but since unauthenticated users can't gild, there's no point.
199
+
95
200
  ```ruby
96
201
  Redd::Client::Authenticated.include(MyGildingExtension)
97
202
  ```
98
203
 
99
204
  4. You might also want to add the method to objects to make it easier to access.
205
+
100
206
  ```ruby
101
207
  module Gildable
102
- def gild
103
- # Every Redd::Object is instantiated with the client that created
104
- # it, so the method can be called on the client easily, similar to
105
- # praw in python.
106
- client.gild(self)
107
- end
208
+ def gild
209
+ # Every Redd::Object is instantiated with the client that created
210
+ # it, so the method can be called on the client easily, similar to
211
+ # praw in python.
212
+ client.gild(self)
213
+ end
108
214
  end
109
215
 
110
216
  Redd::Object::Submission.include(Gildable)
111
217
  Redd::Object::Comment.include(Gildable)
112
218
  ```
113
219
 
220
+ #### Contributing
221
+ Please do. If you would like to become a contributor, do ask.
222
+
114
223
  ## Supported Rubies
115
224
  This gem aims to work on the following rubies:
116
225
 
data/RedditKit.LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- The error and base files would have been impossible if it weren't for @samsymons :)
1
+ The error and base files would have been impossible if it weren't for [@samsymons](https://github.com/samsymons) :)
2
2
 
3
3
  ---
4
4
 
@@ -10,4 +10,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
10
10
 
11
11
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
12
 
13
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -71,6 +71,18 @@ module Redd
71
71
  Redd::Object::Listing.new(data: {children: things})
72
72
  end
73
73
 
74
+ def edit_stylesheet(subreddit, contents, reason = nil)
75
+ name = extract_attribute(subreddit, :display_name)
76
+ path = "/r/#{name}/api/subreddit_stylesheet"
77
+ params = {
78
+ api_type: "json",
79
+ op: "save",
80
+ stylesheet_contents: contents
81
+ }
82
+ params[:reason] = reason if reason
83
+ post path, params
84
+ end
85
+
74
86
  private
75
87
 
76
88
  # Subscribe or unsubscribe to a subreddit.
@@ -95,9 +95,9 @@ module Redd
95
95
  params = {token: token}
96
96
 
97
97
  if remove_refresh_token
98
- params[:token_type_hint] = true
98
+ params[:token_type_hint] = :refresh_token
99
99
  elsif remove_refresh_token == false
100
- params[:token_type_hint] = false
100
+ params[:token_type_hint] = :access_token
101
101
  end
102
102
 
103
103
  auth_connection.post "/api/v1/revoke_token", params
@@ -64,7 +64,7 @@ module Redd
64
64
 
65
65
  # Gets the Faraday connection or creates one if it doesn't exist yet.
66
66
  #
67
- # @return [Faraday] A new Faraday connection.
67
+ # @return [Faraday] A new or existing Faraday connection.
68
68
  def connection
69
69
  @connection ||= Faraday.new(url: api_endpoint) do |faraday|
70
70
  faraday.use Faraday::Request::UrlEncoded
@@ -80,36 +80,36 @@ module Redd
80
80
  #
81
81
  # @param [#to_sym] method The HTTP verb to use.
82
82
  # @param [String] path The path under the api endpoint to request from.
83
- # @param [Hash] params The additional parameters to send (defualt: {}).
84
- # @return [String] The response body.
83
+ # @param [Hash] params The additional parameters to send.
84
+ # @return [Faraday::Response] The faraday response.
85
85
  def request(method, path, params = {})
86
86
  rate_limit.after_limit do
87
- connection.send(method.to_sym, path, params).body
87
+ connection.send(method.to_sym, path, params)
88
88
  end
89
89
  end
90
90
 
91
91
  # Performs a GET request via {#request}.
92
92
  # @see #request
93
93
  def get(*args)
94
- request(:get, *args)
94
+ request(:get, *args).body
95
95
  end
96
96
 
97
97
  # Performs a POST request via {#request}.
98
98
  # @see #request
99
99
  def post(*args)
100
- request(:post, *args)
100
+ request(:post, *args).body
101
101
  end
102
102
 
103
103
  # Performs a PUT request via {#request}.
104
104
  # @see #request
105
105
  def put(*args)
106
- request(:put, *args)
106
+ request(:put, *args).body
107
107
  end
108
108
 
109
109
  # Performs a DELETE request via {#request}.
110
110
  # @see #request
111
111
  def delete(*args)
112
- request(:delete, *args)
112
+ request(:delete, *args).body
113
113
  end
114
114
  end
115
115
  end
@@ -7,11 +7,11 @@ module Redd
7
7
  # query.
8
8
  # @return [String] The url for the subreddit's css stylesheet.
9
9
  def stylesheet_url(subreddit = nil)
10
- name = extract_attribute(subreddit, :display_name)
10
+ name = extract_attribute(subreddit, :display_name) if subreddit
11
11
  path = "/stylesheet"
12
12
  path = path.prepend("/r/#{name}") if subreddit
13
13
 
14
- get(path).headers[:location]
14
+ request(:get, path).headers[:location]
15
15
  end
16
16
 
17
17
  # @param subreddit [Redd::Object::Subreddit, String] The subreddit to
@@ -23,4 +23,4 @@ module Redd
23
23
  end
24
24
  end
25
25
  end
26
- end
26
+ end
@@ -95,12 +95,12 @@ module Redd
95
95
  end
96
96
 
97
97
  def comments_from_response(*args)
98
- body = request(*args)[1]
98
+ body = request(*args).body[1]
99
99
  object_from_body(body)
100
100
  end
101
101
 
102
102
  def object_from_response(*args)
103
- body = request(*args)
103
+ body = request(*args).body
104
104
  object_from_body(body)
105
105
  end
106
106
  end
@@ -1,3 +1,5 @@
1
+ require "faraday_middleware"
2
+
1
3
  module Redd
2
4
  # The module that contains middleware that alters the Faraday response.
3
5
  module Response
@@ -1,3 +1,4 @@
1
+ require "faraday_middleware"
1
2
  require "redd/error"
2
3
 
3
4
  module Redd
data/lib/redd/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # The main Redd module.
2
2
  module Redd
3
3
  # The semantic version number for Redd.
4
- VERSION = "0.6.0"
4
+ VERSION = "0.6.1"
5
5
  end
data/redd.gemspec CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
27
27
  s.add_development_dependency "webmock"
28
28
 
29
29
  s.add_dependency "faraday", "~> 0.9.0"
30
+ s.add_dependency "faraday_middleware", "~> 0.9.1"
30
31
  s.add_dependency "multi_json", "~> 1.10"
31
32
  s.add_dependency "memoizable"
32
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Avinash Dwarapu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-29 00:00:00.000000000 Z
11
+ date: 2014-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ~>
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.9.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: faraday_middleware
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: 0.9.1
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: 0.9.1
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: multi_json
127
141
  requirement: !ruby/object:Gem::Requirement