redditkit 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +22 -0
  3. data/README.md +155 -0
  4. data/Rakefile +8 -0
  5. data/lib/redditkit.rb +26 -0
  6. data/lib/redditkit/base.rb +60 -0
  7. data/lib/redditkit/client.rb +142 -0
  8. data/lib/redditkit/client/account.rb +73 -0
  9. data/lib/redditkit/client/apps.rb +63 -0
  10. data/lib/redditkit/client/captcha.rb +36 -0
  11. data/lib/redditkit/client/comments.rb +54 -0
  12. data/lib/redditkit/client/flair.rb +148 -0
  13. data/lib/redditkit/client/links.rb +134 -0
  14. data/lib/redditkit/client/miscellaneous.rb +50 -0
  15. data/lib/redditkit/client/moderation.rb +179 -0
  16. data/lib/redditkit/client/multireddits.rb +207 -0
  17. data/lib/redditkit/client/private_messages.rb +74 -0
  18. data/lib/redditkit/client/search.rb +25 -0
  19. data/lib/redditkit/client/subreddits.rb +120 -0
  20. data/lib/redditkit/client/users.rb +109 -0
  21. data/lib/redditkit/client/utilities.rb +137 -0
  22. data/lib/redditkit/client/voting.rb +41 -0
  23. data/lib/redditkit/client/wiki.rb +83 -0
  24. data/lib/redditkit/comment.rb +54 -0
  25. data/lib/redditkit/creatable.rb +17 -0
  26. data/lib/redditkit/error.rb +111 -0
  27. data/lib/redditkit/link.rb +140 -0
  28. data/lib/redditkit/moderator_action.rb +19 -0
  29. data/lib/redditkit/multireddit.rb +32 -0
  30. data/lib/redditkit/multireddit_description.rb +14 -0
  31. data/lib/redditkit/paginated_response.rb +22 -0
  32. data/lib/redditkit/private_message.rb +27 -0
  33. data/lib/redditkit/response/parse_json.rb +29 -0
  34. data/lib/redditkit/response/raise_error.rb +21 -0
  35. data/lib/redditkit/subreddit.rb +86 -0
  36. data/lib/redditkit/thing.rb +20 -0
  37. data/lib/redditkit/user.rb +30 -0
  38. data/lib/redditkit/version.rb +19 -0
  39. data/lib/redditkit/votable.rb +37 -0
  40. data/redditkit.gemspec +25 -0
  41. data/spec/cassettes/RedditKit_Client/should_raise_an_error_with_invalid_credentials.yml +39 -0
  42. data/spec/cassettes/RedditKit_Client_Account/_sign_in/signs_the_user_in.yml +132 -0
  43. data/spec/cassettes/RedditKit_Client_Account/_update_session/updates_the_current_session.yml +133 -0
  44. data/spec/cassettes/RedditKit_Client_Captcha/_captcha_url/returns_a_CAPTCHA_url_from_an_identifier.yml +38 -0
  45. data/spec/cassettes/RedditKit_Client_Captcha/_needs_captcha_/checks_if_the_current_account_needs_a_CAPTCHA.yml +44 -0
  46. data/spec/cassettes/RedditKit_Client_Captcha/_new_captcha_identifier/returns_a_new_CAPTCHA_identifier.yml +38 -0
  47. data/spec/cassettes/RedditKit_Client_Comments/_comment/requests_the_correct_resource.yml +47 -0
  48. data/spec/cassettes/RedditKit_Client_Comments/_comments/with_a_RedditKit_Link/returns_comments_on_a_link.yml +140 -0
  49. data/spec/cassettes/RedditKit_Client_Comments/_comments/with_a_link_identifier/returns_comments_on_a_link.yml +89 -0
  50. data/spec/cassettes/RedditKit_Client_Comments/_submit_comment/requests_the_correct_resource.yml +313 -0
  51. data/spec/cassettes/RedditKit_Client_Flair/_apply_flair_template/clears_flair_templates.yml +52 -0
  52. data/spec/cassettes/RedditKit_Client_Flair/_clear_flair_templates/clears_flair_templates.yml +49 -0
  53. data/spec/cassettes/RedditKit_Client_Flair/_create_flair_template/creates_a_flair_template.yml +46 -0
  54. data/spec/cassettes/RedditKit_Client_Flair/_create_flair_template/raises_InvalidClassName.yml +46 -0
  55. data/spec/cassettes/RedditKit_Client_Flair/_create_flair_template/raises_TooManyClassNames.yml +47 -0
  56. data/spec/cassettes/RedditKit_Client_Flair/_delete_user_flair/requests_the_correct_resource.yml +60 -0
  57. data/spec/cassettes/RedditKit_Client_Flair/_flair_list/returns_the_list_of_flair.yml +44 -0
  58. data/spec/cassettes/RedditKit_Client_Flair/_set_flair/requests_the_correct_resource.yml +49 -0
  59. data/spec/cassettes/RedditKit_Client_Flair/_set_flair_options/sets_flair_options.yml +49 -0
  60. data/spec/cassettes/RedditKit_Client_Flair/_set_flair_with_csv/requests_the_correct_resource.yml +51 -0
  61. data/spec/cassettes/RedditKit_Client_Flair/_toggle_flair/requests_the_correct_resource.yml +49 -0
  62. data/spec/cassettes/RedditKit_Client_Links/_front_page/requests_the_correct_category.yml +498 -0
  63. data/spec/cassettes/RedditKit_Client_Links/_front_page/requests_the_correct_resource.yml +603 -0
  64. data/spec/cassettes/RedditKit_Client_Links/_hide/requests_the_correct_resource.yml +46 -0
  65. data/spec/cassettes/RedditKit_Client_Links/_link/returns_a_link.yml +55 -0
  66. data/spec/cassettes/RedditKit_Client_Links/_links/contains_pagination_information.yml +402 -0
  67. data/spec/cassettes/RedditKit_Client_Links/_links/requests_a_certain_number_of_links.yml +186 -0
  68. data/spec/cassettes/RedditKit_Client_Links/_links/requests_front_page_links_if_no_subreddit_is_present.yml +603 -0
  69. data/spec/cassettes/RedditKit_Client_Links/_links/requests_links_with_the_correct_time_frame.yml +375 -0
  70. data/spec/cassettes/RedditKit_Client_Links/_links/requests_the_correct_subreddit_and_category.yml +402 -0
  71. data/spec/cassettes/RedditKit_Client_Links/_links_with_domain/returns_links_with_a_specific_domain.yml +99 -0
  72. data/spec/cassettes/RedditKit_Client_Links/_mark_nsfw/requests_the_correct_resource.yml +46 -0
  73. data/spec/cassettes/RedditKit_Client_Links/_random_link/returns_a_random_link.yml +91 -0
  74. data/spec/cassettes/RedditKit_Client_Links/_submit/raises_RedditKit_InvalidCaptcha_if_no_CAPTCHA_is_filled_out.yml +54 -0
  75. data/spec/cassettes/RedditKit_Client_Links/_unhide/requests_the_correct_resource.yml +46 -0
  76. data/spec/cassettes/RedditKit_Client_Links/_unmark_nsfw/requests_the_correct_resource.yml +46 -0
  77. data/spec/cassettes/RedditKit_Client_Miscellaneous/_delete/requests_the_correct_resource.yml +46 -0
  78. data/spec/cassettes/RedditKit_Client_Miscellaneous/_edit/requests_the_correct_resource.yml +52 -0
  79. data/spec/cassettes/RedditKit_Client_Miscellaneous/_save/saves_an_object.yml +46 -0
  80. data/spec/cassettes/RedditKit_Client_Miscellaneous/_unsave/unsaves_an_object.yml +89 -0
  81. data/spec/cassettes/RedditKit_Client_Moderation/_accept_moderator_invitation/requests_the_correct_resource.yml +53 -0
  82. data/spec/cassettes/RedditKit_Client_Moderation/_ban/requests_the_correct_resource.yml +103 -0
  83. data/spec/cassettes/RedditKit_Client_Moderation/_contributors_to_subreddit/requests_the_correct_resource.yml +47 -0
  84. data/spec/cassettes/RedditKit_Client_Moderation/_ignore_reports/requests_the_correct_resource.yml +46 -0
  85. data/spec/cassettes/RedditKit_Client_Moderation/_moderation_log/returns_RedditKit_ModeratorAction_objects.yml +153 -0
  86. data/spec/cassettes/RedditKit_Client_Moderation/_moderators_of_subreddit/requests_the_correct_resource.yml +48 -0
  87. data/spec/cassettes/RedditKit_Client_Moderation/_reset_subreddit_header/requests_the_correct_resource.yml +55 -0
  88. data/spec/cassettes/RedditKit_Client_Moderation/_set_contest_mode/requests_the_correct_resource.yml +46 -0
  89. data/spec/cassettes/RedditKit_Client_Moderation/_set_sticky_post/requests_the_correct_resource.yml +46 -0
  90. data/spec/cassettes/RedditKit_Client_Moderation/_unban/requests_the_correct_resource.yml +54 -0
  91. data/spec/cassettes/RedditKit_Client_Moderation/_unignore_reports/requests_the_correct_resource.yml +46 -0
  92. data/spec/cassettes/RedditKit_Client_Multireddits/_add_subreddit_to_multireddit/adds_a_subreddit_to_a_multireddit.yml +177 -0
  93. data/spec/cassettes/RedditKit_Client_Multireddits/_create_multireddit/creates_a_multireddit.yml +137 -0
  94. data/spec/cassettes/RedditKit_Client_Multireddits/_create_multireddit/raises_RedditKit_Conflict_when_using_an_existing_name.yml +133 -0
  95. data/spec/cassettes/RedditKit_Client_Multireddits/_delete_multireddit/deletes_a_multireddit.yml +134 -0
  96. data/spec/cassettes/RedditKit_Client_Multireddits/_multireddit/with_a_path/returns_a_multireddit.yml +39 -0
  97. data/spec/cassettes/RedditKit_Client_Multireddits/_multireddit/without_a_path/returns_a_multireddit.yml +39 -0
  98. data/spec/cassettes/RedditKit_Client_Multireddits/_multireddit_description/with_a_multireddit/returns_a_multireddit_description.yml +81 -0
  99. data/spec/cassettes/RedditKit_Client_Multireddits/_multireddit_description/with_a_username_and_multireddit_name/returns_a_multireddit_description.yml +45 -0
  100. data/spec/cassettes/RedditKit_Client_Multireddits/_my_multireddits/return_s_the_user_s_multireddits.yml +47 -0
  101. data/spec/cassettes/RedditKit_Client_Multireddits/_remove_subreddit_from_multireddit/removes_a_subreddit_from_a_multireddit.yml +175 -0
  102. data/spec/cassettes/RedditKit_Client_Multireddits/_rename_multireddit/renames_a_multireddit.yml +134 -0
  103. data/spec/cassettes/RedditKit_Client_Multireddits/_set_multireddit_description/returns_a_multireddit_description.yml +48 -0
  104. data/spec/cassettes/RedditKit_Client_Multireddits/_update_multireddit/updates_a_multireddit.yml +184 -0
  105. data/spec/cassettes/RedditKit_Client_PrivateMessages/_block_author_of_message/requests_the_correct_resource.yml +46 -0
  106. data/spec/cassettes/RedditKit_Client_PrivateMessages/_mark_as_read/requests_the_correct_resource.yml +51 -0
  107. data/spec/cassettes/RedditKit_Client_PrivateMessages/_mark_as_unread/requests_the_correct_resource.yml +51 -0
  108. data/spec/cassettes/RedditKit_Client_PrivateMessages/_messages/requests_the_correct_resource.yml +187 -0
  109. data/spec/cassettes/RedditKit_Client_PrivateMessages/_unblock/requests_the_correct_resource.yml +46 -0
  110. data/spec/cassettes/RedditKit_Client_Search/_search/restricts_searches_to_a_specific_subreddit.yml +878 -0
  111. data/spec/cassettes/RedditKit_Client_Search/_search/returns_a_specific_number_of_results.yml +130 -0
  112. data/spec/cassettes/RedditKit_Client_Search/_search/returns_search_results.yml +844 -0
  113. data/spec/cassettes/RedditKit_Client_Subreddits/_random_subreddit/returns_a_random_subreddit.yml +181 -0
  114. data/spec/cassettes/RedditKit_Client_Subreddits/_recommended_subreddits/returns_subreddit_names.yml +37 -0
  115. data/spec/cassettes/RedditKit_Client_Subreddits/_search_subreddits_by_name/returns_subreddit_names.yml +875 -0
  116. data/spec/cassettes/RedditKit_Client_Subreddits/_subreddit/returns_a_specified_subreddit.yml +100 -0
  117. data/spec/cassettes/RedditKit_Client_Subreddits/_subreddits/returns_a_specified_number_of_subreddits.yml +505 -0
  118. data/spec/cassettes/RedditKit_Client_Subreddits/_subreddits/returns_subreddits_from_a_specific_category.yml +510 -0
  119. data/spec/cassettes/RedditKit_Client_Subreddits/_subreddits_by_topic/returns_subreddit_names.yml +41 -0
  120. data/spec/cassettes/RedditKit_Client_Subreddits/_subscribe/requests_the_correct_resource.yml +46 -0
  121. data/spec/cassettes/RedditKit_Client_Subreddits/_subscribed_subreddits/returns_a_specified_number_of_subreddits.yml +415 -0
  122. data/spec/cassettes/RedditKit_Client_Subreddits/_subscribed_subreddits/returns_subreddits_from_a_specific_category.yml +58 -0
  123. data/spec/cassettes/RedditKit_Client_Subreddits/_subscribed_subreddits/returns_the_user_s_subscribed_subreddits.yml +3469 -0
  124. data/spec/cassettes/RedditKit_Client_Subreddits/_unsubscribe/requests_the_correct_resource.yml +46 -0
  125. data/spec/cassettes/RedditKit_Client_Users/_friends/returns_the_user_s_friends.yml +48 -0
  126. data/spec/cassettes/RedditKit_Client_Users/_my_content/returns_the_user_s_content.yml +60 -0
  127. data/spec/cassettes/RedditKit_Client_Users/_user/requests_the_correct_resource.yml +48 -0
  128. data/spec/cassettes/RedditKit_Client_Users/_user/returns_a_specified_user.yml +48 -0
  129. data/spec/cassettes/RedditKit_Client_Users/_user/returns_the_authenticated_user.yml +48 -0
  130. data/spec/cassettes/RedditKit_Client_Users/_user_content/returns_the_user_s_content.yml +41 -0
  131. data/spec/cassettes/RedditKit_Client_Users/_username_available_/returns_false_for_an_unavailable_username.yml +36 -0
  132. data/spec/cassettes/RedditKit_Client_Users/_username_available_/returns_true_for_an_available_username.yml +36 -0
  133. data/spec/cassettes/RedditKit_Client_Voting/_downvote/with_a_comment_full_name_passed/downvotes_the_comment.yml +100 -0
  134. data/spec/cassettes/RedditKit_Client_Voting/_downvote/with_a_comment_passed/downvotes_the_comment.yml +154 -0
  135. data/spec/cassettes/RedditKit_Client_Voting/_downvote/with_a_link_full_name_passed/downvotes_the_link.yml +106 -0
  136. data/spec/cassettes/RedditKit_Client_Voting/_downvote/with_a_link_passed/downvotes_the_link.yml +166 -0
  137. data/spec/cassettes/RedditKit_Client_Voting/_upvote/with_a_comment_full_name_passed/upvotes_the_comment.yml +100 -0
  138. data/spec/cassettes/RedditKit_Client_Voting/_upvote/with_a_comment_passed/upvotes_the_comment.yml +154 -0
  139. data/spec/cassettes/RedditKit_Client_Voting/_upvote/with_a_link_full_name_passed/upvotes_the_link.yml +106 -0
  140. data/spec/cassettes/RedditKit_Client_Voting/_upvote/with_a_link_passed/upvotes_the_link.yml +166 -0
  141. data/spec/cassettes/RedditKit_Client_Voting/_withdraw_vote/with_a_comment_full_name_passed/withdraws_the_vote_on_the_comment.yml +154 -0
  142. data/spec/cassettes/RedditKit_Client_Voting/_withdraw_vote/with_a_comment_passed/withdraws_the_vote_on_the_comment.yml +208 -0
  143. data/spec/cassettes/RedditKit_Client_Voting/_withdraw_vote/with_a_link_full_name_passed/withdraws_the_vote_on_the_link.yml +166 -0
  144. data/spec/cassettes/RedditKit_Client_Voting/_withdraw_vote/with_a_link_passed/withdraws_the_vote_on_the_link.yml +226 -0
  145. data/spec/cassettes/RedditKit_Client_Wiki/_add_wiki_editor/requests_the_correct_resource.yml +46 -0
  146. data/spec/cassettes/RedditKit_Client_Wiki/_edit_wiki_page/requests_the_correct_resource.yml +48 -0
  147. data/spec/cassettes/RedditKit_Client_Wiki/_hide_wiki_revision/requests_the_correct_resource.yml +46 -0
  148. data/spec/cassettes/RedditKit_Client_Wiki/_remove_wiki_editor/requests_the_correct_resource.yml +46 -0
  149. data/spec/cassettes/RedditKit_Client_Wiki/_revert_to_revision/requests_the_correct_resource.yml +46 -0
  150. data/spec/cassettes/RedditKit_Comment/should_not_be_deleted_if_neither_author_and_comment_attributes_are_set_to_deleted_.yml +90 -0
  151. data/spec/cassettes/RedditKit_Comment/should_return_replies.yml +90 -0
  152. data/spec/cassettes/authenticated_client.yml +87 -0
  153. data/spec/redditkit/base_spec.rb +45 -0
  154. data/spec/redditkit/client/account_spec.rb +50 -0
  155. data/spec/redditkit/client/apps_spec.rb +58 -0
  156. data/spec/redditkit/client/captcha_spec.rb +30 -0
  157. data/spec/redditkit/client/comments_spec.rb +40 -0
  158. data/spec/redditkit/client/flair_spec.rb +92 -0
  159. data/spec/redditkit/client/links_spec.rb +103 -0
  160. data/spec/redditkit/client/miscellaneous_spec.rb +40 -0
  161. data/spec/redditkit/client/moderation_spec.rb +141 -0
  162. data/spec/redditkit/client/multireddits_spec.rb +158 -0
  163. data/spec/redditkit/client/private_messages_spec.rb +51 -0
  164. data/spec/redditkit/client/search_spec.rb +25 -0
  165. data/spec/redditkit/client/subreddits_spec.rb +83 -0
  166. data/spec/redditkit/client/users_spec.rb +92 -0
  167. data/spec/redditkit/client/voting_spec.rb +99 -0
  168. data/spec/redditkit/client/wiki_spec.rb +40 -0
  169. data/spec/redditkit/client_spec.rb +46 -0
  170. data/spec/redditkit/comment_spec.rb +26 -0
  171. data/spec/redditkit/creatable_spec.rb +24 -0
  172. data/spec/redditkit/error_spec.rb +61 -0
  173. data/spec/redditkit/link_spec.rb +33 -0
  174. data/spec/redditkit/multireddit_spec.rb +27 -0
  175. data/spec/redditkit/paginated_response_spec.rb +23 -0
  176. data/spec/redditkit/thing_spec.rb +18 -0
  177. data/spec/redditkit/votable_spec.rb +52 -0
  178. data/spec/redditkit_spec.rb +21 -0
  179. data/spec/spec_helper.rb +124 -0
  180. metadata +390 -0
@@ -0,0 +1,25 @@
1
+ module RedditKit
2
+ class Client
3
+
4
+ # Methods for searching reddit's links.
5
+ module Search
6
+
7
+ # Search for links.
8
+ #
9
+ # @param query [String] The search query.
10
+ # @option options [true, false] :restrict_to_subreddit Whether to search only in a specified subreddit.
11
+ # @option options [String, RedditKit::Subreddit] :subreddit The optional subreddit to search.
12
+ # @option options [1..100] limit The number of links to return.
13
+ # @option options [String] before Only return links before this full name.
14
+ # @option options [String] after Only return links after this full name.
15
+ # @return [RedditKit::PaginatedResponse]
16
+ def search(query, options = {})
17
+ path = "%s/search.json" % ('r/' + options[:subreddit] if options[:subreddit])
18
+ parameters = { :q => query, :restrict_sr => options[:restrict_to_subreddit], :limit => options[:limit] }
19
+
20
+ objects_from_response(:get, path, parameters)
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,120 @@
1
+ require 'redditkit/subreddit'
2
+
3
+ module RedditKit
4
+ class Client
5
+
6
+ # Methods for interacting with subreddits.
7
+ module Subreddits
8
+
9
+ # Gets subreddits from a specified category.
10
+ #
11
+ # @option options [new, popular, banned] category The category of subreddits. Defaults to popular.
12
+ # @option options [1..100] limit The number of subreddits to return.
13
+ # @option options [String] before Only return subreddits before this id.
14
+ # @option options [String] after Only return subreddits after this id.
15
+ # @return [RedditKit::PaginatedResponse]
16
+ def subreddits(options = {})
17
+ category = options[:category] or 'popular'
18
+ path = "reddits/#{category}.json"
19
+ options.delete :category
20
+
21
+ objects_from_response(:get, path, options)
22
+ end
23
+
24
+ # Gets the current user's subscribed subreddits.
25
+ #
26
+ # @option options [subscriber, contributor, moderator] category The category from which to return subreddits. Defaults to subscriber.
27
+ # @option options [1..100] limit The number of subreddits to return.
28
+ # @option options [String] before Only return subreddits before this id.
29
+ # @option options [String] after Only return subreddits after this id.
30
+ # @return [RedditKit::PaginatedResponse]
31
+ def subscribed_subreddits(options = {})
32
+ category = options[:category] or 'subscriber'
33
+ path = "subreddits/mine/#{category}.json"
34
+ options.delete :category
35
+
36
+ objects_from_response(:get, path, options)
37
+ end
38
+
39
+ # Gets a subreddit object.
40
+ #
41
+ # @param subreddit_name [String] A subreddit's display name.
42
+ # @return [RedditKit::Subreddit]
43
+ # @example client.subreddit "programming"
44
+ def subreddit(subreddit_name)
45
+ object_from_response(:get, "r/#{subreddit_name}/about.json", nil)
46
+ end
47
+
48
+ # Subscribes to a subreddit.
49
+ #
50
+ # @param subreddit [String, RedditKit::Subreddit] A subreddit's full name, or a RedditKit::Subreddit.
51
+ def subscribe(subreddit)
52
+ full_name = extract_full_name subreddit
53
+ parameters = { :action => 'sub', :sr => full_name }
54
+
55
+ post("api/subscribe", parameters)
56
+ end
57
+
58
+ # Unsubscribes from a subreddit.
59
+ #
60
+ # @param subreddit [String, RedditKit::Subreddit] A subreddit's full name, or a RedditKit::Subreddit.
61
+ def unsubscribe(subreddit)
62
+ full_name = extract_full_name subreddit
63
+ parameters = { :action => 'unsub', :sr => full_name }
64
+
65
+ post("api/subscribe", parameters)
66
+ end
67
+
68
+ # Gets a random subreddit.
69
+ #
70
+ # @return [RedditKit::Subreddit]
71
+ def random_subreddit
72
+ response = get('r/random', nil)
73
+ headers = response[:response_headers]
74
+ location = headers[:location]
75
+
76
+ subreddit_name = location[/\/r\/(.*)\//, 1]
77
+ subreddit subreddit_name
78
+ end
79
+
80
+ # Searches for subreddits with a specific name.
81
+ #
82
+ # @param name [String] The name to search for.
83
+ # @return [RedditKit::PaginatedResponse]
84
+ def search_subreddits_by_name(name)
85
+ parameters = { :q => name }
86
+ objects_from_response :get, 'subreddits/search.json', parameters
87
+ end
88
+
89
+ # Gets an array of subreddit names by topic.
90
+ #
91
+ # @param topic [String] The desired topic.
92
+ # @return [Array<String>] An array of subreddit names.
93
+ # @example RedditKit.subreddits_by_topic 'programming'
94
+ def subreddits_by_topic(topic)
95
+ parameters = { :query => topic }
96
+
97
+ response = get('api/subreddits_by_topic.json', parameters)
98
+ body = response[:body]
99
+
100
+ body.collect { |subreddit| subreddit[:name] }
101
+ end
102
+
103
+ # Gets an array of recommended subreddits.
104
+ #
105
+ # @param subreddits [Array<String>] An array of subreddit names.
106
+ # @return [Array<String>] An array of recommended subreddit names.
107
+ # @example RedditKit.recommended_subreddits %w(ruby programming)
108
+ def recommended_subreddits(subreddits)
109
+ names = subreddits.join(',')
110
+ parameters = { :srnames => names }
111
+
112
+ response = get('api/subreddit_recommendations.json', parameters)
113
+ body = response[:body]
114
+
115
+ body.collect { |subreddit| subreddit[:sr_name] }
116
+ end
117
+
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,109 @@
1
+ require 'redditkit/user'
2
+
3
+ module RedditKit
4
+ class Client
5
+
6
+ # Methods for interacting with reddit users.
7
+ module Users
8
+
9
+ # Gets a user object.
10
+ #
11
+ # @param username [String] A reddit account's username. Gets the current user if this is nil.
12
+ # @return [RedditKit::User]
13
+ # @example current_user = client.user
14
+ # @example user = client.user 'amberlynns'
15
+ def user(username = nil)
16
+ if username
17
+ object_from_response(:get, "user/#{username}/about.json", nil)
18
+ else
19
+ object_from_response(:get, "api/me.json", nil)
20
+ end
21
+ end
22
+
23
+ # Gets links and comments for the current user.
24
+ #
25
+ # @option options [overview, comments, submitted, liked, disliked] :category The category from which to return links and comments. Defaults to overview.
26
+ # @option options [1..100] :limit The number of links and comments to return.
27
+ # @option options [String] :before Only return links and comments before this id.
28
+ # @option options [String] :after Only return links and comments after this id.
29
+ # @return [RedditKit::PaginatedResponse]
30
+ def my_content(options = {})
31
+ category = options[:category] || :overview
32
+ path = "user/#{@username}/#{category}.json"
33
+ options.delete :category
34
+
35
+ objects_from_response(:get, path, options)
36
+ end
37
+
38
+ # Gets links and comments for a user.
39
+ #
40
+ # @option options [overview, comments, submitted, liked, disliked] :category The category from which to return links and comments. Defaults to overview.
41
+ # @option options [1..100] :limit The number of links and comments to return.
42
+ # @option options [String] :before Only return links and comments before this id.
43
+ # @option options [String] :after Only return links and comments after this id.
44
+ # @return [RedditKit::PaginatedResponse]
45
+ # @note Public access to the liked and disliked categories is disabled by default, so this will return an empty array for most users.
46
+ def user_content(user, options = {})
47
+ username = user
48
+
49
+ path = "user/#{username}/%s.json" % (options[:category] if options[:category])
50
+ options.delete :category
51
+
52
+ objects_from_response(:get, path, options)
53
+ end
54
+
55
+ # Gets the current user's friends.
56
+ #
57
+ # @return [Array<OpenStruct>]
58
+ def friends
59
+ response = request(:get, 'prefs/friends.json', nil, https_connection)
60
+ body = response[:body]
61
+ friends = body[0][:data][:children]
62
+
63
+ friends.collect { |friend| OpenStruct.new(friend) }
64
+ end
65
+
66
+ # Adds a user to the current user's friend list.
67
+ #
68
+ # @param user [String, RedditKit::User] A user's username, or a RedditKit::User.
69
+ def friend(user)
70
+ friend_name = extract_string(user, :username)
71
+ friend_request 'friend', :container => current_user.full_name, :name => friend_name, :type => :friend
72
+ end
73
+
74
+ # Removes a user from the current user's friend list.
75
+ #
76
+ # @param user [String, RedditKit::User] A user's ID, or a RedditKit::User.
77
+ def unfriend(user)
78
+ friend_name = extract_string(user, :username)
79
+ friend_request 'unfriend', :container => current_user.full_name, :name => friend_name, :type => :friend
80
+ end
81
+
82
+ # Checks whether a specific username is available.
83
+ #
84
+ # @param username [String] A username for which to check availability.
85
+ # @return [Boolean]
86
+ # @example puts "Username is available" if client.username_available? 'some_username'
87
+ def username_available?(username)
88
+ response = get('api/username_available.json', :user => username)
89
+ available = response[:body]
90
+
91
+ available == 'true'
92
+ end
93
+
94
+ # Registers a new reddit account.
95
+ #
96
+ # @option options [String] username The username to register.
97
+ # @option options [String] password The password for the account.
98
+ # @option options [String] email The optional email address for the account.
99
+ # @option options [String] captcha_identifier The identifier for the CAPTCHA challenge solved by the user.
100
+ # @option options [String] captcha The user's response to the CAPTCHA challenge.
101
+ # @option options [Boolean] remember Whether to keep the user's session cookie beyond the current session.
102
+ def register(username, password, options = {})
103
+ parameters = { :user => username, :passwd => password, :passwd2 => password, :captcha => options[:captcha], :iden => options[:captcha_identifier] }
104
+ post('api/register', parameters)
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,137 @@
1
+ require 'redditkit/paginated_response'
2
+
3
+ module RedditKit
4
+ class Client
5
+
6
+ # Methods for streamlining requests to reddit's servers.
7
+ module Utilities
8
+
9
+ private
10
+
11
+ # Return an id from a string or a RedditKit::Thing object.
12
+ #
13
+ # @param object [String, RedditKit::Thing] A string or object.
14
+ # @return [String]
15
+ def extract_id(object)
16
+ extract_string object, :id
17
+ end
18
+
19
+ # Return a full name from a string or a RedditKit::Thing object.
20
+ #
21
+ # @param object [String, RedditKit::Thing] A string or object.
22
+ # @return [String]
23
+ def extract_full_name(object)
24
+ extract_string object, :full_name
25
+ end
26
+
27
+ def extract_string(object, attribute_name)
28
+ case object
29
+ when ::String
30
+ object
31
+ else
32
+ object.send attribute_name if object.respond_to? attribute_name
33
+ end
34
+ end
35
+
36
+ # Return the class of an object from a response.
37
+ #
38
+ # @param response [Faraday::Response] A response.
39
+ # @return [Class]
40
+ def object_class_from_response(response)
41
+ kind = object_kind_from_response(response)
42
+ object_class_from_kind(kind)
43
+ end
44
+
45
+ # Return the class of an object of a given kind.
46
+ #
47
+ # @param kind [String] The object's kind.
48
+ # @return [Class]
49
+ def object_class_from_kind(kind)
50
+ case kind
51
+ when "t1"
52
+ RedditKit::Comment
53
+ when "t2"
54
+ RedditKit::User
55
+ when "t3"
56
+ RedditKit::Link
57
+ when "t4"
58
+ RedditKit::PrivateMessage
59
+ when "t5"
60
+ RedditKit::Subreddit
61
+ when "LabeledMulti"
62
+ RedditKit::Multireddit
63
+ when "LabeledMultiDescription"
64
+ RedditKit::MultiredditDescription
65
+ when "modaction"
66
+ RedditKit::ModeratorAction
67
+ end
68
+ end
69
+
70
+ def object_kind_from_response(response)
71
+ response[:kind]
72
+ end
73
+
74
+ def object_from_response(request_type, path, parameters = {})
75
+ response = send(request_type.to_sym, path, parameters)
76
+ body = response[:body]
77
+
78
+ object_class = object_class_from_response(body)
79
+ object_class.new(body) if object_class
80
+ end
81
+
82
+ def objects_from_response(request_type, path, parameters = {})
83
+ response = send(request_type.to_sym, path, parameters)
84
+ body = response[:body]
85
+
86
+ if body.is_a?(Hash) and body[:kind] == 'Listing'
87
+ data = body[:data]
88
+ results = objects_from_listing(body)
89
+
90
+ RedditKit::PaginatedResponse.new(data[:before], data[:after], results)
91
+ elsif body.is_a?(Array)
92
+ objects_from_array body
93
+ elsif body.is_a?(Hash)
94
+ objects_from_array body[:data]
95
+ end
96
+ end
97
+
98
+ def objects_from_listing(listing)
99
+ children = listing[:data][:children]
100
+ objects_from_array children
101
+ end
102
+
103
+ def objects_from_array(array)
104
+ array.map do |thing|
105
+ object_class = object_class_from_response(thing)
106
+ object_class.new(thing) if object_class
107
+ end
108
+ end
109
+
110
+ def comments_from_response(request_type, path, parameters = {})
111
+ response = send(request_type.to_sym, path, parameters)
112
+ body = response[:body]
113
+ comments_listing = body.last
114
+
115
+ objects_from_listing(comments_listing)
116
+ end
117
+
118
+ def path_for_multireddit(username, multireddit_name)
119
+ "/user/#{username}/m/#{multireddit_name}"
120
+ end
121
+
122
+ # Performs a friend or unfriend request.
123
+ #
124
+ # @param type [friend, unfriend] The type of request.
125
+ # @param options Any parameters to send with the request.
126
+ def friend_request(type, options)
127
+ if options[:subreddit]
128
+ options[:r] = options[:subreddit]
129
+ options.delete :subreddit
130
+ end
131
+
132
+ post("api/#{type}", options)
133
+ end
134
+
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,41 @@
1
+ module RedditKit
2
+ class Client
3
+
4
+ # Methods for voting on links and comments.
5
+ module Voting
6
+
7
+ # Upvotes a link or comment.
8
+ #
9
+ # @param link_or_comment [String, RedditKit::Comment, RedditKit::Link] The link or comment to upvote.
10
+ def upvote(link_or_comment)
11
+ vote link_or_comment, 1
12
+ end
13
+
14
+ # Downvotes a link or comment.
15
+ #
16
+ # @param link_or_comment [String, RedditKit::Comment, RedditKit::Link] The link or comment to downvote.
17
+ def downvote(link_or_comment)
18
+ vote link_or_comment, -1
19
+ end
20
+
21
+ # Withdraws a vote on a link or comment.
22
+ #
23
+ # @param link_or_comment [String, RedditKit::Comment, RedditKit::Link] The link or comment from which to withdraw the vote.
24
+ def withdraw_vote(link_or_comment)
25
+ vote link_or_comment, 0
26
+ end
27
+
28
+ # Votes on a link or comment.
29
+ #
30
+ # @param link_or_comment [String, RedditKit::Comment, RedditKit::Link] The link or comment from which to withdraw the vote.
31
+ # @param direction [-1, 0, 1] Downvote, no vote, and upvote respectively.
32
+ def vote(link_or_comment, direction)
33
+ full_name = extract_full_name(link_or_comment)
34
+ parameters = { :id => full_name, :dir => direction, :api_type => 'json' }
35
+
36
+ post('api/vote', parameters)
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,83 @@
1
+ module RedditKit
2
+ class Client
3
+
4
+ # Methods for interacting with a subreddit's wiki.
5
+ module Wiki
6
+
7
+ # Adds a user as an approved editor of a wiki page.
8
+ #
9
+ # @param subreddit [String, RedditKit::Subreddit] A subreddit's display name, or a RedditKit::Subreddit.
10
+ # @param user [String, RedditKit::User] A user's full name, or a RedditKit::User.
11
+ # @param page [String] page The name of an existing wiki page.
12
+ def add_wiki_editor(subreddit, user, page)
13
+ toggle_wiki_editor(subreddit, user, page, 'add')
14
+ end
15
+
16
+ # Removes a user from being an approved editor of a wiki page.
17
+ #
18
+ # @param subreddit [String, RedditKit::Subreddit] A subreddit's display name, or a RedditKit::Subreddit.
19
+ # @param user [String, RedditKit::User] A user's full name, or a RedditKit::User.
20
+ # @param page [String] page The name of an existing wiki page.
21
+ def remove_wiki_editor(subreddit, user, page)
22
+ toggle_wiki_editor(subreddit, user, page, 'del')
23
+ end
24
+
25
+ # Edits a wiki page.
26
+ #
27
+ # @option options [String, RedditKit::Subreddit] subreddit A subreddit's display name, or a RedditKit::Subreddit.
28
+ # @option options [String] page The name of an existing wiki page.
29
+ # @option options [String] content The contents of the edit.
30
+ # @option options [String] reason The reason for the edit.
31
+ # @option options [String] previous_revision The starting revision for this edit.
32
+ def edit_wiki_page(options)
33
+ subreddit_name = extract_string(options[:subreddit], :display_name)
34
+ parameters = { :page => options[:page], :previous => options[:previous_revision], :content => options[:content], :reason => options[:reason] }
35
+
36
+ post("r/#{subreddit_name}/api/wiki/edit", parameters)
37
+ end
38
+
39
+ # Hides a wiki page revision. If the revision is already hidden, this will unhide it.
40
+ #
41
+ # @option options [String, RedditKit::Subreddit] subreddit A subreddit's display name, or a RedditKit::Subreddit.
42
+ # @option options [String] page The name of an existing wiki page.
43
+ # @option options [String] revision The revision to hide.
44
+ # @return [Boolean] True if the revision is now hidden, false if it is not hidden.
45
+ def hide_wiki_revision(options)
46
+ subreddit_name = extract_string(options[:subreddit], :display_name)
47
+ options.delete :subreddit
48
+
49
+ response = post("r/#{subreddit_name}/api/wiki/hide", options)
50
+ response[:body][:status]
51
+ end
52
+
53
+ # Reverts to a specific wiki page revision.
54
+ #
55
+ # @option options [String, RedditKit::Subreddit] subreddit A subreddit's display name, or a RedditKit::Subreddit.
56
+ # @option options [String] page The name of an existing wiki page.
57
+ # @option options [String] revision The revision to revert to.
58
+ def revert_to_revision(options)
59
+ subreddit_name = extract_string(options[:subreddit], :display_name)
60
+ options.delete :subreddit
61
+
62
+ post("r/#{subreddit_name}/api/wiki/revert", options)
63
+ end
64
+
65
+ private
66
+
67
+ # Adds or removes a user as an approved editor of a wiki page.
68
+ #
69
+ # @param subreddit [String, RedditKit::Subreddit] A subreddit's display name, or a RedditKit::Subreddit.
70
+ # @param user [String, RedditKit::User] A user's full name, or a RedditKit::User.
71
+ # @param page [String] page The name of an existing wiki page.
72
+ # @param status [add, del] Whether to add or delete a user.
73
+ def toggle_wiki_editor(subreddit, user, page, status)
74
+ subreddit_name = extract_string(subreddit, :display_name)
75
+ username = extract_string(user, :username)
76
+ parameters = { :page => page, :username => username }
77
+
78
+ post("r/#{subreddit_name}/api/wiki/alloweditor/#{status}", parameters)
79
+ end
80
+
81
+ end
82
+ end
83
+ end