redd 0.8.8 → 0.9.0.pre.1

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.
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