ruby_reddit_api-h 0.2.7
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.
- data/README.rdoc +27 -0
- data/features/api.feature +10 -0
- data/features/base.feature +15 -0
- data/features/comment.feature +40 -0
- data/features/message.feature +19 -0
- data/features/message_group.feature +14 -0
- data/features/reddit.yml +5 -0
- data/features/search.feature +6 -0
- data/features/step_definitions/api_steps.rb +22 -0
- data/features/step_definitions/base_steps.rb +49 -0
- data/features/step_definitions/comment_steps.rb +59 -0
- data/features/step_definitions/message_group_steps.rb +30 -0
- data/features/step_definitions/message_steps.rb +68 -0
- data/features/step_definitions/search_steps.rb +12 -0
- data/features/step_definitions/submission_steps.rb +118 -0
- data/features/step_definitions/user_steps.rb +27 -0
- data/features/submission.feature +58 -0
- data/features/support/base_helpers.rb +17 -0
- data/features/user.feature +11 -0
- data/lib/ruby_reddit_api/api.rb +87 -0
- data/lib/ruby_reddit_api/base.rb +133 -0
- data/lib/ruby_reddit_api/comment.rb +125 -0
- data/lib/ruby_reddit_api/json_listing.rb +46 -0
- data/lib/ruby_reddit_api/message.rb +63 -0
- data/lib/ruby_reddit_api/message_group.rb +39 -0
- data/lib/ruby_reddit_api/submission.rb +73 -0
- data/lib/ruby_reddit_api/thing.rb +38 -0
- data/lib/ruby_reddit_api/user.rb +42 -0
- data/lib/ruby_reddit_api/version.rb +6 -0
- data/lib/ruby_reddit_api/vote.rb +39 -0
- data/lib/ruby_reddit_api/voteable.rb +22 -0
- data/lib/ruby_reddit_api.rb +20 -0
- metadata +145 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
module Reddit
|
2
|
+
|
3
|
+
# @author James Cook
|
4
|
+
class Api < Base
|
5
|
+
attr_accessor :user, :password
|
6
|
+
attr_reader :last_action, :debug
|
7
|
+
|
8
|
+
def initialize(user=nil,password=nil, options={})
|
9
|
+
@user = user
|
10
|
+
@password = password
|
11
|
+
@debug = StringIO.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
"<Reddit::Api>"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Browse submissions by subreddit
|
19
|
+
# @param [String] Subreddit to browse
|
20
|
+
# @return [Array<Reddit::Submission>]
|
21
|
+
def browse(subreddit, options={})
|
22
|
+
subreddit = sanitize_subreddit(subreddit)
|
23
|
+
options.merge! :handler => "Submission"
|
24
|
+
if options[:limit]
|
25
|
+
options.merge!({:query => {:limit => options[:limit]}})
|
26
|
+
end
|
27
|
+
read("/r/#{subreddit}.json", options )
|
28
|
+
end
|
29
|
+
|
30
|
+
# Search reddit
|
31
|
+
# @param [String, Hash] Search terms and options
|
32
|
+
# @example
|
33
|
+
# search("programming", :in => "ruby", :sort => "relevance")
|
34
|
+
# @return [Array<Reddit::Submission>]
|
35
|
+
def search(terms=nil, options={})
|
36
|
+
http_options = {:verb => "get", :query => {}}
|
37
|
+
subreddit = options[:in]
|
38
|
+
sort = options.fetch(:sort){ "relevance" }
|
39
|
+
http_options[:query].merge!({:sort => sort})
|
40
|
+
|
41
|
+
if subreddit
|
42
|
+
http_options[:query].merge!({:restrict_sr => "1"})
|
43
|
+
end
|
44
|
+
|
45
|
+
if terms
|
46
|
+
http_options[:query].merge!({:q => terms})
|
47
|
+
end
|
48
|
+
path = subreddit.to_s == "" ? "/search.json" : "/r/#{subreddit}/search.json"
|
49
|
+
read(path, http_options)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Read sent messages
|
53
|
+
# @return [Array<Reddit::Message>]
|
54
|
+
def sent_messages
|
55
|
+
messages :sent
|
56
|
+
end
|
57
|
+
|
58
|
+
# Read received messages
|
59
|
+
# @return [Array<Reddit::Message>]
|
60
|
+
def received_messages
|
61
|
+
messages :inbox
|
62
|
+
end
|
63
|
+
|
64
|
+
#Read unread messages
|
65
|
+
# @return [Array<Reddit::Message>]
|
66
|
+
def unread_messages
|
67
|
+
messages :unread
|
68
|
+
end
|
69
|
+
|
70
|
+
# Read received comments
|
71
|
+
# @return [Array<Reddit::Message>]
|
72
|
+
def comments
|
73
|
+
messages :comments
|
74
|
+
end
|
75
|
+
|
76
|
+
# Read post replies
|
77
|
+
# @return [Array<Reddit::Message>]
|
78
|
+
def post_replies
|
79
|
+
messages :selfreply
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
def messages(kind)
|
84
|
+
read("/message/#{kind.to_s}.json", :handler => "Message")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Reddit
|
2
|
+
# Base module all other classes descend from. Stores the cookie, modhash and user info for many API calls. Handles authentication and directs JSON
|
3
|
+
# to the relevant handler.
|
4
|
+
# @author James Cook
|
5
|
+
class Base
|
6
|
+
include HTTParty
|
7
|
+
|
8
|
+
attr_reader :last_action, :debug
|
9
|
+
base_uri "www.reddit.com"
|
10
|
+
class << self; attr_reader :cookie, :modhash, :user_id, :user, :throttle_duration end
|
11
|
+
|
12
|
+
@throttle_duration = 1.0
|
13
|
+
|
14
|
+
def initialize(options={})
|
15
|
+
@debug = StringIO.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [String]
|
19
|
+
def inspect
|
20
|
+
"<Reddit::Base>"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Login to Reddit and capture the cookie
|
24
|
+
# @return [Boolean] Login success or failure
|
25
|
+
def login
|
26
|
+
capture_session(self.class.post( "/api/login", {:body => {:user => @user, :passwd => @password}, :debug_output => @debug} ) )
|
27
|
+
logged_in?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Remove the cookie to effectively logout of Reddit
|
31
|
+
# @return [nil]
|
32
|
+
def logout
|
33
|
+
Reddit::Base.instance_variable_set("@cookie",nil)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [String, nil]
|
37
|
+
def cookie
|
38
|
+
Reddit::Base.cookie
|
39
|
+
end
|
40
|
+
|
41
|
+
# A kind of authenticity token for many API calls
|
42
|
+
# @return [String, nil]
|
43
|
+
def modhash
|
44
|
+
Reddit::Base.modhash
|
45
|
+
end
|
46
|
+
|
47
|
+
# Reddit's displayed ID for the logged in user
|
48
|
+
# @return [String]
|
49
|
+
def user_id
|
50
|
+
Reddit::Base.user_id
|
51
|
+
end
|
52
|
+
|
53
|
+
# Logged in user
|
54
|
+
# @return [String]
|
55
|
+
def user
|
56
|
+
Reddit::Base.user
|
57
|
+
end
|
58
|
+
|
59
|
+
# The session is authenticated if the captured cookie shows a valid session is in place
|
60
|
+
# @return [true,false]
|
61
|
+
def logged_in?
|
62
|
+
!!(cookie && (cookie =~ /reddit_session/) != nil)
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return String
|
66
|
+
def user_agent
|
67
|
+
self.class.user_agent
|
68
|
+
end
|
69
|
+
|
70
|
+
# HTTP headers to be sent in all API requests. At a minimum, 'User-agent' and 'Cookie' are needed.
|
71
|
+
# @return Hash
|
72
|
+
def base_headers
|
73
|
+
self.class.base_headers
|
74
|
+
end
|
75
|
+
|
76
|
+
# Base communication function for nearly all API calls
|
77
|
+
# @return [Reddit::Submission, Reddit::Comment, Reddit::User, false] Various reddit-related, json parseable objects
|
78
|
+
def read(url, options={})
|
79
|
+
unless throttled?
|
80
|
+
@debug.rewind
|
81
|
+
verb = (options[:verb] || "get")
|
82
|
+
param_key = (verb == "get") ? :query : :body
|
83
|
+
resp = self.class.send( verb, url, {param_key => (options[param_key] || {}), :headers => base_headers, :debug_output => @debug})
|
84
|
+
if valid_response?(resp)
|
85
|
+
@last_action = Time.now
|
86
|
+
klass = Reddit.const_get(options[:handler] || "Submission")
|
87
|
+
resp = klass.parse( JSON.parse(resp.body, :max_nesting => 9_999) )
|
88
|
+
return resp
|
89
|
+
else
|
90
|
+
return false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
def valid_response?(response)
|
97
|
+
response.code == 200 && response.headers["content-type"].to_s =~ /json/
|
98
|
+
end
|
99
|
+
|
100
|
+
def capture_session(response)
|
101
|
+
cookies = response.headers["set-cookie"]
|
102
|
+
Reddit::Base.instance_variable_set("@cookie", cookies)
|
103
|
+
Reddit::Base.instance_variable_set("@user", @user)
|
104
|
+
end
|
105
|
+
|
106
|
+
def capture_user_id
|
107
|
+
return true if user_id
|
108
|
+
this_user = read("/user/#{user}/about.json", :handler => "User")[0]
|
109
|
+
Reddit::Base.instance_variable_set("@user_id", this_user.id)
|
110
|
+
end
|
111
|
+
|
112
|
+
def throttled?
|
113
|
+
@last_action && ( ( Time.now - @last_action ) < Reddit::Base.throttle_duration )
|
114
|
+
end
|
115
|
+
|
116
|
+
def sanitize_subreddit(subreddit)
|
117
|
+
subreddit.gsub!(/^\/?r\//,'')
|
118
|
+
subreddit.gsub!(/\.json\Z/,'')
|
119
|
+
subreddit
|
120
|
+
end
|
121
|
+
|
122
|
+
class << self
|
123
|
+
|
124
|
+
def base_headers
|
125
|
+
{'Cookie' => Reddit::Base.cookie.to_s, 'user-agent' => user_agent}
|
126
|
+
end
|
127
|
+
|
128
|
+
def user_agent
|
129
|
+
"Ruby Reddit Client v#{Reddit::VERSION}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Reddit
|
2
|
+
# @author James Cook
|
3
|
+
class Comment < Thing
|
4
|
+
include Voteable
|
5
|
+
include JsonListing
|
6
|
+
|
7
|
+
attr_reader :body, :subreddit_id, :name, :created, :downs, :author, :created_utc, :body_html, :link_id, :parent_id, :likes, :num_comments, :subreddit, :ups, :debug, :kind, :replies
|
8
|
+
def initialize(json, options={})
|
9
|
+
mode = options.fetch(:mode){ :json }
|
10
|
+
if mode == :json
|
11
|
+
parse(json)
|
12
|
+
end
|
13
|
+
|
14
|
+
if mode == :replies
|
15
|
+
json.keys.each do |key|
|
16
|
+
instance_variable_set("@#{key}", json[key])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
if replies.is_a?(Hash)
|
21
|
+
handle_replies(replies)
|
22
|
+
end
|
23
|
+
|
24
|
+
@debug = StringIO.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def inspect
|
28
|
+
"<Reddit::Comment author='#{@author}' body='#{short_body}' replies='#{replies.size}' ups='#{ups}' downs='#{downs}'>"
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [String]
|
32
|
+
def to_s
|
33
|
+
body
|
34
|
+
end
|
35
|
+
|
36
|
+
# Fetch comments
|
37
|
+
# @return [Array<Reddit::Comment>]
|
38
|
+
def comments
|
39
|
+
opts = {:handler => "Comment",
|
40
|
+
:verb => "post",
|
41
|
+
:body =>
|
42
|
+
{:link_id => id, :depth => 10, :r => subreddit, :uh => modhash, :renderstyle => "json", :pv_hex => "", :id => id}
|
43
|
+
}
|
44
|
+
return read("/api/morechildren", opts )
|
45
|
+
end
|
46
|
+
|
47
|
+
# Modify a comment
|
48
|
+
# @return [true,false]
|
49
|
+
def edit(newtext)
|
50
|
+
resp=self.class.post("/api/editusertext", {:body => {:thing_id => id, :uh => modhash, :r => subreddit, :text => newtext }, :headers => base_headers, :debug_output => @debug })
|
51
|
+
resp.code == 200
|
52
|
+
end
|
53
|
+
|
54
|
+
# Hide a comment
|
55
|
+
# @return [true,false]
|
56
|
+
def hide
|
57
|
+
resp=self.class.post("/api/del", {:body => {:id => id, :uh => modhash, :r => subreddit, :executed => "removed" }, :headers => base_headers, :debug_output => @debug })
|
58
|
+
resp.code == 200
|
59
|
+
end
|
60
|
+
|
61
|
+
# Remove a comment
|
62
|
+
# @return [true,false]
|
63
|
+
def remove
|
64
|
+
resp=self.class.post("/api/remove", {:body => {:id => id, :uh => modhash, :r => subreddit}, :headers => base_headers, :debug_output => @debug })
|
65
|
+
resp.code == 200
|
66
|
+
end
|
67
|
+
|
68
|
+
# Approve a comment
|
69
|
+
# @return [true,false]
|
70
|
+
def approve
|
71
|
+
resp=self.class.post("/api/approve", {:body => {:id => id, :uh => modhash, :r => subreddit}, :headers => base_headers, :debug_output => @debug })
|
72
|
+
resp.code == 200
|
73
|
+
end
|
74
|
+
|
75
|
+
def moderator_distinguish
|
76
|
+
add_distinction "yes"
|
77
|
+
end
|
78
|
+
|
79
|
+
def admin_distinguish
|
80
|
+
add_distinction "admin"
|
81
|
+
end
|
82
|
+
|
83
|
+
def indistinguish
|
84
|
+
add_distinction "no"
|
85
|
+
end
|
86
|
+
|
87
|
+
# Reply to another comment
|
88
|
+
# @return [true,false]
|
89
|
+
def reply(text)
|
90
|
+
resp = self.class.post("/api/comment", {:body => {:thing_id => id, :text => text, :uh => modhash, :r => subreddit }, :headers => base_headers, :debug_output => @debug })
|
91
|
+
resp.code == 200
|
92
|
+
end
|
93
|
+
|
94
|
+
# Trimmed comment body suitable for #inspect
|
95
|
+
# @return [String]
|
96
|
+
def short_body
|
97
|
+
str = body.to_s.strip
|
98
|
+
if str.size > 15
|
99
|
+
sb = str[0..15] + "..."
|
100
|
+
else
|
101
|
+
sb = body
|
102
|
+
end
|
103
|
+
|
104
|
+
sb.gsub(/[\n\r]/,'\n')
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_distinction(verb)
|
108
|
+
resp=self.class.post("/api/distinguish/#{verb}", {:body => {:id => id, :uh => modhash, :r => subreddit, :executed => "distinguishing..."}, :headers => base_headers, :debug_output => @debug })
|
109
|
+
resp.code == 200
|
110
|
+
end
|
111
|
+
|
112
|
+
# Parse nested comment hashes into a Comment
|
113
|
+
# @param [Hash] JSON containing reply data
|
114
|
+
# @return [true]
|
115
|
+
def handle_replies(data)
|
116
|
+
dup = data.dup
|
117
|
+
_kind, data = dup["kind"], dup["data"]
|
118
|
+
modhash, children = data["modhash"], data["children"]
|
119
|
+
if children.is_a?(Array)
|
120
|
+
@replies = children.map{|reply| Comment.new(reply["data"], :mode => :replies) }
|
121
|
+
end
|
122
|
+
true
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#@author James Cook
|
2
|
+
module Reddit
|
3
|
+
module JsonListing
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
base.send(:include, InstanceMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
# @param [Hash] JSON received from Reddit
|
12
|
+
# @return [Array<Reddit::Submission, Reddit::User, Reddit::Comment, Reddit::Message>]
|
13
|
+
def parse(json)
|
14
|
+
results = []
|
15
|
+
if json.is_a?(Array)
|
16
|
+
json.each do |j|
|
17
|
+
results << parse(j)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
data = json["data"]
|
21
|
+
Reddit::Base.instance_variable_set("@modhash", data["modhash"]) # Needed for api calls
|
22
|
+
|
23
|
+
children = data["children"] || [{"data" => data, "kind" => json["kind"] }]
|
24
|
+
children.each do |message|
|
25
|
+
kind = message["kind"]
|
26
|
+
message["data"]["kind"] = kind
|
27
|
+
results << self.new(message["data"])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
return results.flatten
|
32
|
+
end
|
33
|
+
end
|
34
|
+
module InstanceMethods
|
35
|
+
# Iterate over JSON and set instance variables that map to each JSON key
|
36
|
+
# @param [Hash] JSON received from Reddit
|
37
|
+
# @return [true]
|
38
|
+
def parse(json)
|
39
|
+
json.keys.each do |key|
|
40
|
+
instance_variable_set("@#{key}", json[key])
|
41
|
+
end
|
42
|
+
true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# @author James Cook
|
2
|
+
module Reddit
|
3
|
+
class Message < Thing
|
4
|
+
include JsonListing
|
5
|
+
|
6
|
+
attr_reader :body, :was_comment, :kind, :first_message, :name, :created, :dest, :created_utc, :body_html, :subreddit, :parent_id, :context, :replies, :subject, :debug
|
7
|
+
def initialize(json)
|
8
|
+
parse(json)
|
9
|
+
@debug = StringIO.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# The reddit ID of this message
|
13
|
+
# @return [String]
|
14
|
+
def id
|
15
|
+
"#{kind}_#{@id}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def unread?
|
19
|
+
@new == true
|
20
|
+
end
|
21
|
+
|
22
|
+
def read?
|
23
|
+
@new == false
|
24
|
+
end
|
25
|
+
|
26
|
+
# The author of the message. The data is lazy-loaded and cached on the message
|
27
|
+
# @return [Reddit::User]
|
28
|
+
def author
|
29
|
+
@author_data ||= read("/user/#{@author}/about.json", :handler => "User")
|
30
|
+
end
|
31
|
+
|
32
|
+
# Reply to this message
|
33
|
+
# @return [true,false]
|
34
|
+
def reply(text)
|
35
|
+
resp = self.class.post("/api/comment", {:body => {:thing_id => id, :text => text, :uh => modhash, :r => subreddit }, :headers => base_headers, :debug_output => @debug })
|
36
|
+
resp.code == 200
|
37
|
+
end
|
38
|
+
|
39
|
+
def mark_unread
|
40
|
+
resp = self.class.post("/api/unread_message", {:body => {:id => id, :uh => modhash}, :headers => base_headers, :debug_output => @debug })
|
41
|
+
resp.code == 200
|
42
|
+
end
|
43
|
+
|
44
|
+
def mark_read
|
45
|
+
resp = self.class.post("/api/read_message", {:body => {:id => id, :uh => modhash }, :headers => base_headers, :debug_output => @debug })
|
46
|
+
resp.code == 200
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
"<Reddit::Message '#{short_body}'>"
|
51
|
+
end
|
52
|
+
|
53
|
+
# Trimmed comment body suitable for #inspect
|
54
|
+
# @return [String]
|
55
|
+
def short_body
|
56
|
+
if body.size > 15
|
57
|
+
body[0..15]
|
58
|
+
else
|
59
|
+
body
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# @author James Cook
|
2
|
+
module Reddit
|
3
|
+
class MessageGroup < Thing
|
4
|
+
include JsonListing
|
5
|
+
attr_reader :debug
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@debug = StringIO.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def mark_read(messages)
|
12
|
+
mark messages, "read"
|
13
|
+
end
|
14
|
+
|
15
|
+
def mark_unread(messages)
|
16
|
+
mark messages, "unread"
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
def mark(messages, action)
|
21
|
+
ids = ids(messages)
|
22
|
+
action = action == "read" ? "read_message" : "unread_message"
|
23
|
+
resp = self.class.post("/api/#{action}", {:body => {:id => ids.join(','), :uh => modhash }, :headers => base_headers, :debug_output => @debug })
|
24
|
+
resp.code == 200
|
25
|
+
end
|
26
|
+
|
27
|
+
def ids(messages)
|
28
|
+
if messages.is_a?(Array)
|
29
|
+
if messages.first.is_a?(Reddit::Message)
|
30
|
+
return messages.map{|m| m.id }
|
31
|
+
else
|
32
|
+
return messages # assume array of String
|
33
|
+
end
|
34
|
+
else
|
35
|
+
return [ messages.id ]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# @author James Cook
|
2
|
+
module Reddit
|
3
|
+
class Submission < Thing
|
4
|
+
include JsonListing
|
5
|
+
include Voteable
|
6
|
+
|
7
|
+
attr_reader :domain, :media_embed, :subreddit, :selftext_html, :selftext, :likes, :saved, :clicked, :media, :score, :over_18, :hidden, :thumbnail, :subreddit_id, :downs, :is_self, :permalink, :name, :created, :url, :title, :created_utc, :num_comments, :ups, :kind, :last_comment_id
|
8
|
+
|
9
|
+
def inspect
|
10
|
+
"<Reddit::Submission id='#{id}' author='#{@author}' title='#{title}'>"
|
11
|
+
end
|
12
|
+
|
13
|
+
# Add a comment to a submission
|
14
|
+
# @param [String] Comment text
|
15
|
+
# @return [true,false]
|
16
|
+
def add_comment(text)
|
17
|
+
resp = self.class.post("/api/comment", {:body => {:thing_id => id, :text => text, :uh => modhash, :r => subreddit }, :headers => base_headers, :debug_output => @debug })
|
18
|
+
resp.code == 200
|
19
|
+
end
|
20
|
+
|
21
|
+
# Save submission
|
22
|
+
# @return [true,false]
|
23
|
+
def save
|
24
|
+
toggle :save
|
25
|
+
end
|
26
|
+
|
27
|
+
# Unsave submission
|
28
|
+
# @return [true,false]
|
29
|
+
def unsave
|
30
|
+
toggle :unsave
|
31
|
+
end
|
32
|
+
|
33
|
+
# Hide submission
|
34
|
+
# @return [true,false]
|
35
|
+
def hide
|
36
|
+
toggle :hide
|
37
|
+
end
|
38
|
+
|
39
|
+
# Unhide submission
|
40
|
+
# @return [true,false]
|
41
|
+
def unhide
|
42
|
+
toggle :unhide
|
43
|
+
end
|
44
|
+
|
45
|
+
def moderator_distinguish
|
46
|
+
add_distinction "yes"
|
47
|
+
end
|
48
|
+
|
49
|
+
def admin_distinguish
|
50
|
+
add_distinction "admin"
|
51
|
+
end
|
52
|
+
|
53
|
+
def indistinguish
|
54
|
+
add_distinction "no"
|
55
|
+
end
|
56
|
+
|
57
|
+
# Fetch submission comments
|
58
|
+
# @todo Move to 'Thing' class
|
59
|
+
# @return [Array<Reddit::Comment>]
|
60
|
+
def comments
|
61
|
+
_comments = read( permalink + ".json", {:handler => "Comment", :query => {:limit => 250}} )
|
62
|
+
@last_comment_id = _comments.last.id if _comments && _comments.any?
|
63
|
+
_comments.shift # First 'comment' is actually the submission
|
64
|
+
return _comments
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
def add_distinction(verb)
|
69
|
+
resp=self.class.post("/api/distinguish/#{verb}", {:body => {:id => id, :uh => modhash, :r => subreddit, :executed => "distinguishing..."}, :headers => base_headers, :debug_output => @debug })
|
70
|
+
resp.code == 200
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Reddit
|
2
|
+
# @author James Cook
|
3
|
+
class Thing < Base
|
4
|
+
include JsonListing
|
5
|
+
|
6
|
+
def initialize(data)
|
7
|
+
parse(data)
|
8
|
+
@debug = StringIO.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# The reddit ID of this entity
|
12
|
+
# @return [String]
|
13
|
+
def id
|
14
|
+
"#{kind}_#{@id}"
|
15
|
+
end
|
16
|
+
|
17
|
+
# The author of the entity. The data is lazy-loaded and cached on the object
|
18
|
+
# @return [Reddit::User]
|
19
|
+
def author
|
20
|
+
response = read("/user/#{@author}/about.json", :handler => "User") if @author
|
21
|
+
@author_data ||= response[0] if response
|
22
|
+
end
|
23
|
+
|
24
|
+
# Report thing
|
25
|
+
# @return [true,false]
|
26
|
+
def report
|
27
|
+
toggle :report
|
28
|
+
end
|
29
|
+
|
30
|
+
def toggle(which)
|
31
|
+
return false unless logged_in?
|
32
|
+
mapping = {:save => "save", :unsave => "unsave", :hide => "hidden", :unhide => "unhidden", :report => "report"}
|
33
|
+
mode = mapping[which]
|
34
|
+
resp = self.class.post("/api/#{which}", {:body => {:id => id, :uh => modhash, :r => subreddit, :executed => mode }, :headers => base_headers, :debug_output => @debug })
|
35
|
+
resp.code == 200
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Reddit
|
2
|
+
# @author James Cook
|
3
|
+
class User < Api
|
4
|
+
include JsonListing
|
5
|
+
attr_reader :name, :debug, :created, :created_utc, :link_karma, :comment_karma, :is_mod, :has_mod_mail, :kind
|
6
|
+
def initialize(json)
|
7
|
+
@debug = StringIO.new
|
8
|
+
parse(json)
|
9
|
+
end
|
10
|
+
|
11
|
+
def inspect
|
12
|
+
"<Reddit::User name='#{name}'>"
|
13
|
+
end
|
14
|
+
|
15
|
+
# The reddit ID of this submission
|
16
|
+
# @return [String]
|
17
|
+
def id
|
18
|
+
"#{kind}_#{@id}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [String]
|
22
|
+
def to_s
|
23
|
+
name
|
24
|
+
end
|
25
|
+
|
26
|
+
# Add redditor as friend. Requires a authenticated user.
|
27
|
+
# @return [true,false]
|
28
|
+
def friend
|
29
|
+
capture_user_id
|
30
|
+
resp=self.class.post("/api/friend", {:body => {:name => name, :container => user_id, :type => "friend", :uh => modhash}, :headers => base_headers, :debug_output => @debug })
|
31
|
+
resp.code == 200
|
32
|
+
end
|
33
|
+
|
34
|
+
# Remove redditor as friend. Requires a authenticated user.
|
35
|
+
# @return [true,false]
|
36
|
+
def unfriend
|
37
|
+
capture_user_id
|
38
|
+
resp=self.class.post("/api/unfriend", {:body => {:name => name, :container => user_id, :type => "friend", :uh => modhash}, :headers => base_headers, :debug_output => @debug })
|
39
|
+
resp.code == 200
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# @author James Cook
|
2
|
+
module Reddit
|
3
|
+
class Vote < Base
|
4
|
+
attr_reader :submission
|
5
|
+
|
6
|
+
def initialize(submission)
|
7
|
+
@submission = submission
|
8
|
+
end
|
9
|
+
|
10
|
+
# Upvote submission or comment
|
11
|
+
# @return [true,false]
|
12
|
+
def up
|
13
|
+
vote(:up)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Downvote submission or comment
|
17
|
+
# @return [true,false]
|
18
|
+
def down
|
19
|
+
vote(:down)
|
20
|
+
end
|
21
|
+
|
22
|
+
#@return [String]
|
23
|
+
def inspect
|
24
|
+
"<Reddit::Vote>"
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
def vote(direction)
|
29
|
+
return false unless logged_in?
|
30
|
+
up_or_down = direction == :up ? 1 : -1
|
31
|
+
resp = self.class.post( "/api/vote", {:body => {:id => submission.id, :dir => up_or_down, :uh => modhash}, :headers => base_headers})
|
32
|
+
if resp.code == 200
|
33
|
+
return true
|
34
|
+
else
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|