Module: Snooby

Defined in:
lib/snooby.rb,
lib/snooby/post.rb,
lib/snooby/user.rb,
lib/snooby/client.rb,
lib/snooby/actions.rb,
lib/snooby/comment.rb,
lib/snooby/subreddit.rb

Defined Under Namespace

Modules: About, Comments, Compose, Delete, Posts, Reply, Voting Classes: Client, Comment, 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 =
paths.merge(paths) { |k, v| "http://www.reddit.com/#{v}" }
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

Class Method Summary collapse

Class Attribute Details

.activeObject

Returns the value of attribute active.



101
102
103
# File 'lib/snooby.rb', line 101

def active
  @active
end

.configObject

Returns the value of attribute config.



101
102
103
# File 'lib/snooby.rb', line 101

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.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/snooby.rb', line 68

def self.build(object, path, which, count)
  # A bit of string manipulation to determine which fields to populate the
  # generated struct 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, '', []

  # Fetch data until we've met the count or reached the end of the results.
  while results.size < count && after
    uri = Paths[path] % which + "?limit=#{limit}&after=#{after}"
    json = JSON.parse(Snooby.request(uri), :max_nesting => 100)
    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 created above for both POST and GET requests to ensure that the two-second rule is adhered to. The uri parameter is turned into an actual URI once here instead of all over the place. The client’s modhash is always required for POST requests, so it is passed along by default.



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/snooby.rb', line 49

def self.request(uri, data = nil)
  uri = URI(uri)
  if data
    data.merge!(:uh => Snooby.active.uh) if Snooby.active
    post = Net::HTTP::Post.new(uri.path)
    post.set_form_data(data)
  end
  Snooby.wait if @last_request && Time.now - @last_request < 2
  @last_request = Time.now
  Conn.request(uri, post).body
end

.waitObject

Called whenever respecting the API is required.



109
110
111
# File 'lib/snooby.rb', line 109

def self.wait
  sleep 2
end