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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bf49ee7e4888671f3860d38d4a794b6594207827
4
+ data.tar.gz: 9495006c5cc268dd6df62780c97017521239c17f
5
+ SHA512:
6
+ metadata.gz: d9e8b304a65560e2df483a9b0b55bfb8811647691e61afdb71ed454e7653fee11e8db600e28c23d6f944ff634e30d9d32a422994abe9fc96de9d8e143d9d59d6
7
+ data.tar.gz: b5fbc3f4729e5ed803d029d206369ff80132d697f73cd099fdb56fab15aaad9b0a049b84c7e548f0ebe29e57f5f791e57616c0b8661399cec172cea4f45c296c
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Sam Symons
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # RedditKit.rb
2
+
3
+ RedditKit.rb is a [reddit API](http://www.reddit.com/dev/api) wrapper, written in Ruby.
4
+
5
+ [![Build Status](https://travis-ci.org/samsymons/RedditKit.rb.png?branch=master)][travis]
6
+ [![Code Climate](https://codeclimate.com/github/samsymons/RedditKit.rb.png)][codeclimate]
7
+ [![Coverage Status](https://coveralls.io/repos/samsymons/RedditKit.rb/badge.png?branch=master)][coveralls]
8
+
9
+ [travis]: http://travis-ci.org/samsymons/RedditKit.rb
10
+ [codeclimate]: https://codeclimate.com/github/samsymons/RedditKit.rb
11
+ [coveralls]: https://coveralls.io/r/samsymons/RedditKit.rb
12
+
13
+ ## Installation
14
+
15
+ Add this to your Gemfile:
16
+
17
+ gem 'redditkit', '~> 1.0'
18
+
19
+ Or install it directly:
20
+
21
+ gem install redditkit
22
+
23
+ ## Getting Started
24
+
25
+ RedditKit.rb is structured closely to the wonderful [Octokit.rb](https://github.com/octokit/octokit.rb) and [Twitter](https://github.com/sferik/twitter) gems. If you're familiar with either of those, you'll feel right at home here. You can find the [project's documentation on the RedditKit website](http://redditkit.com/redditkit.rb/).
26
+
27
+ RedditKit.rb is used through either the `RedditKit` module, or `RedditKit::Client` objects, like so:
28
+
29
+ **Module usage:**
30
+ ```ruby
31
+ RedditKit.sign_in 'username', 'password'
32
+ subreddits = RedditKit.subscribed_subreddits
33
+ ```
34
+
35
+ **Instance method usage:**
36
+ ```ruby
37
+ client = RedditKit::Client.new 'username', 'password'
38
+ subreddits = client.subscribed_subreddits
39
+ ```
40
+
41
+ Using RedditKit.rb at the module level allows you to use a single account without having to keep track of RedditKit::Client instances. Working at the instance method level makes it possible to use multiple accounts at once, with one client object per account.
42
+
43
+ > RedditKit.rb doesn't have any built-in rate limiting. reddit's API rules require that you make no more than 30 requests per minute and try to avoid requesting the same page more than once every 30 seconds. You can read up on the API rules [on their wiki page](https://github.com/reddit/reddit/wiki/API).
44
+
45
+ ### Authentication
46
+
47
+ ```ruby
48
+ client = RedditKit::Client.new 'username', 'password'
49
+ client.signed_in? # => true
50
+ ```
51
+
52
+ ## More Examples
53
+
54
+ **Fetch a user and check their link karma:**
55
+
56
+ ```ruby
57
+ user = RedditKit.user 'samsymons'
58
+ puts "#{user.username} has #{user.link_karma} link karma."
59
+ ```
60
+
61
+ **Subscribe to a subreddit:**
62
+
63
+ ```ruby
64
+ authenticated_client = RedditKit::Client.new 'samsymons', 'password'
65
+ authenticated_client.subscribe 'ruby'
66
+ ```
67
+
68
+ **Upvote the top post in a subreddit:**
69
+
70
+ ```ruby
71
+ posts = authenticated_client.posts 'programming', :category => :top, :time => :all
72
+ authenticated_client.upvote posts.first
73
+ ```
74
+
75
+ **Send private messages:**
76
+
77
+ ```ruby
78
+ authenticated_client.send_message 'How are you?', 'amberlynns', :subject => 'Hi!'
79
+ ```
80
+
81
+ ## Pagination
82
+
83
+ Some RedditKit.rb methods accept pagination options and return `RedditKit::PaginatedResponse` objects upon completion. These options allow you to, for example, limit the number of results returned, or fetch results before/after a specific object.
84
+
85
+ `RedditKit::PaginatedResponse` forwards its enumeration methods to its `results` array, so you can iterate over it like you would with a standard array.
86
+
87
+ ``` ruby
88
+ paginated_response = RedditKit.front_page
89
+
90
+ paginated_response.each do |link|
91
+ # Do something with each link.
92
+ end
93
+ ```
94
+
95
+ ## Multiple Accounts
96
+
97
+ ## Configuration
98
+
99
+ You can configure various aspects of RedditKit.rb's operation, including its default API endpoint and user agent, by setting attributes on `RedditKit::Client`.
100
+
101
+ **You should set your user agent to the name and version of your app, along with your reddit username. That way, if you ever have a buggy version of your app abusing the API, the reddit admins will know who to contact.**
102
+
103
+ ## Contributing
104
+
105
+ ### Debugging
106
+
107
+ Because RedditKit.rb is built atop Faraday, you can modify its middleware stack to add new behaviour. This is particularly handy for debugging as you can turn on Faraday's response logger.
108
+
109
+ ```ruby
110
+ RedditKit.middleware = Faraday::Builder.new do |builder|
111
+ builder.use Faraday::Request::UrlEncoded
112
+ builder.use RedditKit::Response::RaiseError
113
+ builder.use RedditKit::Response::ParseJSON
114
+ builder.use Faraday::Response::Logger
115
+ builder.adapter Faraday.default_adapter
116
+ end
117
+ ```
118
+
119
+ ### Writing Tests
120
+
121
+ Tests assume the presence of a `.env` file at the project's root. This file should contain the following three environment variables:
122
+
123
+ * `REDDITKIT_TEST_USERNAME` The username of a reddit account dedicated solely to testing.
124
+ * `REDDITKIT_TEST_PASSWORD` The password for the reddit account.
125
+ * `REDDITKIT_TEST_SUBREDDIT` A subreddit for which the provided reddit account has admin privileges. This subreddit should be also be dedicated to testing as the test suite will run many different methods on it, creating & deleting various resources.
126
+
127
+ ## Requirements
128
+
129
+ Ruby 1.9.3 and Ruby 2.0.0 are officially supported.
130
+
131
+ ## Need Help?
132
+
133
+ Open an [issue](https://github.com/samsymons/RedditKit.rb/issues), or hit me up on [Twitter](http://twitter.com/sam_symons).
134
+
135
+ ## License
136
+
137
+ Copyright (c) 2013 Sam Symons (http://samsymons.com/)
138
+
139
+ Permission is hereby granted, free of charge, to any person obtaining a copy
140
+ of this software and associated documentation files (the "Software"), to deal
141
+ in the Software without restriction, including without limitation the rights
142
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
143
+ copies of the Software, and to permit persons to whom the Software is
144
+ furnished to do so, subject to the following conditions:
145
+
146
+ The above copyright notice and this permission notice shall be included in
147
+ all copies or substantial portions of the Software.
148
+
149
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
150
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
151
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
152
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
153
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
154
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
155
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :test => :spec
8
+ task :default => :spec
data/lib/redditkit.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'redditkit/client'
2
+
3
+ # The main RedditKit module.
4
+ module RedditKit
5
+ class << self
6
+
7
+ # A RedditKit::Client, used when calling methods on the RedditKit module itself.
8
+ #
9
+ # @return [RedditKit::Client]
10
+ def client
11
+ @client ||= RedditKit::Client.new
12
+ end
13
+
14
+ def respond_to?(method_name, include_private = false)
15
+ client.respond_to?(method_name, include_private) || super
16
+ end
17
+
18
+ private
19
+
20
+ def method_missing(method_name, *args, &block)
21
+ return super unless client.respond_to?(method_name)
22
+ client.send(method_name, *args, &block)
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ module RedditKit
2
+
3
+ # A base class for RedditKit's model objects, automatically generating attribute and predicate methods.
4
+ class Base
5
+
6
+ attr_reader :attributes
7
+
8
+ class << self
9
+
10
+ def attr_reader(*attrs)
11
+ attrs.each do |attr|
12
+ define_attribute_method(attr)
13
+ define_predicate_method(attr)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def define_attribute_method(method)
20
+ define_method(method) do
21
+ memoize(method) do
22
+ @attributes[method]
23
+ end
24
+ end
25
+ end
26
+
27
+ def define_predicate_method(method)
28
+ define_method(:"#{method}?") do
29
+ !!@attributes[method]
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ def initialize(attributes = {})
36
+ kind = attributes[:kind]
37
+ data = attributes[:data]
38
+
39
+ @attributes = data || {}
40
+ @attributes[:kind] = kind
41
+ end
42
+
43
+ def [](method)
44
+ send(method.to_sym)
45
+ rescue NoMethodError
46
+ nil
47
+ end
48
+
49
+ private
50
+
51
+ def memoize(key, &block)
52
+ ivar = :"@#{key}"
53
+ return instance_variable_get(ivar) if instance_variable_defined?(ivar)
54
+
55
+ result = block.call
56
+ instance_variable_set(ivar, result)
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,142 @@
1
+ require 'faraday'
2
+ require 'redditkit/error'
3
+ require 'redditkit/version'
4
+ require 'redditkit/client/account'
5
+ require 'redditkit/client/apps'
6
+ require 'redditkit/client/captcha'
7
+ require 'redditkit/client/comments'
8
+ require 'redditkit/client/flair'
9
+ require 'redditkit/client/links'
10
+ require 'redditkit/client/miscellaneous'
11
+ require 'redditkit/client/moderation'
12
+ require 'redditkit/client/multireddits'
13
+ require 'redditkit/client/private_messages'
14
+ require 'redditkit/client/search'
15
+ require 'redditkit/client/subreddits'
16
+ require 'redditkit/client/users'
17
+ require 'redditkit/client/utilities'
18
+ require 'redditkit/client/voting'
19
+ require 'redditkit/client/wiki'
20
+ require 'redditkit/response/parse_json'
21
+ require 'redditkit/response/raise_error'
22
+
23
+ module RedditKit
24
+
25
+ # The client for the reddit API, handling all interactions with reddit's servers.
26
+ class Client
27
+ include RedditKit::Client::Account
28
+ include RedditKit::Client::Apps
29
+ include RedditKit::Client::Captcha
30
+ include RedditKit::Client::Comments
31
+ include RedditKit::Client::Flair
32
+ include RedditKit::Client::Links
33
+ include RedditKit::Client::Miscellaneous
34
+ include RedditKit::Client::Moderation
35
+ include RedditKit::Client::Multireddits
36
+ include RedditKit::Client::PrivateMessages
37
+ include RedditKit::Client::Search
38
+ include RedditKit::Client::Subreddits
39
+ include RedditKit::Client::Users
40
+ include RedditKit::Client::Utilities
41
+ include RedditKit::Client::Voting
42
+ include RedditKit::Client::Wiki
43
+
44
+ attr_reader :username
45
+ attr_reader :current_user
46
+ attr_reader :cookie
47
+ attr_reader :modhash
48
+
49
+ attr_accessor :api_endpoint
50
+ attr_accessor :authentication_endpoint
51
+ attr_accessor :user_agent
52
+ attr_accessor :middleware
53
+
54
+ def initialize(username = nil, password = nil)
55
+ @username = username
56
+ @password = password
57
+
58
+ @cookie = nil
59
+ @modhash = nil
60
+
61
+ unless @username.nil? or @password.nil?
62
+ sign_in @username, @password
63
+ end
64
+ end
65
+
66
+ def api_endpoint
67
+ @api_endpoint ||= 'http://www.reddit.com/'
68
+ end
69
+
70
+ def authentication_endpoint
71
+ @authentication_endpoint ||= 'https://ssl.reddit.com/'
72
+ end
73
+
74
+ def user_agent
75
+ @user_agent ||= "RedditKit.rb #{RedditKit::Version.to_s}"
76
+ end
77
+
78
+ def middleware
79
+ @middleware ||= Faraday::Builder.new do |builder|
80
+ builder.use Faraday::Request::UrlEncoded
81
+ builder.use RedditKit::Response::RaiseError
82
+ builder.use RedditKit::Response::ParseJSON
83
+ builder.adapter Faraday.default_adapter
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def get(path, params = nil)
90
+ request(:get, path, params, connection)
91
+ end
92
+
93
+ def post(path, params = nil)
94
+ request(:post, path, params, connection)
95
+ end
96
+
97
+ def https_post(path, params = nil)
98
+ request(:post, path, params, https_connection)
99
+ end
100
+
101
+ def put(path, params = nil)
102
+ request(:put, path, params, connection)
103
+ end
104
+
105
+ def delete_path(path, params = nil)
106
+ request(:delete, path, params, connection)
107
+ end
108
+
109
+ def request(method, path, parameters = {}, request_connection)
110
+ if signed_in?
111
+ request = authenticated_request_configuration(method, path, parameters)
112
+ request_connection.send(method.to_sym, path, parameters, &request).env
113
+ else
114
+ request_connection.send(method.to_sym, path, parameters).env
115
+ end
116
+ rescue Faraday::Error::ClientError
117
+ raise RedditKit::RequestError
118
+ end
119
+
120
+ def authenticated_request_configuration(method, path, parameters)
121
+ raise RedditKit::NotAuthenticated unless signed_in?
122
+
123
+ Proc.new do |request|
124
+ request.headers['Cookie'] = "reddit_session=#{@cookie}"
125
+ request.headers['X-Modhash'] = @modhash
126
+ end
127
+ end
128
+
129
+ def connection
130
+ @connection ||= connection_with_url(api_endpoint)
131
+ end
132
+
133
+ def https_connection
134
+ @https_connection ||= connection_with_url(authentication_endpoint)
135
+ end
136
+
137
+ def connection_with_url(url)
138
+ Faraday.new(url, { :builder => middleware })
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,73 @@
1
+ module RedditKit
2
+ class Client
3
+
4
+ # Methods which operate on a user's account.
5
+ module Account
6
+
7
+ # Sign in to a reddit account.
8
+ #
9
+ # @see http://www.reddit.com/dev/api#POST_api_login
10
+ # @param username [String] The reddit account's username.
11
+ # @param password [String] The reddit account's password.
12
+ def sign_in(username, password)
13
+ response = https_post 'api/login', { :user => username, :passwd => password, :api_type => :json }
14
+ body = response[:body]
15
+
16
+ data = body[:json][:data]
17
+
18
+ @modhash = data[:modhash]
19
+ @cookie = data[:cookie]
20
+ @username = username
21
+
22
+ @current_user = user @username
23
+ @username = @current_user.username
24
+ end
25
+
26
+ # Check is a user is currently signed in.
27
+ #
28
+ # @return [Boolean]
29
+ def signed_in?
30
+ !!@modhash and !!@cookie
31
+ end
32
+
33
+ # Sign the current user out.
34
+ def sign_out
35
+ @username = nil
36
+ @current_user = nil
37
+
38
+ @modhash = nil
39
+ @cookie = nil
40
+ end
41
+
42
+ # Updates the current user's email or password.
43
+ #
44
+ # @see http://www.reddit.com/dev/api#POST_api_update
45
+ # @option options [String] current_password The user's current password.
46
+ # @option options [String] new_password The user's new password.
47
+ # @option options [String] email The user's new email address.
48
+ def update_account(options)
49
+ password = options[:new_password]
50
+ parameters = { :curpass => options[:current_password], :email => options[:email], :newpass => password, :verpass => password, :api_type => :json }
51
+
52
+ post('api/update', parameters)
53
+ end
54
+
55
+ # Invalidates all session cookies and updates the current one.
56
+ #
57
+ # @see http://www.reddit.com/dev/api#POST_api_clear_sessions
58
+ # @param password [String] The authenticated user's current password.
59
+ # @return [String] The new cookie value.
60
+ def update_session(password)
61
+ response = post('api/clear_sessions', :dest => api_endpoint, :curpass => password, :api_type => 'json')
62
+
63
+ response_headers = response[:response_headers]
64
+ full_cookie_string = response_headers['set-cookie']
65
+ cookie = full_cookie_string[/reddit_session=(.*?);/m, 1]
66
+
67
+ @cookie = cookie
68
+ cookie
69
+ end
70
+
71
+ end
72
+ end
73
+ end