Module: Snooby
- Defined in:
- lib/snoobyplus.rb,
lib/snooby/post.rb,
lib/snooby/user.rb,
lib/snooby/client.rb,
lib/snooby/domain.rb,
lib/snooby/actions.rb,
lib/snooby/comment.rb,
lib/snooby/subreddit.rb
Overview
reddit API (Snoo) + happy programming (Ruby) = Snooby
Defined Under Namespace
Modules: About, Comments, Compose, Delete, Posts, Reply, Voting Classes: Client, Comment, Config, Domain, Post, RedditError, Subreddit, User
Constant Summary collapse
- Conn =
Opens a persistent connection that provides a significant speed improvement during repeated calls; reddit’s two-second rule pretty much nullifies this, but it’s still a great library and persistent connections are a Good Thing.
Net::HTTP::Persistent.new 'Snooby'
- Paths =
Provides a mapping of things and actions to their respective URL fragments.
paths.merge(paths) { |act, path| "http://www.reddit.com/#{path}" }
- Fields =
Provides a mapping of things to a list of all the attributes present in the relevant JSON object. A lot of these probably won’t get used too often, but might as well grab all available data (except body_html and selftext_html).
{ :comment => %w[author author_flair_css_class author_flair_text body created created_utc downs id likes link_id link_title name parent_id replies subreddit subreddit_id ups], :post => %w[author author_flair_css_class author_flair_text clicked created created_utc domain downs hidden id is_self likes media media_embed name num_comments over_18 permalink saved score selftext subreddit subreddit_id thumbnail title ups url] }
Class Attribute Summary collapse
-
.active ⇒ Object
Returns the value of attribute active.
-
.config ⇒ Object
Returns the value of attribute config.
Class Method Summary collapse
-
.build(object, path, which, count) ⇒ Object
The crux of Snooby.
-
.request(uri, data = nil) ⇒ Object
Wraps the connection for all requests to ensure that the two-second rule is adhered to.
-
.wait ⇒ Object
Called whenever respecting the API is required.
Class Attribute Details
.active ⇒ Object
Returns the value of attribute active.
19 20 21 |
# File 'lib/snoobyplus.rb', line 19 def active @active end |
.config ⇒ Object
Returns the value of attribute config.
19 20 21 |
# File 'lib/snoobyplus.rb', line 19 def config @config end |
Class Method Details
.build(object, path, which, count) ⇒ Object
The crux of Snooby. Generates an array of structs from the Paths and Fields hashes defined above. In addition to just being a very neat container, this allows accessing the returned JSON values using thing.attribute, as opposed to thing[‘attribute’]. Only used for listings of posts and comments at the moment, but I imagine it’ll be used for moderation down the road. Having to explicitly pass the path isn’t very DRY, but deriving it from the object (say, Snooby::Comment) doesn’t expose which kind of comment it is.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/snoobyplus.rb', line 137 def self.build(object, path, which, count) # A bit of string manipulation to determine which fields to populate the # generated structs with. There might be a less fragile way to go about it, # but it shouldn't be a problem as long as naming remains consistent. kind = object.to_s.split('::')[1].downcase.to_sym # Set limit to the maximum of 100 if we're grabbing more than that, give # after a truthy value since we stop when it's no longer so, and initialize # an empty result set that the generated structs will be pushed into. limit, after, results = [count, 100].min, '', [] while results.size < count && after uri = Paths[path] % which + "?limit=#{limit}&after=#{after}" json = request uri json = json[1] if path == :post_comments # skip over the post's data json['data']['children'].each do |child| # Converts each child's JSON data into the relevant struct based on the # kind of object being built. The symbols of a struct definition are # ordered, but Python dictionaries are not, so #values is insufficient. # Preliminary testing showed that appending one at a time is slightly # faster than concatenating the entire page of results and then taking # a slice at the end. This also allows for premature stopping if the # count is reached before all results have been processed. results << object.new(*child['data'].values_at(*Fields[kind])) return results if results.size == count end after = json['data']['after'] end results end |
.request(uri, data = nil) ⇒ Object
Wraps the connection for all requests to ensure that the two-second rule is adhered to. The uri parameter comes in as a string because it may have been susceptible to variables, so it gets turned into an actual URI here instead of all over the place. Since it’s required for all POST requests other than logging in, the client’s modhash is sent along by default.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/snoobyplus.rb', line 105 def self.request(uri, data = nil) uri = URI uri if data && data != 'html' unless active.uh || data[:passwd] raise RedditError, 'You must be logged in to make POST requests.' end post = Net::HTTP::Post.new uri.path post.set_form_data data.merge!(:uh => active.uh, :api_type => 'json') end wait if @last_request && Time.now - @last_request < @config['delay'] @last_request = Time.now resp = Conn.request uri, post raise ArgumentError, resp.code_type unless resp.code == '200' # Raw HTML is parsed to obtain the user's trophy data and karma breakdown. return resp.body if data == 'html' json = JSON.parse resp.body, :max_nesting => 100 if (resp = json['json']) && (errors = resp['errors']) raise RedditError, jj(json) unless errors.empty? end json end |
.wait ⇒ Object
Called whenever respecting the API is required.
169 170 171 |
# File 'lib/snoobyplus.rb', line 169 def self.wait sleep @config['delay'] end |