redd 0.8.8 → 0.9.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/CONTRIBUTING.md +63 -0
  4. data/Guardfile +7 -0
  5. data/README.md +6 -5
  6. data/Rakefile +1 -1
  7. data/TODO.md +423 -0
  8. data/bin/console +91 -77
  9. data/bin/guard +2 -0
  10. data/lib/redd.rb +7 -5
  11. data/lib/redd/api_client.rb +2 -3
  12. data/lib/redd/auth_strategies/auth_strategy.rb +7 -2
  13. data/lib/redd/auth_strategies/script.rb +7 -0
  14. data/lib/redd/auth_strategies/userless.rb +7 -0
  15. data/lib/redd/auth_strategies/web.rb +6 -1
  16. data/lib/redd/client.rb +0 -3
  17. data/lib/redd/errors.rb +56 -0
  18. data/lib/redd/middleware.rb +10 -8
  19. data/lib/redd/models/access.rb +30 -18
  20. data/lib/redd/models/comment.rb +185 -27
  21. data/lib/redd/models/front_page.rb +16 -36
  22. data/lib/redd/models/gildable.rb +1 -1
  23. data/lib/redd/models/inboxable.rb +13 -3
  24. data/lib/redd/models/listing.rb +27 -6
  25. data/lib/redd/models/live_thread.rb +76 -23
  26. data/lib/redd/models/live_update.rb +46 -0
  27. data/lib/redd/models/messageable.rb +1 -1
  28. data/lib/redd/models/mod_action.rb +59 -0
  29. data/lib/redd/models/model.rb +23 -0
  30. data/lib/redd/models/moderatable.rb +6 -6
  31. data/lib/redd/models/modmail.rb +61 -0
  32. data/lib/redd/models/modmail_conversation.rb +154 -0
  33. data/lib/redd/models/modmail_message.rb +35 -0
  34. data/lib/redd/models/more_comments.rb +29 -5
  35. data/lib/redd/models/multireddit.rb +63 -20
  36. data/lib/redd/models/paginated_listing.rb +113 -0
  37. data/lib/redd/models/postable.rb +11 -13
  38. data/lib/redd/models/private_message.rb +78 -11
  39. data/lib/redd/models/replyable.rb +2 -2
  40. data/lib/redd/models/reportable.rb +14 -0
  41. data/lib/redd/models/searchable.rb +2 -2
  42. data/lib/redd/models/self.rb +17 -0
  43. data/lib/redd/models/session.rb +75 -31
  44. data/lib/redd/models/submission.rb +309 -56
  45. data/lib/redd/models/subreddit.rb +330 -103
  46. data/lib/redd/models/trophy.rb +34 -0
  47. data/lib/redd/models/user.rb +185 -46
  48. data/lib/redd/models/wiki_page.rb +37 -16
  49. data/lib/redd/utilities/error_handler.rb +13 -13
  50. data/lib/redd/utilities/unmarshaller.rb +7 -5
  51. data/lib/redd/version.rb +1 -1
  52. data/redd.gemspec +18 -15
  53. metadata +82 -16
  54. data/lib/redd/error.rb +0 -53
  55. data/lib/redd/models/basic_model.rb +0 -80
  56. data/lib/redd/models/lazy_model.rb +0 -75
  57. data/lib/redd/models/mod_mail.rb +0 -142
  58. data/lib/redd/utilities/stream.rb +0 -61
@@ -8,8 +8,8 @@ module Redd
8
8
  # @param text [String] the text to comment
9
9
  # @return [Comment, PrivateMessage] The created reply.
10
10
  def reply(text)
11
- fullname = get_attribute(:name)
12
- @client.model(:post, '/api/comment', text: text, thing_id: fullname).first
11
+ fullname = read_attribute(:name)
12
+ client.model(:post, '/api/comment', text: text, thing_id: fullname).first
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Redd
4
+ module Models
5
+ # Things that can be reported (except users).
6
+ module Reportable
7
+ # Report the object.
8
+ # @param reason [String] the report reason
9
+ def report(reason)
10
+ client.post('/api/report', thing_id: read_attribute(:name), reason: reason)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -25,9 +25,9 @@ module Redd
25
25
  if params[:restrict_to]
26
26
  subreddit = params.delete(:restrict_to)
27
27
  params[:restrict_sr] = true
28
- @client.model(:get, "/r/#{subreddit}/search", params)
28
+ client.model(:get, "/r/#{subreddit}/search", params)
29
29
  else
30
- @client.model(:get, '/search', params)
30
+ client.model(:get, '/search', params)
31
31
  end
32
32
  end
33
33
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'user'
4
+
5
+ module Redd
6
+ module Models
7
+ # The user that the bot is running under.
8
+ class Self < User
9
+ private
10
+
11
+ def lazer_reload
12
+ fully_loaded!
13
+ client.get('/api/v1/me').body
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,83 +1,108 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lazy_model'
3
+ require_relative 'model'
4
4
  require_relative 'searchable'
5
5
 
6
6
  module Redd
7
7
  module Models
8
8
  # The starter class.
9
- class Session < BasicModel
9
+ class Session < Model
10
10
  include Searchable
11
11
 
12
- # @return [ModMail] the new modmail
13
- def mod_mail
14
- ModMail.new(@client)
12
+ # @return [Modmail] the new modmail
13
+ def modmail
14
+ Modmail.new(client)
15
15
  end
16
16
 
17
17
  # @return [LiveThread] the live thread
18
18
  def live_thread(id)
19
- LiveThread.from_id(client, id)
19
+ LiveThread.new(client, id: id)
20
20
  end
21
21
 
22
22
  # @return [FrontPage] the user's front page
23
23
  def front_page
24
- FrontPage.new(@client)
24
+ FrontPage.new(client)
25
25
  end
26
26
 
27
27
  # @return [Hash] a breakdown of karma over subreddits
28
28
  def karma_breakdown
29
- @client.get('/api/v1/me/karma').body[:data]
29
+ client.get('/api/v1/me/karma').body[:data]
30
30
  end
31
31
 
32
32
  # @return [User] the logged-in user
33
33
  def me
34
- User.new(@client) { |client| client.get('/api/v1/me').body }
34
+ Self.new(client)
35
35
  end
36
36
 
37
37
  # Get a (lazily loaded) reddit user by their name.
38
38
  # @param name [String] the username
39
39
  # @return [User]
40
40
  def user(name)
41
- User.from_id(@client, name)
41
+ User.new(client, name: name)
42
+ end
43
+
44
+ # Returns whether a username is available.
45
+ # @param username [String] the username to check
46
+ # @return [Boolean] whether the username is available
47
+ def username_available?(username)
48
+ client.get('/api/username_available', user: username).body
42
49
  end
43
50
 
44
51
  # Get a (lazily loaded) subreddit by its name.
45
52
  # @param display_name [String] the subreddit's display name
46
53
  # @return [Subreddit]
47
54
  def subreddit(display_name)
48
- Subreddit.from_id(@client, display_name)
55
+ Subreddit.new(client, display_name: display_name)
49
56
  end
50
57
 
51
58
  # @return [Array<Multireddit>] array of multireddits belonging to the user
52
59
  def my_multis
53
- @client.get('/api/multi/mine').body.map { |m| @client.unmarshal(m) }
60
+ client.get('/api/multi/mine').body.map { |m| client.unmarshal(m) }
54
61
  end
55
62
 
56
63
  # Get a (lazily loaded) multi by its path.
57
64
  # @param path [String] the multi's path, surrounded by a leading and trailing /
58
65
  # @return [Multireddit]
59
66
  def multi(path)
60
- Multireddit.from_id(@client, path)
67
+ Multireddit.new(client, path: path)
61
68
  end
62
69
 
63
70
  # Get submissions or comments by their fullnames.
64
71
  # @param fullnames [String, Array<String>] one or an array of fullnames (e.g. t3_abc1234)
65
72
  # @return [Listing<Submission, Comment>]
66
- def from_ids(fullnames)
67
- # XXX: Could we use better methods for t1_ and t3_?
68
- @client.model(:get, '/api/info', id: Array(fullnames).join(','))
73
+ # @deprecated Try the lazier {#from_fullnames} instead.
74
+ def from_ids(*fullnames)
75
+ client.model(:get, '/api/info', id: fullnames.join(','))
76
+ end
77
+
78
+ # Create lazily-loaded objects from their fullnames (e.g. t1_abc123).
79
+ # @param fullnames [String] fullname for a submission, comment, or subreddit.
80
+ # @return [Array<Submission, Comment, User, Subreddit>]
81
+ def from_fullnames(*fullnames)
82
+ fullnames.map do |name|
83
+ if name.start_with?('t1_')
84
+ Comment.new(client, name: name)
85
+ elsif name.start_with?('t3_')
86
+ Submission.new(client, name: name)
87
+ elsif name.start_with?('t5_')
88
+ Subreddit.new(client, name: name)
89
+ else
90
+ raise "unknown fullname #{name}"
91
+ end
92
+ end
69
93
  end
70
94
 
71
95
  # Get submissions or comments by their fullnames.
72
96
  # @param url [String] the object's url
73
97
  # @return [Submission, Comment, nil] the object, or nil if not found
74
98
  def from_url(url)
75
- @client.model(:get, '/api/info', url: url).first
99
+ client.model(:get, '/api/info', url: url).first
76
100
  end
77
101
 
78
102
  # Return a listing of the user's inbox (including comment replies and private messages).
79
103
  #
80
- # @param category ['inbox', 'unread', 'sent', 'moderator'] the category of messages to view
104
+ # @param category ['inbox', 'unread', 'sent', 'moderator', 'messages'] the category of
105
+ # messages to view
81
106
  # @param mark [Boolean] whether to remove the orangered from the user's inbox
82
107
  # @param params [Hash] a list of optional params to send with the request
83
108
  # @option params [String] :after return results after the given fullname
@@ -86,17 +111,17 @@ module Redd
86
111
  # @option params [1..100] :limit (25) the maximum number of things to return
87
112
  # @return [Listing<Comment, PrivateMessage>]
88
113
  def my_messages(category: 'inbox', mark: false, **params)
89
- @client.model(:get, "/message/#{category}.json", params.merge(mark: mark))
114
+ client.model(:get, "/message/#{category}.json", params.merge(mark: mark))
90
115
  end
91
116
 
92
117
  # Mark all messages as read.
93
118
  def read_all_messages
94
- @client.post('/api/read_all_messages')
119
+ client.post('/api/read_all_messages')
95
120
  end
96
121
 
97
122
  # @return [Hash] the user's preferences
98
123
  def my_preferences
99
- @client.get('/api/v1/me/prefs').body
124
+ client.get('/api/v1/me/prefs').body
100
125
  end
101
126
 
102
127
  # Edit the user's preferences.
@@ -104,7 +129,7 @@ module Redd
104
129
  # @return [Hash] the new preferences
105
130
  # @see #my_preferences
106
131
  def edit_preferences(new_prefs = {})
107
- @client.request(
132
+ client.request(
108
133
  :patch, '/api/v1/me/prefs',
109
134
  headers: { 'Content-Type' => 'application/json' },
110
135
  body: JSON.generate(new_prefs)
@@ -113,28 +138,28 @@ module Redd
113
138
 
114
139
  # @return [Array<User>] the logged-in user's friends
115
140
  def friends
116
- @client.get('/api/v1/me/friends').body[:data][:children].map do |h|
117
- User.new(@client, name: h[:name], id: h[:id].sub('t2_', ''), since: h[:date])
141
+ client.get('/api/v1/me/friends').body[:data][:children].map do |h|
142
+ User.new(client, name: h[:name], id: h[:id].sub('t2_', ''), since: h[:date])
118
143
  end
119
144
  end
120
145
 
121
146
  # @return [Array<User>] users blocked by the logged-in user
122
147
  def blocked
123
- @client.get('/prefs/blocked').body[:data][:children].map do |h|
124
- User.new(@client, name: h[:name], id: h[:id].sub('t2_', ''), since: h[:date])
148
+ client.get('/prefs/blocked').body[:data][:children].map do |h|
149
+ User.new(client, name: h[:name], id: h[:id].sub('t2_', ''), since: h[:date])
125
150
  end
126
151
  end
127
152
 
128
- # @return [Array<User>] users blocked by the logged-in user
153
+ # @return [Array<User>] users trusted by the logged-in user
129
154
  def trusted
130
- @client.get('/prefs/trusted').body[:data][:children].map do |h|
131
- User.new(@client, name: h[:name], id: h[:id].sub('t2_', ''), since: h[:date])
155
+ client.get('/prefs/trusted').body[:data][:children].map do |h|
156
+ User.new(client, name: h[:name], id: h[:id].sub('t2_', ''), since: h[:date])
132
157
  end
133
158
  end
134
159
 
135
160
  # @return [Array<String>] a list of categories the user's items are saved in
136
161
  def saved_categories
137
- @client.get('/api/saved_categories').body
162
+ client.get('/api/saved_categories').body
138
163
  end
139
164
 
140
165
  # Return a listing of the user's subreddits.
@@ -147,7 +172,26 @@ module Redd
147
172
  # @option params [1..100] :limit (25) the maximum number of things to return
148
173
  # @return [Listing<Subreddit>]
149
174
  def my_subreddits(type, **params)
150
- @client.model(:get, "/subreddits/mine/#{type}", params)
175
+ client.model(:get, "/subreddits/mine/#{type}", params)
176
+ end
177
+
178
+ # Return trending subreddits.
179
+ # @return [Hash]
180
+ # @example
181
+ # session.trending_subreddits
182
+ # => {
183
+ # "subreddit_names": [
184
+ # "AskLibertarians",
185
+ # "OpTicGaming",
186
+ # "Cuphead",
187
+ # "AlmostParkour",
188
+ # "TheGoodPlace"
189
+ # ],
190
+ # "comment_count": 176,
191
+ # "comment_url": "/r/trendingsubreddits/comments/73dkin/trending_subreddits_for_20170930_rasklibertarians/"
192
+ # }
193
+ def trending_subreddits
194
+ client.get('/api/trending_subreddits').body
151
195
  end
152
196
  end
153
197
  end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lazy_model'
3
+ require_relative 'model'
4
4
  require_relative 'gildable'
5
5
  require_relative 'moderatable'
6
6
  require_relative 'postable'
7
7
  require_relative 'replyable'
8
+ require_relative 'reportable'
8
9
 
9
10
  require_relative 'user'
10
11
  require_relative 'subreddit'
@@ -12,36 +13,19 @@ require_relative 'subreddit'
12
13
  module Redd
13
14
  module Models
14
15
  # A text or link post.
15
- class Submission < LazyModel
16
+ class Submission < Model
16
17
  include Gildable
17
18
  include Moderatable
18
19
  include Postable
19
20
  include Replyable
21
+ include Reportable
20
22
 
21
- # Create a Subreddit from its fullname.
22
- # @param client [APIClient] the api client to initialize the object with
23
- # @param id [String] the fullname
24
- # @return [Submission]
25
- def self.from_id(client, id)
26
- new(client, name: id)
27
- end
28
-
29
- # @return [Symbol] the requested sort order
30
- def sort_order
31
- @sort_order ||= nil
32
- end
33
-
34
- # Set the sort order of the comments and reload if necessary.
23
+ # Set the sort order of the comments and reload the comments.
35
24
  # @param new_order [:confidence, :top, :controversial, :old, :qa] the sort order
36
- def sort_order=(new_order)
37
- # If the comments were loaded in a different sort order, delete them and invalidate this
38
- # model.
39
- if @attributes.key?(:comments) && @sort_order != new_order
40
- @attributes.delete(:comments)
41
- @definitely_fully_loaded = false
42
- end
43
-
44
- @sort_order = new_order
25
+ def update_sort_order(new_order)
26
+ return self if new_order == read_attribute(:sort_order)
27
+ write_attribute(:sort_order, new_order)
28
+ reload
45
29
  end
46
30
 
47
31
  # Get all submissions for the same url.
@@ -52,94 +36,363 @@ module Redd
52
36
  # @option params [1..100] :limit (25) the maximum number of things to return
53
37
  # @return [Listing<Submission>]
54
38
  def duplicates(**params)
55
- @client.unmarshal(@client.get("/duplicates/#{get_attribute(:id)}", params).body[1])
39
+ client.unmarshal(client.get("/duplicates/#{read_attribute(:id)}", params).body[1])
56
40
  end
57
41
 
58
42
  # Mark the link as "Not Suitable For Work".
59
43
  def mark_as_nsfw
60
- @client.get('/api/marknsfw', id: get_attribute(:name))
61
- @attributes[:over_18] = true
44
+ client.get('/api/marknsfw', id: read_attribute(:name))
62
45
  end
63
46
 
64
47
  # No longer mark the link as "Not Suitable For Work".
65
48
  def unmark_as_nsfw
66
- @client.get('/api/unmarknsfw', id: get_attribute(:name))
67
- @attributes[:over_18] = false
49
+ client.get('/api/unmarknsfw', id: read_attribute(:name))
68
50
  end
69
51
 
70
52
  # Mark the link as a spoiler.
71
53
  def mark_as_spoiler
72
- @client.get('/api/spoiler', id: get_attribute(:name))
73
- @attributes[:spoiler] = true
54
+ client.get('/api/spoiler', id: read_attribute(:name))
74
55
  end
75
56
 
76
57
  # No longer mark the link as a spoiler.
77
58
  def unmark_as_spoiler
78
- @client.get('/api/unspoiler', id: get_attribute(:name))
79
- @attributes[:spoiler] = false
59
+ client.get('/api/unspoiler', id: read_attribute(:name))
80
60
  end
81
61
 
82
62
  # Set the submission to "contest mode" (comments are randomly sorted)
83
63
  def enable_contest_mode
84
- @client.post('/api/set_contest_mode', id: get_attribute(:name), state: true)
64
+ client.post('/api/set_contest_mode', id: read_attribute(:name), state: true)
85
65
  end
86
66
 
87
67
  # Disable the "contest mode".
88
68
  def disable_contest_mode
89
- @client.post('/api/set_contest_mode', id: get_attribute(:name), state: false)
69
+ client.post('/api/set_contest_mode', id: read_attribute(:name), state: false)
90
70
  end
91
71
 
92
72
  # Set the submission as the sticky post of the subreddit.
93
73
  # @param slot [1, 2] which "slot" to place the sticky on
94
74
  def make_sticky(slot: nil)
95
- @client.post('/api/set_subreddit_sticky', id: get_attribute(:name), num: slot, state: true)
75
+ client.post('/api/set_subreddit_sticky', id: read_attribute(:name), num: slot, state: true)
96
76
  end
97
77
 
98
78
  # Unsticky the post from the subreddit.
99
79
  def remove_sticky
100
- @client.post('/api/set_subreddit_sticky', id: get_attribute(:name), state: false)
80
+ client.post('/api/set_subreddit_sticky', id: read_attribute(:name), state: false)
101
81
  end
102
82
 
103
83
  # Prevent users from commenting on the link (and hide it as well).
104
84
  def lock
105
- @client.post('/api/lock', id: get_attribute(:name))
85
+ client.post('/api/lock', id: read_attribute(:name))
106
86
  end
107
87
 
108
88
  # Allow users to comment on the link again.
109
89
  def unlock
110
- @client.post('/api/unlock', id: get_attribute(:name))
90
+ client.post('/api/unlock', id: read_attribute(:name))
111
91
  end
112
92
 
113
93
  # Set the suggested sort order for comments for all users.
114
94
  # @param suggested ['blank', 'confidence', 'top', 'new', 'controversial', 'old', 'random',
115
95
  # 'qa', 'live'] the sort type
116
- def set_suggested_sort(suggested) # rubocop:disable Style/AccessorMethodName
117
- # Style/AccessorMethodName is disabled because it feels wrong for accessor methods to make
118
- # HTTP requests.
119
- @client.post('/api/set_suggested_sort', id: get_attribute(:name), sort: suggested)
96
+ def set_suggested_sort(suggested) # rubocop:disable Naming/AccessorMethodName
97
+ client.post('/api/set_suggested_sort', id: read_attribute(:name), sort: suggested)
120
98
  end
121
99
 
100
+ # @!attribute [r] sort_order
101
+ # @return [Symbol] the comment sort order
102
+ property :sort_order, :nil
103
+
104
+ # @!attribute [r] comments
105
+ # @return [Array<Comment>] the comment tree
106
+ property :comments, :nil, with: ->(l) { Listing.new(client, l) if l }
107
+
108
+ # @!attribute [r] domain
109
+ # @return [String] the domain name of the link (or self.subreddit_name)
110
+ property :domain
111
+
112
+ # @!attribute [r] approved_at
113
+ # @return [Time, nil] when the submission was last approved
114
+ property :approved_at, :approved_at_utc, with: ->(t) { Time.at(t) if t }
115
+
116
+ # @!attribute [r] banned_by
117
+ # @return [String] not sure what this does
118
+ property :banned_by
119
+
120
+ # @!attribute [r] media_embed
121
+ # @return [Hash] media embed properties
122
+ property :media_embed
123
+
124
+ # @!attribute [r] subreddit
125
+ # @return [Subreddit] the subreddit the post belongs to.
126
+ property :subreddit, with: ->(n) { Subreddit.new(client, display_name: n) }
127
+
128
+ # @!attribute [r] selftext_html
129
+ # @return [String, nil] the html-rendered self text, can be nil if link
130
+ property :selftext_html
131
+
132
+ # @!attribute [r] selftext
133
+ # @return [String] the self text contents
134
+ property :selftext
135
+
136
+ # @!attribute [r] upvoted?
137
+ # @return [Boolean, nil] whether the user upvoted/downvoted this post
138
+ property :upvoted?, from: :likes
139
+
140
+ # @!attribute [r] suggested_sort
141
+ # @return [String, nil] the suggested sort
142
+ property :suggested_sort
143
+
144
+ # @!attribute [r] user_reports
145
+ # @return [Array<String>] user reports
146
+ property :user_reports
147
+
148
+ # @!attribute [r] secure_media
149
+ # @return [Hash, nil] secure media details
150
+ property :secure_media
151
+
152
+ # @!attribute [r] link_flair_text
153
+ # @return [String] the link flair text
154
+ property :link_flair_text
155
+
156
+ # @!attribute [r] link_flair_css_class
157
+ # @return [String] the link flair css class
158
+ property :link_flair_css_class
159
+
160
+ # @!attribute [r] id
161
+ # @return [String] the submission id
162
+ property :id
163
+
164
+ # @!attribute [r] banned_at
165
+ # @return [Time, nil] the time the post was banned
166
+ property :banned_at, from: :banned_at_utc, with: ->(t) { Time.at(t) if t }
167
+
168
+ # @!attribute [r] view_count
169
+ # @return [Integer, nil] the view count
170
+ property :view_count
171
+
172
+ # @!attribute [r] archived?
173
+ # @return [Boolean] whether the post is archived
174
+ property :archived?, from: :archived
175
+
176
+ # @!attribute [r] clicked?
177
+ # @return [Boolean] whether the post was clicked
178
+ property :clicked?, from: :clicked
179
+
180
+ # @!attribute [r] report_reasons
181
+ # @return [Object] i think it's an array of strings?
182
+ property :report_reasons
183
+
184
+ # @!attribute [r] title
185
+ # @return [String] the post title
186
+ property :title
187
+
188
+ # @!attribute [r] num_crossposts
189
+ # @return [Integer] the number of crossposts made to other subreddits
190
+ property :num_crossposts
191
+
192
+ # @!attribute [r] saved?
193
+ # @return [String] whether the post was saved by the logged-in user
194
+ property :saved?, from: :saved
195
+
196
+ # @!attribute [r] can_mod_post?
197
+ # @return [Boolean] whether you can post as a mod, i think
198
+ property :can_mod_post?, from: :can_mod_post
199
+
200
+ # @!attribute [r] crosspostable?
201
+ # @return [Boolean] whether the post can be crossposted
202
+ property :crosspostable?, from: :is_crosspostable
203
+
204
+ # @!attribute [r] pinned?
205
+ # @return [Boolean] whether the post is pinned
206
+ property :pinned?, from: :pinned
207
+
208
+ # @!attribute [r] score
209
+ # @return [Integer] the post's score
210
+ property :score
211
+
212
+ # @!attribute [r] approved_by
213
+ # @return [Object] the person that approved this post (not sure about the schema)
214
+ property :approved_by
215
+
216
+ # @!attribute [r] over_18?
217
+ # @return [Boolean] whether the post is marked as over 18
218
+ property :over_18?, from: :over_18
219
+
220
+ # @!attribute [r] hidden?
221
+ # @return [Boolean] whether the logged-in user hid the post
222
+ property :hidden?, from: :hidden
223
+
224
+ # @!attribute [r] preview
225
+ # @return [Hash] preview details
226
+ property :preview
227
+
228
+ # @!attribute [r] comment_count
229
+ # @return [Integer] the post's comment count
230
+ property :comment_count, from: :num_comments
231
+
232
+ # @!attribute [r] thumbnail
233
+ # @return [String] the thumbnail url
234
+ property :thumbnail
235
+
236
+ # @!attribute [r] thumbnail_height
237
+ # @return [Integer] thumbnail height
238
+ property :thumbnail_height
239
+
240
+ # @!attribute [r] score_hidden?
241
+ # @return [Boolean] whether the score is hidden
242
+ property :score_hidden?, from: :hide_score
243
+
244
+ # @!attribute [r] edited
245
+ # @return [Time, false] the time of the last edit
246
+ property :edited, with: ->(t) { Time.at(t) if t }
247
+
248
+ # @!attribute [r] author_flair_text
249
+ # @return [String] the author flair text
250
+ property :author_flair_text
251
+
252
+ # @!attribute [r] author_flair_css_class
253
+ # @return [String] the author flair css class
254
+ property :author_flair_css_class
255
+
256
+ # @!attribute [r] contest_mode_enabled?
257
+ # @return [Boolean] whether contest mode is turned on
258
+ property :contest_mode_enabled?, from: :contest_mode
259
+
260
+ # @!attribute [r] gilded
261
+ # @return [Integer] the number of times the post was gilded
262
+ property :gilded
263
+
264
+ # @!attribute [r] locked?
265
+ # @return [Boolean] whether the post is locked
266
+ property :locked?, from: :locked
267
+
268
+ # @!attribute [r] ups
269
+ # @return [Integer] upvote count
270
+ # @deprecated this doesn't return the raw upvote count - use {#score} instead
271
+ property :ups
272
+
273
+ # @!attribute [r] downs
274
+ # @return [Integer] downvote count
275
+ # @deprecated this always returns zero - use {#score} instead
276
+ property :downs
277
+
278
+ # @!attribute [r] brand_safe?
279
+ # @return [Boolean] whether the post is marked as brand safe
280
+ property :brand_safe?, from: :brand_safe
281
+
282
+ # @!attribute [r] secure_media_embed
283
+ # @return [Hash] secure media embed details
284
+ property :secure_media_embed
285
+
286
+ # @!attribute [r] removal_reason
287
+ # @return [String] the removal reason
288
+ property :removal_reason
289
+
290
+ # @!attribute [r] post_hint
291
+ # @return [String] a hint at what the link should contain
292
+ property :post_hint
293
+
294
+ # @!attribute [r] can_gild?
295
+ # @return [Boolean] whether the user can gild this post
296
+ property :can_gild?, from: :can_gild
297
+
298
+ # @!attribute [r] parent_whitelist_status
299
+ # @return [String] ad-related whitelist stuff
300
+ property :parent_whitelist_status
301
+
302
+ # @!attribute [r] name
303
+ # @return [String] the fullname (i.e. t3_xxxxxx)
304
+ property :name
305
+
306
+ # @!attribute [r] spoiler?
307
+ # @return [Boolean] whether the post was marked as a spoiler
308
+ property :spoiler?, from: :spoiler
309
+
310
+ # @!attribute [r] permalink
311
+ # @return [String] the **relative** url permalink
312
+ property :permalink
313
+
314
+ # @!attribute [r] report_count
315
+ # @return [Integer] the number of reports
316
+ property :report_count, from: :num_reports
317
+
318
+ # @!attribute [r] whitelist_status
319
+ # @return [String] ad-related whitelist stuff
320
+ property :whitelist_status
321
+
322
+ # @!attribute [r] stickied?
323
+ # @return [Boolean] whether the post was stickied
324
+ property :stickied?, from: :stickied
325
+
326
+ # @!attribute [r] url
327
+ # @return [String] the link url
328
+ property :url
329
+
330
+ # @!attribute [r] quarantined?
331
+ # @return [Boolean] whether the post has been quarantined
332
+ property :quarantined?, from: :quarantine
333
+
334
+ # @!attribute [r] author
335
+ # @return [User] the post author
336
+ property :author, with: ->(n) { User.new(client, name: n) }
337
+
338
+ # @!attribute [r] created_at
339
+ # @return [Time] creation time
340
+ property :created_at, from: :created_utc, with: ->(t) { Time.at(t) }
341
+
342
+ # @!attribute [r] subreddit_name_prefixed
343
+ # @return [String] r/[subreddit name]
344
+ property :subreddit_name_prefixed,
345
+ default: ->() { "r/#{read_attribute(:subreddit).display_name}" }
346
+
347
+ # @!attribute [r] distinguished?
348
+ # @return [Boolean] whether the post is distinguished
349
+ property :distinguished?, from: :distinguished
350
+
351
+ # @!attribute [r] media
352
+ # @return [Hash] media details
353
+ property :media
354
+
355
+ # @!attribute [r] upvote_ratio
356
+ # @return [Float] the upvote ratio (ups/downs)
357
+ property :upvote_ratio
358
+
359
+ # @!attribute [r] mod_reports
360
+ # @return [Array] moderator reports
361
+ property :mod_reports
362
+
363
+ # @!attribute [r] self?
364
+ # @return [Boolean] whether the post is a self post
365
+ property :self?, from: :is_self
366
+
367
+ # @!attribute [r] visited?
368
+ # @return [Boolean] whether the post was visited
369
+ property :visited?, from: :visited
370
+
371
+ # @!attribute [r] subreddit_type
372
+ # @return [String] the subreddit's type
373
+ property :subreddit_type
374
+
375
+ # @!attribute [r] video?
376
+ # @return [Boolean] whether the post is probably a video
377
+ property :video, from: :is_video
378
+
122
379
  private
123
380
 
124
- def default_loader
381
+ def lazer_reload
382
+ fully_loaded!
383
+
125
384
  # Ensure we have the link's id.
126
- id = @attributes[:id] ? @attributes[:id] : @attributes.fetch(:name).sub('t3_', '')
385
+ id = self[:id] ? read_attribute(:id) : read_attribute(:name).sub('t3_', '')
386
+
127
387
  # If a specific sort order was requested, provide it.
128
388
  params = {}
129
- params[:sort] = @sort_order if @sort_order
389
+ params[:sort] = read_attribute(:sort_order) if self[:sort_order]
130
390
 
131
391
  # `response` is a pair (2-element array):
132
392
  # - response[0] is a one-item listing containing the submission
133
393
  # - response[1] is listing of comments
134
- response = @client.get("/comments/#{id}", params).body
135
- response[0][:data][:children][0][:data].merge(comments: @client.unmarshal(response[1]))
136
- end
137
-
138
- def after_initialize
139
- if @attributes[:subreddit]
140
- @attributes[:subreddit] = Subreddit.from_id(@client, @attributes[:subreddit])
141
- end
142
- @attributes[:author] = User.from_id(@client, @attributes[:author]) if @attributes[:author]
394
+ response = client.get("/comments/#{id}", params).body
395
+ response[0][:data][:children][0][:data].merge(comments: response[1][:data])
143
396
  end
144
397
  end
145
398
  end