ruby_reddit_api 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +47 -0
- data/features/api.feature +10 -0
- data/features/base.feature +15 -0
- data/features/comment.feature +40 -0
- data/features/message.feature +5 -0
- data/features/reddit.yml +5 -0
- data/features/step_definitions/api_steps.rb +22 -0
- data/features/step_definitions/base_steps.rb +49 -0
- data/features/step_definitions/comment_steps.rb +59 -0
- data/features/step_definitions/message_steps.rb +18 -0
- data/features/step_definitions/submission_steps.rb +117 -0
- data/features/step_definitions/user_steps.rb +25 -0
- data/features/submission.feature +58 -0
- data/features/support/base_helpers.rb +17 -0
- data/features/user.feature +11 -0
- data/lib/ruby_reddit_api.rb +17 -0
- data/lib/ruby_reddit_api/api.rb +46 -0
- data/lib/ruby_reddit_api/base.rb +109 -0
- data/lib/ruby_reddit_api/comment.rb +86 -0
- data/lib/ruby_reddit_api/json_listing.rb +38 -0
- data/lib/ruby_reddit_api/message.rb +30 -0
- data/lib/ruby_reddit_api/submission.rb +99 -0
- data/lib/ruby_reddit_api/user.rb +47 -0
- data/lib/ruby_reddit_api/version.rb +3 -0
- data/lib/ruby_reddit_api/vote.rb +33 -0
- metadata +129 -0
data/README
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
Ruby Reddit Client v0.1.9
|
2
|
+
==================
|
3
|
+
Tested with 1.9.2
|
4
|
+
|
5
|
+
Usage:
|
6
|
+
=======
|
7
|
+
> require "ruby_reddit_api"
|
8
|
+
> r = Reddit::Api.new "user", "password"
|
9
|
+
> results = r.browse "ruby"
|
10
|
+
> results[0].upvote
|
11
|
+
|
12
|
+
Features:
|
13
|
+
========
|
14
|
+
- Authentication
|
15
|
+
- Parse submissions
|
16
|
+
- Comments parsing
|
17
|
+
- Vote on submission
|
18
|
+
|
19
|
+
|
20
|
+
Running Tests:
|
21
|
+
=============
|
22
|
+
- Set up the reddit VM (http://blog.reddit.com/2010/05/admins-never-do-what-you-want-now-it-is.html)
|
23
|
+
- Ensure your hosts file has reddit.local pointing to the VM
|
24
|
+
- rake cucumber
|
25
|
+
|
26
|
+
License
|
27
|
+
(The MIT License)
|
28
|
+
|
29
|
+
Copyright (c) 2010 James Cook
|
30
|
+
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
32
|
+
of this software and associated documentation files (the "Software"), to deal
|
33
|
+
in the Software without restriction, including without limitation the rights
|
34
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
35
|
+
copies of the Software, and to permit persons to whom the Software is
|
36
|
+
furnished to do so, subject to the following conditions:
|
37
|
+
|
38
|
+
The above copyright notice and this permission notice shall be included in
|
39
|
+
all copies or substantial portions of the Software.
|
40
|
+
|
41
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
42
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
43
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
44
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
45
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
46
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
47
|
+
THE SOFTWARE.
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Feature: Browsing
|
2
|
+
I want to be able to browse submissions
|
3
|
+
|
4
|
+
Scenario: Valid subreddit
|
5
|
+
Given I submit a valid subreddit
|
6
|
+
Then I should get back a listing of submissions
|
7
|
+
|
8
|
+
Scenario: Invalid subreddit
|
9
|
+
Given I submit a invalid subreddit
|
10
|
+
Then I should get back some error
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Feature: Authentication
|
2
|
+
In order perform things like voting and commenting
|
3
|
+
As a Redditor
|
4
|
+
I want to be able to login in my step definitions
|
5
|
+
|
6
|
+
Scenario: Valid user and password
|
7
|
+
Given I have a valid user
|
8
|
+
And I send my user and password to the login API
|
9
|
+
Then I should have a valid cookie
|
10
|
+
And the stored headers should refer to the cookie
|
11
|
+
|
12
|
+
Scenario: Invalid user and password
|
13
|
+
Given I have a invalid user
|
14
|
+
And I send my user and password to the login API
|
15
|
+
Then I should not have a valid cookie
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Feature: Comments
|
2
|
+
I want to be able to comment on a comment
|
3
|
+
I want to be able to delete my comments
|
4
|
+
|
5
|
+
Scenario: Valid comment text
|
6
|
+
Given I enter some text
|
7
|
+
Then I should be able to add a comment
|
8
|
+
|
9
|
+
Scenario: I want to hide a comment
|
10
|
+
Given I have a comment
|
11
|
+
Then I should be able to hide the comment
|
12
|
+
|
13
|
+
Scenario: I want to remove a comment
|
14
|
+
Given I have a comment
|
15
|
+
Then I should be able to remove the comment
|
16
|
+
|
17
|
+
Scenario: I want to approve a comment
|
18
|
+
Given I have a comment
|
19
|
+
Then I should be able to approve the comment
|
20
|
+
|
21
|
+
Scenario: I want to edit a comment
|
22
|
+
Given I have a comment
|
23
|
+
Then I should be able to edit the comment
|
24
|
+
|
25
|
+
Scenario: I want to comment on a comment
|
26
|
+
Given I have a comment
|
27
|
+
Then I should be able to reply to the comment
|
28
|
+
|
29
|
+
Scenario: I want to moderator distinguish a comment
|
30
|
+
Given I have a comment
|
31
|
+
Then I should be able to moderator distinguish the comment
|
32
|
+
|
33
|
+
Scenario: I want to indistinguish a comment
|
34
|
+
Given I have a comment
|
35
|
+
Then I should be able to indistinguish the comment
|
36
|
+
|
37
|
+
Scenario: I want to admin distinguish a comment
|
38
|
+
Given I have a comment
|
39
|
+
Then I should be able to admin distinguish the comment
|
40
|
+
|
data/features/reddit.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Given /^I submit a valid subreddit$/ do
|
2
|
+
Reddit::Api.base_uri "reddit.local"
|
3
|
+
@api = Reddit::Api.new "reddit", "password"
|
4
|
+
@subreddit = "reddit_test0"
|
5
|
+
end
|
6
|
+
|
7
|
+
Then /^I should get back a listing of submissions$/ do
|
8
|
+
results = @api.browse(@subreddit)
|
9
|
+
results[0].class.should == Reddit::Submission
|
10
|
+
results[0].author.should_not == nil
|
11
|
+
end
|
12
|
+
|
13
|
+
Given /^I submit a invalid subreddit$/ do
|
14
|
+
Reddit::Api.base_uri "reddit.local"
|
15
|
+
@api = Reddit::Api.new "reddit", "password"
|
16
|
+
@subreddit = "invalid_subreddit"
|
17
|
+
end
|
18
|
+
|
19
|
+
Then /^I should get back some error$/ do
|
20
|
+
results = @api.browse(@subreddit)
|
21
|
+
results.should == false
|
22
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), "..", "..", "lib", "ruby_reddit_api.rb")
|
2
|
+
Before do
|
3
|
+
Reddit::Base.instance_variable_set("@cookie", nil)
|
4
|
+
load_server_config
|
5
|
+
Reddit::Api.base_uri @address
|
6
|
+
end
|
7
|
+
|
8
|
+
Given /^I have a valid user$/ do
|
9
|
+
load_server_config
|
10
|
+
end
|
11
|
+
|
12
|
+
Given /^I have a invalid user$/ do
|
13
|
+
@user, @pass = "invalid", "user"
|
14
|
+
end
|
15
|
+
|
16
|
+
Given /^I send my user and password to the login API$/ do
|
17
|
+
@api = Reddit::Api.new @user, @pass
|
18
|
+
@api.login
|
19
|
+
end
|
20
|
+
|
21
|
+
Given /I'm logged in$/ do
|
22
|
+
@api = Reddit::Api.new @user, @pass
|
23
|
+
@api.login
|
24
|
+
end
|
25
|
+
|
26
|
+
Given /I'm not logged in$/ do
|
27
|
+
@api.logout if @api
|
28
|
+
@api = Reddit::Api.new @user, "bad pass"
|
29
|
+
@api.logout
|
30
|
+
end
|
31
|
+
|
32
|
+
Then /^I should have a valid cookie$/ do
|
33
|
+
@api.cookie.should_not == nil
|
34
|
+
@api.cookie.should =~ /reddit_session/
|
35
|
+
end
|
36
|
+
|
37
|
+
Then /^I should not have a valid cookie$/ do
|
38
|
+
@api.cookie.should_not == nil
|
39
|
+
@api.cookie.should =~ /reddit_first/
|
40
|
+
end
|
41
|
+
|
42
|
+
Then /^I should not have a cookie$/ do
|
43
|
+
@api.cookie.should == nil
|
44
|
+
end
|
45
|
+
|
46
|
+
Then /^the stored headers should refer to the cookie$/ do
|
47
|
+
@api.base_headers["Cookie"].should == @api.cookie
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
Before do
|
2
|
+
load_server_config
|
3
|
+
Reddit::Api.base_uri @address
|
4
|
+
Reddit::Submission.base_uri @address
|
5
|
+
Reddit::Comment.base_uri @address
|
6
|
+
@api = Reddit::Api.new @user, @pass
|
7
|
+
@api.login
|
8
|
+
@submission ||= @api.browse("reddit_test0")[0]
|
9
|
+
end
|
10
|
+
|
11
|
+
Given /^I enter some text$/ do
|
12
|
+
@text = "SOME COMMENT"
|
13
|
+
end
|
14
|
+
|
15
|
+
Then /^I should be able to add a comment$/ do
|
16
|
+
@submission.add_comment(@text).should be true
|
17
|
+
end
|
18
|
+
|
19
|
+
Given /^I have a comment$/ do
|
20
|
+
@submission.add_comment("a comment")
|
21
|
+
@comment = @submission.comments.last
|
22
|
+
end
|
23
|
+
|
24
|
+
Then /^I should be able to hide the comment$/ do
|
25
|
+
@comment.hide
|
26
|
+
end
|
27
|
+
|
28
|
+
Then /^I should be able to remove the comment$/ do
|
29
|
+
@comment.remove
|
30
|
+
end
|
31
|
+
|
32
|
+
Then /^I should be able to approve the comment$/ do
|
33
|
+
@comment.approve
|
34
|
+
end
|
35
|
+
|
36
|
+
Then /^I should not be able to edit the comment$/ do
|
37
|
+
@comment.edit( "1234" ).should be false
|
38
|
+
end
|
39
|
+
|
40
|
+
Then /^I should be able to edit the comment$/ do
|
41
|
+
@comment.edit( "1234" ).should be true
|
42
|
+
end
|
43
|
+
|
44
|
+
Then /^I should be able to moderator distinguish the comment$/ do
|
45
|
+
pending #@comment.moderator_distinguish
|
46
|
+
end
|
47
|
+
|
48
|
+
Then /^I should be able to indistinguish the comment$/ do
|
49
|
+
pending #@comment.indistinguish
|
50
|
+
end
|
51
|
+
|
52
|
+
Then /^I should be able to admin distinguish the comment$/ do
|
53
|
+
pending #@comment.admin_distinguish
|
54
|
+
end
|
55
|
+
|
56
|
+
Then /^I should be able to reply to the comment$/ do
|
57
|
+
pending #@comment.reply("a reply").should be true
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Before do
|
2
|
+
load_server_config
|
3
|
+
Reddit::Api.base_uri @address
|
4
|
+
Reddit::Message.base_uri @address
|
5
|
+
end
|
6
|
+
|
7
|
+
Given /^I am logged in$/ do
|
8
|
+
@api = Reddit::Api.new @user, @pass
|
9
|
+
@api.login
|
10
|
+
end
|
11
|
+
|
12
|
+
When /^I go to the sent messages page$/ do
|
13
|
+
@result = @api.sent_messages
|
14
|
+
end
|
15
|
+
|
16
|
+
Then /^I should see a listing of messages$/ do
|
17
|
+
@result.any?{|r| r.is_a?(Reddit::Message) == false}.should be false
|
18
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
Given /^I have a submission$/ do
|
2
|
+
load_server_config
|
3
|
+
Reddit::Api.base_uri @address
|
4
|
+
Reddit::Submission.base_uri @address
|
5
|
+
Reddit::Comment.base_uri @address
|
6
|
+
@api = Reddit::Api.new @user, @pass
|
7
|
+
@api.login
|
8
|
+
@submission = @api.browse("reddit_test0")[0]
|
9
|
+
if @api.logged_in?
|
10
|
+
@submission.add_comment("STOP REPOSTING!!1") if @submission
|
11
|
+
else
|
12
|
+
raise "Can't run test. Submit failed.."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Then /^I should be able to see the author$/ do
|
17
|
+
@submission.author.should_not == nil
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^I should be able to see the title$/ do
|
21
|
+
@submission.title.should_not == nil
|
22
|
+
end
|
23
|
+
|
24
|
+
Then /^I should be able to see the selftext$/ do
|
25
|
+
@submission.selftext.should_not == nil
|
26
|
+
end
|
27
|
+
|
28
|
+
Then /^I should be able to see the url$/ do
|
29
|
+
@submission.url.should_not == nil
|
30
|
+
end
|
31
|
+
|
32
|
+
Then /^I should be able to see the up votes$/ do
|
33
|
+
@submission.ups.should_not == nil
|
34
|
+
end
|
35
|
+
|
36
|
+
Then /^I should be able to see the down votes$/ do
|
37
|
+
@submission.downs.should_not == nil
|
38
|
+
end
|
39
|
+
|
40
|
+
Then /^I should not be able to upvote it$/ do
|
41
|
+
@submission.upvote.should be false
|
42
|
+
end
|
43
|
+
|
44
|
+
Then /^I should not be able to downvote it$/ do
|
45
|
+
@submission.downvote.should be false
|
46
|
+
end
|
47
|
+
|
48
|
+
Then /^I should be able to upvote it$/ do
|
49
|
+
@submission.upvote.should be true
|
50
|
+
end
|
51
|
+
|
52
|
+
Then /^I should be able to downvote it$/ do
|
53
|
+
@submission.downvote.should be true
|
54
|
+
end
|
55
|
+
|
56
|
+
Then /^I should be able to see the comments$/ do
|
57
|
+
comments = @submission.comments
|
58
|
+
comments.size.should > 0
|
59
|
+
end
|
60
|
+
|
61
|
+
Then /^I should not be able to save the submission$/ do
|
62
|
+
@submission.save.should be false
|
63
|
+
end
|
64
|
+
|
65
|
+
Then /^I should not be able to unsave the submission$/ do
|
66
|
+
@submission.unsave.should be false
|
67
|
+
end
|
68
|
+
|
69
|
+
Then /^I should not be able to hide the submission$/ do
|
70
|
+
@submission.hide.should be false
|
71
|
+
end
|
72
|
+
|
73
|
+
Then /^I should not be able to unhide the submission$/ do
|
74
|
+
@submission.unhide.should be false
|
75
|
+
end
|
76
|
+
|
77
|
+
Then /^I should be able to save the submission$/ do
|
78
|
+
@submission.save.should be true
|
79
|
+
end
|
80
|
+
|
81
|
+
Then /^I should be able to unsave the submission$/ do
|
82
|
+
@submission.unsave.should be true
|
83
|
+
end
|
84
|
+
|
85
|
+
Then /^I should be able to hide the submission$/ do
|
86
|
+
result = @submission.hide
|
87
|
+
@submission.unhide if result
|
88
|
+
result.should be true
|
89
|
+
end
|
90
|
+
|
91
|
+
Then /^I should be able to unhide the submission$/ do
|
92
|
+
@submission.unhide.should be true
|
93
|
+
end
|
94
|
+
|
95
|
+
Then /^I should be able to report the submission$/ do
|
96
|
+
@submission.report.should be true
|
97
|
+
end
|
98
|
+
|
99
|
+
Then /^I should not be able to report the submission$/ do
|
100
|
+
@submission.report.should be false
|
101
|
+
end
|
102
|
+
|
103
|
+
Then /^I should be able to see more comments if needed$/ do
|
104
|
+
pending
|
105
|
+
end
|
106
|
+
|
107
|
+
Then /^I should be able to moderator distinguish the submission$/ do
|
108
|
+
@submission.moderator_distinguish
|
109
|
+
end
|
110
|
+
|
111
|
+
Then /^I should be able to admin distinguish the submission$/ do
|
112
|
+
@submission.admin_distinguish
|
113
|
+
end
|
114
|
+
|
115
|
+
Then /^I should be able to indistinguish the submission$/ do
|
116
|
+
@submission.indistinguish
|
117
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Before do
|
2
|
+
load_server_config
|
3
|
+
Reddit::Api.base_uri @address
|
4
|
+
Reddit::Submission.base_uri @address
|
5
|
+
Reddit::Comment.base_uri @address
|
6
|
+
Reddit::User.base_uri @address
|
7
|
+
@api = Reddit::Api.new @user, @pass
|
8
|
+
@api.login
|
9
|
+
end
|
10
|
+
|
11
|
+
Given /^I select a redditor$/ do
|
12
|
+
@submission = @api.browse("reddit_test1")[0]
|
13
|
+
@user = @submission.author
|
14
|
+
end
|
15
|
+
|
16
|
+
Then /^I should be able to friend them$/ do
|
17
|
+
@user.friend.should be true
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^I should be able to unfriend them$/ do
|
21
|
+
@user.unfriend.should be true
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
Feature: Submissions
|
2
|
+
I want to be able to peruse the submission details
|
3
|
+
And I want to be able to up vote the submission
|
4
|
+
And I want to be able to down vote the submission
|
5
|
+
And I want to be able to save submissions I like
|
6
|
+
And I want to be able to unsave submissions
|
7
|
+
|
8
|
+
|
9
|
+
Scenario: Viewing a submission
|
10
|
+
Scenario: When not logged in
|
11
|
+
Given I have a submission
|
12
|
+
And I'm not logged in
|
13
|
+
Then I should be able to see the author
|
14
|
+
And I should be able to see the title
|
15
|
+
And I should be able to see the selftext
|
16
|
+
And I should be able to see the url
|
17
|
+
And I should be able to see the up votes
|
18
|
+
And I should be able to see the down votes
|
19
|
+
And I should be able to see the comments
|
20
|
+
But I should not be able to upvote it
|
21
|
+
But I should not be able to downvote it
|
22
|
+
But I should not be able to save the submission
|
23
|
+
But I should not be able to unsave the submission
|
24
|
+
But I should not be able to hide the submission
|
25
|
+
But I should not be able to unhide the submission
|
26
|
+
But I should not be able to report the submission
|
27
|
+
And I should be able to see more comments if needed
|
28
|
+
|
29
|
+
Scenario: When logged in
|
30
|
+
Given I have a submission
|
31
|
+
And I'm logged in
|
32
|
+
Then I should be able to see the author
|
33
|
+
And I should be able to see the title
|
34
|
+
And I should be able to see the selftext
|
35
|
+
And I should be able to see the url
|
36
|
+
And I should be able to see the up votes
|
37
|
+
And I should be able to see the down votes
|
38
|
+
And I should be able to see the comments
|
39
|
+
And I should be able to upvote it
|
40
|
+
And I should be able to downvote it
|
41
|
+
And I should be able to save the submission
|
42
|
+
And I should be able to unsave the submission
|
43
|
+
And I should be able to hide the submission
|
44
|
+
And I should be able to unhide the submission
|
45
|
+
And I should be able to report the submission
|
46
|
+
And I should be able to see more comments if needed
|
47
|
+
|
48
|
+
Scenario: I want to moderator distinguish a submission
|
49
|
+
Given I have a submission
|
50
|
+
Then I should be able to moderator distinguish the submission
|
51
|
+
|
52
|
+
Scenario: I want to admin distinguish a submission
|
53
|
+
Given I have a submission
|
54
|
+
Then I should be able to admin distinguish the submission
|
55
|
+
|
56
|
+
Scenario: I want to indistinguish a submission
|
57
|
+
Given I have a submission
|
58
|
+
Then I should be able to indistinguish the submission
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module BaseHelpers
|
2
|
+
def load_server_config
|
3
|
+
@address, @post, @user, @pass = parse_config.compact
|
4
|
+
end
|
5
|
+
|
6
|
+
protected
|
7
|
+
def parse_config
|
8
|
+
file = File.exist?("features/reddit.yml") ? YAML.load_file("features/reddit.yml") : {}
|
9
|
+
server = file.fetch("server"){ server_defaults }
|
10
|
+
return [ server["address"], server["port"], server["test_user"], server["test_pass"] ]
|
11
|
+
end
|
12
|
+
|
13
|
+
def server_defaults
|
14
|
+
{"address" => "reddit.local", "port" => "80", "test_user" => "reddit", "test_pass" => "password"}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
World(BaseHelpers)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
module Reddit
|
4
|
+
end
|
5
|
+
|
6
|
+
require "httparty"
|
7
|
+
require "json"
|
8
|
+
require "reddit/version"
|
9
|
+
require "reddit/base"
|
10
|
+
require "reddit/json_listing"
|
11
|
+
require "reddit/api"
|
12
|
+
require "reddit/user"
|
13
|
+
require "reddit/vote"
|
14
|
+
require "reddit/submission"
|
15
|
+
require "reddit/comment"
|
16
|
+
require "reddit/message"
|
17
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Reddit
|
2
|
+
|
3
|
+
class Api < Base
|
4
|
+
attr_reader :last_action, :debug
|
5
|
+
|
6
|
+
def initialize(user=nil,password=nil, options={})
|
7
|
+
@user = user
|
8
|
+
@password = password
|
9
|
+
@debug = StringIO.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
"<Reddit::Api user='#{user}'>"
|
14
|
+
end
|
15
|
+
|
16
|
+
def browse(subreddit, options={})
|
17
|
+
subreddit = sanitize_subreddit(subreddit)
|
18
|
+
options.merge! :handler => "Submission"
|
19
|
+
if options[:limit]
|
20
|
+
options.merge!({:query => {:limit => options[:limit]}})
|
21
|
+
end
|
22
|
+
read("/r/#{subreddit}.json", options )
|
23
|
+
end
|
24
|
+
|
25
|
+
def sent_messages
|
26
|
+
messages :sent
|
27
|
+
end
|
28
|
+
|
29
|
+
def received_messages
|
30
|
+
messages :inbox
|
31
|
+
end
|
32
|
+
|
33
|
+
def comments
|
34
|
+
messages :comments
|
35
|
+
end
|
36
|
+
|
37
|
+
def post_replies
|
38
|
+
messages :selfreply
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
def messages(kind)
|
43
|
+
read("/message/#{kind.to_s}.json", :handler => "Message")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Reddit
|
2
|
+
class Base
|
3
|
+
include HTTParty
|
4
|
+
|
5
|
+
attr_reader :last_action, :debug
|
6
|
+
base_uri "www.reddit.com"
|
7
|
+
class << self; attr_reader :cookie, :modhash, :user_id, :user, end
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
@debug = StringIO.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def inspect
|
14
|
+
"<Reddit::Base user='#{user}'>"
|
15
|
+
end
|
16
|
+
|
17
|
+
def login
|
18
|
+
capture_session(self.class.post( "/api/login", {:body => {:user => @user, :passwd => @password}, :debug_output => @debug} ) )
|
19
|
+
logged_in?
|
20
|
+
end
|
21
|
+
|
22
|
+
def logout
|
23
|
+
Reddit::Base.instance_variable_set("@cookie",nil)
|
24
|
+
end
|
25
|
+
|
26
|
+
def cookie
|
27
|
+
Reddit::Base.cookie
|
28
|
+
end
|
29
|
+
|
30
|
+
def modhash
|
31
|
+
Reddit::Base.modhash
|
32
|
+
end
|
33
|
+
|
34
|
+
def user_id
|
35
|
+
Reddit::Base.user_id
|
36
|
+
end
|
37
|
+
|
38
|
+
def user
|
39
|
+
Reddit::Base.user
|
40
|
+
end
|
41
|
+
|
42
|
+
def logged_in?
|
43
|
+
!!(cookie && (cookie =~ /reddit_session/) != nil)
|
44
|
+
end
|
45
|
+
|
46
|
+
def user_agent
|
47
|
+
self.class.user_agent
|
48
|
+
end
|
49
|
+
|
50
|
+
def base_headers
|
51
|
+
self.class.base_headers
|
52
|
+
end
|
53
|
+
|
54
|
+
def read(url, options={})
|
55
|
+
unless throttled?
|
56
|
+
@debug.rewind
|
57
|
+
verb = (options[:verb] || "get")
|
58
|
+
param_key = (verb == "get") ? :query : :body
|
59
|
+
resp = self.class.send( verb, url, {param_key => (options[param_key] || {}), :headers => base_headers, :debug_output => @debug})
|
60
|
+
if valid_response?(resp)
|
61
|
+
@last_action = Time.now
|
62
|
+
klass = Reddit.const_get(options[:handler] || "Submission")
|
63
|
+
resp = klass.parse( JSON.parse(resp.body, :max_nesting => 9_999) )
|
64
|
+
return resp
|
65
|
+
else
|
66
|
+
return false
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
def valid_response?(response)
|
73
|
+
response.code == 200 && response.headers["content-type"].to_s =~ /json/
|
74
|
+
end
|
75
|
+
|
76
|
+
def capture_session(response)
|
77
|
+
cookies = response.headers["set-cookie"]
|
78
|
+
Reddit::Base.instance_variable_set("@cookie", cookies)
|
79
|
+
Reddit::Base.instance_variable_set("@user", @user)
|
80
|
+
end
|
81
|
+
|
82
|
+
def capture_user_id
|
83
|
+
return true if user_id
|
84
|
+
this_user = read("/user/#{user}/about.json", :handler => "User")
|
85
|
+
Reddit::Base.instance_variable_set("@user_id", this_user.id)
|
86
|
+
end
|
87
|
+
|
88
|
+
def throttled?
|
89
|
+
@last_action && ( ( Time.now - @last_action ) < 1.0 )
|
90
|
+
end
|
91
|
+
|
92
|
+
def sanitize_subreddit(subreddit)
|
93
|
+
subreddit.gsub!(/^\/?r\//,'')
|
94
|
+
subreddit.gsub!(/\.json\Z/,'')
|
95
|
+
subreddit
|
96
|
+
end
|
97
|
+
|
98
|
+
class << self
|
99
|
+
|
100
|
+
def base_headers
|
101
|
+
{'Cookie' => Reddit::Base.cookie.to_s, 'user-agent' => user_agent}
|
102
|
+
end
|
103
|
+
|
104
|
+
def user_agent
|
105
|
+
"Ruby Reddit Client v#{Reddit::VERSION}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Reddit
|
2
|
+
class Comment < Api
|
3
|
+
include JsonListing
|
4
|
+
attr_reader :body, :subreddit_id, :name, :created, :downs, :author, :created_utc, :body_html, :link_id, :parent_id, :likes, :replies, :subreddit, :ups, :debug, :kind
|
5
|
+
def initialize(json)
|
6
|
+
parse(json)
|
7
|
+
@debug = StringIO.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
"<Reddit::Comment author='#{@author}' body='#{short_body}'>"
|
12
|
+
end
|
13
|
+
|
14
|
+
def id
|
15
|
+
"#{kind}_#{@id}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def author
|
19
|
+
@author_data ||= read("/user/#{@author}/about.json", :handler => "User")
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
body
|
24
|
+
end
|
25
|
+
|
26
|
+
def edit(newtext)
|
27
|
+
resp=self.class.post("/api/editusertext", {:body => {:thing_id => id, :uh => modhash, :r => subreddit, :text => newtext }, :headers => base_headers, :debug_output => @debug })
|
28
|
+
resp.code == 200
|
29
|
+
end
|
30
|
+
|
31
|
+
def hide # soft delete?
|
32
|
+
resp=self.class.post("/api/del", {:body => {:id => id, :uh => modhash, :r => subreddit, :executed => "removed" }, :headers => base_headers, :debug_output => @debug })
|
33
|
+
resp.code == 200
|
34
|
+
end
|
35
|
+
|
36
|
+
def remove
|
37
|
+
resp=self.class.post("/api/remove", {:body => {:id => id, :uh => modhash, :r => subreddit}, :headers => base_headers, :debug_output => @debug })
|
38
|
+
resp.code == 200
|
39
|
+
end
|
40
|
+
|
41
|
+
def approve
|
42
|
+
resp=self.class.post("/api/approve", {:body => {:id => id, :uh => modhash, :r => subreddit}, :headers => base_headers, :debug_output => @debug })
|
43
|
+
resp.code == 200
|
44
|
+
end
|
45
|
+
|
46
|
+
def moderator_distinguish
|
47
|
+
add_distinction "yes"
|
48
|
+
end
|
49
|
+
|
50
|
+
def admin_distinguish
|
51
|
+
add_distinction "admin"
|
52
|
+
end
|
53
|
+
|
54
|
+
def indistinguish
|
55
|
+
add_distinction "no"
|
56
|
+
end
|
57
|
+
|
58
|
+
def reply(text)
|
59
|
+
resp = self.class.post("/api/comment", {:body => {:thing_id => id, :text => text, :uh => modhash, :r => subreddit }, :headers => base_headers, :debug_output => @debug })
|
60
|
+
resp.code == 200
|
61
|
+
end
|
62
|
+
|
63
|
+
def upvote
|
64
|
+
Vote.new(self).up
|
65
|
+
end
|
66
|
+
|
67
|
+
def downvote
|
68
|
+
Vote.new(self).down
|
69
|
+
end
|
70
|
+
|
71
|
+
def short_body
|
72
|
+
str = body.to_s
|
73
|
+
if str.size > 15
|
74
|
+
str[0..15] + "..."
|
75
|
+
else
|
76
|
+
body
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_distinction(verb)
|
81
|
+
resp=self.class.post("/api/distinguish/#{verb}", {:body => {:id => id, :uh => modhash, :r => subreddit, :executed => "distinguishing..."}, :headers => base_headers, :debug_output => @debug })
|
82
|
+
puts resp.headers
|
83
|
+
resp.code == 200
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Reddit
|
2
|
+
module JsonListing
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
base.send(:include, InstanceMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def parse(json)
|
10
|
+
results = []
|
11
|
+
if json.is_a?(Array)
|
12
|
+
json.each do |j|
|
13
|
+
results << parse(j)
|
14
|
+
end
|
15
|
+
else
|
16
|
+
data = json["data"]
|
17
|
+
Reddit::Base.instance_variable_set("@modhash", data["modhash"]) # Needed for api calls
|
18
|
+
|
19
|
+
children = data["children"]
|
20
|
+
children.each do |message|
|
21
|
+
kind = message["kind"]
|
22
|
+
message["data"]["kind"] = kind
|
23
|
+
results << self.new(message["data"])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
return results.flatten
|
28
|
+
end
|
29
|
+
end
|
30
|
+
module InstanceMethods
|
31
|
+
def parse(json)
|
32
|
+
json.keys.each do |key|
|
33
|
+
instance_variable_set("@#{key}", json[key])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Reddit
|
2
|
+
class Message < Base
|
3
|
+
include JsonListing
|
4
|
+
attr_reader :body, :was_comment, :kind, :first_message, :name, :created, :dest, :created_utc, :body_html, :subreddit, :parent_id, :context, :replies, :subject, :debug
|
5
|
+
def initialize(json)
|
6
|
+
parse(json)
|
7
|
+
@debug = StringIO.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def id
|
11
|
+
"#{kind}_#{@id}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def author
|
15
|
+
@author_data ||= read("/user/#{@author}/about.json", :handler => "User")
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
"<Reddit::Message '#{short_body}'>"
|
20
|
+
end
|
21
|
+
|
22
|
+
def short_body
|
23
|
+
if body.size > 15
|
24
|
+
body[0..15]
|
25
|
+
else
|
26
|
+
body
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Reddit
|
2
|
+
class Submission < Base
|
3
|
+
include JsonListing
|
4
|
+
attr_reader :domain, :media_embed, :subreddit, :selftext_html, :selftext, :likes, :saved, :clicked, :media, :score, :over_18, :hidden, :thumbnail, :subreddit_id, :downs, :is_self, :permalink, :name, :created, :url, :title, :created_utc, :num_comments, :ups, :kind, :last_comment_id
|
5
|
+
|
6
|
+
def initialize(data)
|
7
|
+
parse(data)
|
8
|
+
@debug = StringIO.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def inspect
|
12
|
+
"<Reddit::Submission id='#{id}' author='#{@author}' title='#{title}'>"
|
13
|
+
end
|
14
|
+
|
15
|
+
def id
|
16
|
+
"#{kind}_#{@id}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def author
|
20
|
+
@author_data ||= read("/user/#{@author}/about.json", :handler => "User")
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_comment(text)
|
24
|
+
resp = self.class.post("/api/comment", {:body => {:thing_id => id, :text => text, :uh => modhash, :r => subreddit }, :headers => base_headers, :debug_output => @debug })
|
25
|
+
resp.code == 200
|
26
|
+
end
|
27
|
+
|
28
|
+
def upvote
|
29
|
+
Reddit::Vote.new(self).up
|
30
|
+
end
|
31
|
+
|
32
|
+
def downvote
|
33
|
+
Reddit::Vote.new(self).down
|
34
|
+
end
|
35
|
+
|
36
|
+
def save
|
37
|
+
toggle :save
|
38
|
+
end
|
39
|
+
|
40
|
+
def unsave
|
41
|
+
toggle :unsave
|
42
|
+
end
|
43
|
+
|
44
|
+
def hide
|
45
|
+
toggle :hide
|
46
|
+
end
|
47
|
+
|
48
|
+
def unhide
|
49
|
+
toggle :unhide
|
50
|
+
end
|
51
|
+
|
52
|
+
def report
|
53
|
+
toggle :report
|
54
|
+
end
|
55
|
+
|
56
|
+
def moderator_distinguish
|
57
|
+
add_distinction "yes"
|
58
|
+
end
|
59
|
+
|
60
|
+
def admin_distinguish
|
61
|
+
add_distinction "admin"
|
62
|
+
end
|
63
|
+
|
64
|
+
def indistinguish
|
65
|
+
add_distinction "no"
|
66
|
+
end
|
67
|
+
|
68
|
+
def comments(more=false)
|
69
|
+
#TODO Get morechildren to work correctly
|
70
|
+
if more && last_comment_id
|
71
|
+
opts = {:handler => "Comment",
|
72
|
+
:verb => "post",
|
73
|
+
:body =>
|
74
|
+
{:link_id => last_comment_id, :depth => 0, :r => subreddit, :uh => modhash, :renderstyle => "json", :pv_hex => "", :id => id}
|
75
|
+
}
|
76
|
+
return read("/api/morechildren", opts )
|
77
|
+
|
78
|
+
else
|
79
|
+
_comments = read( permalink + ".json", {:handler => "Comment", :query => {:limit => 50}} )
|
80
|
+
@last_comment_id = _comments.last.id if _comments && _comments.any?
|
81
|
+
return _comments
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
def add_distinction(verb)
|
87
|
+
resp=self.class.post("/api/distinguish/#{verb}", {:body => {:id => id, :uh => modhash, :r => subreddit, :executed => "distinguishing..."}, :headers => base_headers, :debug_output => @debug })
|
88
|
+
resp.code == 200
|
89
|
+
end
|
90
|
+
|
91
|
+
def toggle(which)
|
92
|
+
return false unless logged_in?
|
93
|
+
mapping = {:save => "save", :unsave => "unsave", :hide => "hidden", :unhide => "unhidden", :report => "report"}
|
94
|
+
mode = mapping[which]
|
95
|
+
resp = self.class.post("/api/#{which}", {:body => {:id => id, :uh => modhash, :r => subreddit, :executed => mode }, :headers => base_headers, :debug_output => @debug })
|
96
|
+
resp.code == 200
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
module Reddit
|
3
|
+
class User < Api
|
4
|
+
attr_reader :name, :debug, :created, :created_utc, :link_karma, :comment_karma, :is_mod, :has_mod_mail, :kind
|
5
|
+
def initialize(json)
|
6
|
+
@debug = StringIO.new
|
7
|
+
parse(json)
|
8
|
+
end
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
"<Reddit::User name='#{name}'>"
|
12
|
+
end
|
13
|
+
|
14
|
+
def id
|
15
|
+
"#{kind}_#{@id}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
name
|
20
|
+
end
|
21
|
+
|
22
|
+
def friend
|
23
|
+
capture_user_id
|
24
|
+
resp=self.class.post("/api/friend", {:body => {:name => name, :container => user_id, :type => "friend", :uh => modhash}, :headers => base_headers, :debug_output => @debug })
|
25
|
+
resp.code == 200
|
26
|
+
end
|
27
|
+
|
28
|
+
def unfriend
|
29
|
+
capture_user_id
|
30
|
+
resp=self.class.post("/api/unfriend", {:body => {:name => name, :container => user_id, :type => "friend", :uh => modhash}, :headers => base_headers, :debug_output => @debug })
|
31
|
+
resp.code == 200
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def parse(json)
|
36
|
+
json.keys.each do |key|
|
37
|
+
instance_variable_set("@#{key}", json[key])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.parse(json)
|
42
|
+
kind, data = json["kind"], json["data"]
|
43
|
+
data["kind"] = kind
|
44
|
+
return self.new(data)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Reddit
|
2
|
+
class Vote < Base
|
3
|
+
attr_reader :submission
|
4
|
+
|
5
|
+
def initialize(submission)
|
6
|
+
@submission = submission
|
7
|
+
end
|
8
|
+
|
9
|
+
def up
|
10
|
+
vote(:up)
|
11
|
+
end
|
12
|
+
|
13
|
+
def down
|
14
|
+
vote(:down)
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
"<Reddit::Vote>"
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
def vote(direction)
|
23
|
+
return false unless logged_in?
|
24
|
+
up_or_down = direction == :up ? 1 : -1
|
25
|
+
resp = self.class.post( "/api/vote", {:body => {:id => submission.id, :dir => up_or_down, :uh => modhash}, :headers => base_headers})
|
26
|
+
if resp.code == 200
|
27
|
+
return true
|
28
|
+
else
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_reddit_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 9
|
9
|
+
version: 0.1.9
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- James Cook
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-10-05 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: httparty
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: cucumber
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
type: :development
|
45
|
+
version_requirements: *id002
|
46
|
+
description: Wraps many reddit API functions such as submission and comments browsing, voting, messaging, friending, and more.
|
47
|
+
email:
|
48
|
+
- jamecook@gmail.com
|
49
|
+
executables: []
|
50
|
+
|
51
|
+
extensions: []
|
52
|
+
|
53
|
+
extra_rdoc_files: []
|
54
|
+
|
55
|
+
files:
|
56
|
+
- lib/ruby_reddit_api.rb
|
57
|
+
- lib/ruby_reddit_api/user.rb
|
58
|
+
- lib/ruby_reddit_api/comment.rb
|
59
|
+
- lib/ruby_reddit_api/message.rb
|
60
|
+
- lib/ruby_reddit_api/version.rb
|
61
|
+
- lib/ruby_reddit_api/vote.rb
|
62
|
+
- lib/ruby_reddit_api/submission.rb
|
63
|
+
- lib/ruby_reddit_api/api.rb
|
64
|
+
- lib/ruby_reddit_api/json_listing.rb
|
65
|
+
- lib/ruby_reddit_api/base.rb
|
66
|
+
- README
|
67
|
+
- features/reddit.yml
|
68
|
+
- features/submission.feature
|
69
|
+
- features/comment.feature
|
70
|
+
- features/user.feature
|
71
|
+
- features/base.feature
|
72
|
+
- features/message.feature
|
73
|
+
- features/api.feature
|
74
|
+
- features/step_definitions/message_steps.rb
|
75
|
+
- features/step_definitions/submission_steps.rb
|
76
|
+
- features/step_definitions/api_steps.rb
|
77
|
+
- features/step_definitions/user_steps.rb
|
78
|
+
- features/step_definitions/comment_steps.rb
|
79
|
+
- features/step_definitions/base_steps.rb
|
80
|
+
- features/support/base_helpers.rb
|
81
|
+
has_rdoc: true
|
82
|
+
homepage: http://github.com/jamescook/RubyRedditAPI
|
83
|
+
licenses: []
|
84
|
+
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
segments:
|
104
|
+
- 1
|
105
|
+
- 3
|
106
|
+
- 6
|
107
|
+
version: 1.3.6
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 1.3.7
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Wrapper for reddit API
|
115
|
+
test_files:
|
116
|
+
- features/reddit.yml
|
117
|
+
- features/submission.feature
|
118
|
+
- features/comment.feature
|
119
|
+
- features/user.feature
|
120
|
+
- features/base.feature
|
121
|
+
- features/message.feature
|
122
|
+
- features/api.feature
|
123
|
+
- features/step_definitions/message_steps.rb
|
124
|
+
- features/step_definitions/submission_steps.rb
|
125
|
+
- features/step_definitions/api_steps.rb
|
126
|
+
- features/step_definitions/user_steps.rb
|
127
|
+
- features/step_definitions/comment_steps.rb
|
128
|
+
- features/step_definitions/base_steps.rb
|
129
|
+
- features/support/base_helpers.rb
|