tweetbot 0.1.3
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/.gitignore +4 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/README +39 -0
- data/Rakefile +1 -0
- data/example/run_bot.rb +19 -0
- data/example/twitter_auth.rb +13 -0
- data/lib/tweetbot.rb +11 -0
- data/lib/tweetbot/bot.rb +59 -0
- data/lib/tweetbot/talk.rb +126 -0
- data/lib/tweetbot/version.rb +3 -0
- data/spec/tweetbot_config_spec.rb +103 -0
- data/spec/tweetbot_spec.rb +136 -0
- data/tweetbot.gemspec +26 -0
- metadata +107 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2@tweetbot
|
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
So you want to write a twitter bot. Use my gem. Then, you can just do this:
|
2
|
+
|
3
|
+
load 'twitter_auth.rb'
|
4
|
+
require 'tweetbot'
|
5
|
+
|
6
|
+
bot = TweetBot.configure do |config|
|
7
|
+
config.response_frequency = 100
|
8
|
+
|
9
|
+
config.respond_to_phrase "tweetbot example phrase" do |responses|
|
10
|
+
responses << "I am tweetbot!" << "You rang?" << "Pretty cool, thanks for saying hello"
|
11
|
+
end
|
12
|
+
|
13
|
+
config.respond_to_phrase "hey @tweetbot" do |responses|
|
14
|
+
responses << "Hey back at ya" << "You rang again?"
|
15
|
+
end
|
16
|
+
|
17
|
+
config.twitter_auth = TwitterAuth::AuthKeys
|
18
|
+
end
|
19
|
+
|
20
|
+
bot.talk
|
21
|
+
|
22
|
+
and build a file called twitter_auth.rb that has your keys
|
23
|
+
|
24
|
+
module TwitterAuth
|
25
|
+
MyName = 'twitter_name'
|
26
|
+
ApigeeEnpoint = nil
|
27
|
+
def self.use_apigee?
|
28
|
+
!ApigeeEnpoint.nil?
|
29
|
+
end
|
30
|
+
AuthKeys = {
|
31
|
+
consumer_key: "key",
|
32
|
+
consumer_secret: "secret",
|
33
|
+
oauth_token: "token",
|
34
|
+
oauth_token_secret: "token_secret"
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
Abstracting out the apigee stuff, don't worry. Just leave it like that for now.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/example/run_bot.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
load 'twitter_auth.rb'
|
2
|
+
require 'tweetbot'
|
3
|
+
|
4
|
+
bot = TweetBot.configure do |config|
|
5
|
+
config.response_frequency = 100
|
6
|
+
|
7
|
+
config.respond_to_phrase "tweetbot example phrase" do |responses|
|
8
|
+
responses << "I am tweetbot!" << "You rang?" << "Pretty cool, thanks for saying hello"
|
9
|
+
end
|
10
|
+
|
11
|
+
config.respond_to_phrase "hey @tweetbot" do |responses|
|
12
|
+
responses << "Hey back at ya" << "You rang again?"
|
13
|
+
end
|
14
|
+
|
15
|
+
config.twitter_auth = TwitterAuth::AuthKeys
|
16
|
+
end
|
17
|
+
|
18
|
+
bot.talk
|
19
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module TwitterAuth
|
2
|
+
MyName = 'twitter_name'
|
3
|
+
ApigeeEnpoint = nil
|
4
|
+
def self.use_apigee?
|
5
|
+
!ApigeeEnpoint.nil?
|
6
|
+
end
|
7
|
+
AuthKeys = {
|
8
|
+
consumer_key: "key",
|
9
|
+
consumer_secret: "secret",
|
10
|
+
oauth_token: "token",
|
11
|
+
oauth_token_secret: "token_secret"
|
12
|
+
}
|
13
|
+
end
|
data/lib/tweetbot.rb
ADDED
data/lib/tweetbot/bot.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module TweetBot
|
2
|
+
class Bot
|
3
|
+
include TweetBot::Talk
|
4
|
+
attr_accessor :response_frequency, :twitter_auth
|
5
|
+
|
6
|
+
DefaultFrequency = 20
|
7
|
+
|
8
|
+
def initialize()
|
9
|
+
self.response_frequency = DefaultFrequency
|
10
|
+
@responses_for_phrases = Hash.new { |hash, key| hash[key] = [] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def phrases_to_search
|
14
|
+
@responses_for_phrases.keys
|
15
|
+
end
|
16
|
+
|
17
|
+
def responses_for(phrase)
|
18
|
+
@responses_for_phrases[phrase]
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to_phrase(phrase)
|
22
|
+
responses = []
|
23
|
+
yield responses
|
24
|
+
add_responses_for_phrase(phrase, *responses)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_responses_for_phrase(phrase, *responses)
|
28
|
+
@responses_for_phrases[phrase.downcase] += responses
|
29
|
+
end
|
30
|
+
|
31
|
+
def response_for(tweet)
|
32
|
+
responses = responses_for_tweet(tweet)
|
33
|
+
"@#{tweet.user.screen_name} #{responses.sample}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def should_i_respond_to?(tweet)
|
37
|
+
return false if under_rate_limit_pause?
|
38
|
+
matches = tweet_matches?(tweet)
|
39
|
+
frequency_check = (rand(100) < self.response_frequency)
|
40
|
+
matches && frequency_check
|
41
|
+
end
|
42
|
+
|
43
|
+
def rate_limited!
|
44
|
+
@rate_limited_until = Time.now + 3600
|
45
|
+
end
|
46
|
+
|
47
|
+
def under_rate_limit_pause?
|
48
|
+
@rate_limited_until && (Time.now < @rate_limited_until)
|
49
|
+
end
|
50
|
+
|
51
|
+
def tweet_matches?(tweet)
|
52
|
+
responses_for_tweet(tweet).any?
|
53
|
+
end
|
54
|
+
|
55
|
+
def responses_for_tweet(tweet)
|
56
|
+
@responses_for_phrases.select{|phrase, _| tweet.text =~ /#{phrase}/i}.values[0] || []
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'twitter'
|
2
|
+
require 'tweetstream'
|
3
|
+
|
4
|
+
if ENV["DEBUG"]
|
5
|
+
module Twitter
|
6
|
+
def self.configure
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.update(status, options = {})
|
10
|
+
puts "DEBUG: #{status}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
module TweetBot
|
15
|
+
module Talk
|
16
|
+
def configure_twitter_auth
|
17
|
+
Twitter.configure do |config|
|
18
|
+
config.consumer_key = twitter_auth[:consumer_key]
|
19
|
+
config.consumer_secret = twitter_auth[:consumer_secret]
|
20
|
+
config.oauth_token = twitter_auth[:oauth_token]
|
21
|
+
config.oauth_token_secret = twitter_auth[:oauth_token_secret]
|
22
|
+
end
|
23
|
+
TweetStream.configure do |config|
|
24
|
+
config.consumer_key = twitter_auth[:consumer_key]
|
25
|
+
config.consumer_secret = twitter_auth[:consumer_secret]
|
26
|
+
config.oauth_token = twitter_auth[:oauth_token]
|
27
|
+
config.oauth_token_secret = twitter_auth[:oauth_token_secret]
|
28
|
+
config.auth_method = :oauth
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def talk
|
33
|
+
configure_twitter_auth
|
34
|
+
|
35
|
+
if TwitterAuth.use_apigee?
|
36
|
+
twitter_api_endpoint = if ENV['APIGEE_TWITTER_API_ENDPOINT']
|
37
|
+
ENV['APIGEE_TWITTER_API_ENDPOINT']
|
38
|
+
else
|
39
|
+
# Get this value from Heroku.
|
40
|
+
# Once you have enabled the addon, boot up the 'heroku console' and run the following:
|
41
|
+
# puts ENV['APIGEE_TWITTER_API_ENDPOINT']
|
42
|
+
# this will spit out your correct api endpoint
|
43
|
+
TwitterAuth::ApigeeEnpoint
|
44
|
+
end
|
45
|
+
Twitter.configure do |config|
|
46
|
+
config.gateway = twitter_api_endpoint
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
bot = self
|
51
|
+
|
52
|
+
announce_wake_up
|
53
|
+
puts "Listening... #{Time.now}"
|
54
|
+
|
55
|
+
|
56
|
+
client = TweetStream::Client.new
|
57
|
+
|
58
|
+
["INT", "TERM", "STOP"].each do |signal|
|
59
|
+
trap(signal) do
|
60
|
+
puts "Got #{signal}"
|
61
|
+
client.stop
|
62
|
+
exit!(1)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
at_exit do
|
67
|
+
puts "Shutting down... #{Time.now}"
|
68
|
+
begin
|
69
|
+
send_twitter_message "Going to sleep... #{Time.now}"
|
70
|
+
rescue
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
client.on_error do |message|
|
76
|
+
puts "Error: #{Time.now}"
|
77
|
+
puts message
|
78
|
+
end
|
79
|
+
|
80
|
+
#EM.defer
|
81
|
+
#EM::HttpRequest
|
82
|
+
client.track(*bot.phrases_to_search) do |status|
|
83
|
+
if status.user.screen_name == TwitterAuth::MyName
|
84
|
+
puts "#{Time.now} Caught myself saying it"
|
85
|
+
else
|
86
|
+
puts "#{Time.now} #{status.user.screen_name} said #{status.text}"
|
87
|
+
if bot.should_i_respond_to?(status)
|
88
|
+
response = bot.response_for(status)
|
89
|
+
begin
|
90
|
+
send_twitter_message(response, :in_reply_to_status_id => status.id)
|
91
|
+
rescue Twitter::Forbidden => ex
|
92
|
+
puts "Rate limited!"
|
93
|
+
bot.rate_limited!
|
94
|
+
rescue Exception => e
|
95
|
+
puts "Exception while sending the reply"
|
96
|
+
puts e
|
97
|
+
end
|
98
|
+
else
|
99
|
+
puts "Bot told me not to respond"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def send_twitter_message(message, options = {})
|
106
|
+
Twitter.update message, options
|
107
|
+
end
|
108
|
+
|
109
|
+
def announce_wake_up
|
110
|
+
puts "Waking up to greet the world... #{Time.now}"
|
111
|
+
send_twitter_message "Waking up to greet the world... #{Time.now}"
|
112
|
+
rescue Twitter::Forbidden => ex
|
113
|
+
puts "Twitter Forbidden Error while waking up"
|
114
|
+
puts ex
|
115
|
+
puts "Continuing"
|
116
|
+
rescue Twitter::Error => ex
|
117
|
+
puts "Twitter Error while waking up"
|
118
|
+
puts ex
|
119
|
+
exit!(1)
|
120
|
+
rescue => ex
|
121
|
+
puts "Unknown Error while waking up"
|
122
|
+
puts ex
|
123
|
+
exit!(1)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require_relative '../lib/tweetbot'
|
2
|
+
module Twitter
|
3
|
+
end
|
4
|
+
module TweetStream
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "configuring tweetbot with a config block" do
|
8
|
+
class DummyAuth
|
9
|
+
attr_accessor :consumer_key, :consumer_secret, :oauth_token,
|
10
|
+
:oauth_token_secret, :auth_method
|
11
|
+
end
|
12
|
+
|
13
|
+
before do
|
14
|
+
Twitter.stub(:configure)
|
15
|
+
TweetStream.stub(:configure)
|
16
|
+
end
|
17
|
+
|
18
|
+
context "configuring with twitter authentication" do
|
19
|
+
it "configures twitter with the oauth keys" do
|
20
|
+
auth = DummyAuth.new
|
21
|
+
bot = TweetBot.configure do |bot|
|
22
|
+
bot.twitter_auth = {
|
23
|
+
consumer_key: "ckey",
|
24
|
+
consumer_secret: "csecret",
|
25
|
+
oauth_token: "token",
|
26
|
+
oauth_token_secret: "tokensecret"
|
27
|
+
}
|
28
|
+
end
|
29
|
+
Twitter.stub(:configure).and_yield auth
|
30
|
+
bot.configure_twitter_auth
|
31
|
+
auth.consumer_key.should == "ckey"
|
32
|
+
auth.consumer_secret.should == "csecret"
|
33
|
+
auth.oauth_token.should == "token"
|
34
|
+
auth.oauth_token_secret.should == "tokensecret"
|
35
|
+
end
|
36
|
+
it "configures tweetstream with the oauth keys" do
|
37
|
+
auth = DummyAuth.new
|
38
|
+
bot = TweetBot.configure do |bot|
|
39
|
+
bot.twitter_auth = {
|
40
|
+
consumer_key: "ckey",
|
41
|
+
consumer_secret: "csecret",
|
42
|
+
oauth_token: "token",
|
43
|
+
oauth_token_secret: "tokensecret"
|
44
|
+
}
|
45
|
+
end
|
46
|
+
TweetStream.stub(:configure).and_yield auth
|
47
|
+
bot.configure_twitter_auth
|
48
|
+
auth.consumer_key.should == "ckey"
|
49
|
+
auth.consumer_secret.should == "csecret"
|
50
|
+
auth.oauth_token.should == "token"
|
51
|
+
auth.oauth_token_secret.should == "tokensecret"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "configuring twice" do
|
56
|
+
it "uses the same bot" do
|
57
|
+
bot1 = TweetBot.configure do |bot|
|
58
|
+
bot.response_frequency = 4
|
59
|
+
end
|
60
|
+
|
61
|
+
bot2 = TweetBot.configure do |bot|
|
62
|
+
bot.response_frequency = 10
|
63
|
+
end
|
64
|
+
|
65
|
+
bot1.should be(bot2)
|
66
|
+
bot1.response_frequency.should == 10
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "configuring frequency" do
|
71
|
+
let(:bot) do
|
72
|
+
TweetBot.configure do |bot|
|
73
|
+
bot.response_frequency = 4
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "saves the response_frequency" do
|
78
|
+
bot.response_frequency.should == 4
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "configuring responses" do
|
83
|
+
let(:bot) do
|
84
|
+
TweetBot.configure do |bot|
|
85
|
+
bot.respond_to_phrase "code and coffee" do |responses|
|
86
|
+
responses << "good times" << "bad times"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it "saves the response given in block" do
|
92
|
+
bot.responses_for("code and coffee").should =~ ["good times", "bad times"]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "without a configure block" do
|
97
|
+
it "returns a bot that I can use" do
|
98
|
+
bot = TweetBot.configure
|
99
|
+
bot.response_frequency = 4
|
100
|
+
bot.response_frequency.should == 4
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require_relative '../lib/tweetbot'
|
2
|
+
require 'timecop'
|
3
|
+
|
4
|
+
|
5
|
+
describe TweetBot::Bot do
|
6
|
+
let(:bot) { TweetBot::Bot.new }
|
7
|
+
let(:tweet) { stub(:text => "hello world", :user => stub(:screen_name => "fun_person")) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
bot.add_responses_for_phrase "hello world", "and hello to you"
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
Timecop.return
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
describe "#phrases_to_search" do
|
19
|
+
it "returns the phrases that have responses associated with them" do
|
20
|
+
bot.add_responses_for_phrase "good night", ""
|
21
|
+
bot.phrases_to_search.should == ["hello world", "good night"]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#tweet_matches?" do
|
26
|
+
before do
|
27
|
+
bot.add_responses_for_phrase "the night", "a dark night"
|
28
|
+
end
|
29
|
+
it "looks to see if any phrases match the tweet" do
|
30
|
+
tweet.stub(:text) { "the night" }
|
31
|
+
bot.tweet_matches?(tweet).should be_true
|
32
|
+
tweet.stub(:text) { "the day" }
|
33
|
+
bot.tweet_matches?(tweet).should be_false
|
34
|
+
end
|
35
|
+
|
36
|
+
it "compares case-insensitive" do
|
37
|
+
tweet.stub(:text) { "The Night"}
|
38
|
+
bot.tweet_matches?(tweet).should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "matches if anywhere in text" do
|
42
|
+
tweet.stub(:text) { "It is cold The Night"}
|
43
|
+
bot.tweet_matches?(tweet).should be_true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#response_for" do
|
48
|
+
it "replies to the user" do
|
49
|
+
tweet.user.stub(:screen_name) { "corey" }
|
50
|
+
bot.response_for(tweet).should =~ /^@corey/
|
51
|
+
end
|
52
|
+
|
53
|
+
it "uses responses associated with phrase" do
|
54
|
+
bot.add_responses_for_phrase("good morning", "morning response")
|
55
|
+
bot.add_responses_for_phrase("good night", "night response")
|
56
|
+
|
57
|
+
tweet.stub(:text) { "good morning" }
|
58
|
+
bot.response_for(tweet).should =~ /morning response/
|
59
|
+
tweet.stub(:text) { "good night" }
|
60
|
+
bot.response_for(tweet).should =~ /night response/
|
61
|
+
end
|
62
|
+
|
63
|
+
it "it randomly uses a phrase from the responses" do
|
64
|
+
tweet.stub(:text) { "good morning" }
|
65
|
+
bot.add_responses_for_phrase("good morning", "response 1", "response 2")
|
66
|
+
responses = (1..20).map do
|
67
|
+
bot.response_for(tweet)
|
68
|
+
end
|
69
|
+
responses.reject! {|response| response =~ /response 1/}
|
70
|
+
responses.should_not be_empty
|
71
|
+
responses.reject! {|response| response =~ /response 2/}
|
72
|
+
responses.should be_empty
|
73
|
+
end
|
74
|
+
|
75
|
+
it "uses responses if phrase appears anywhere in tweet (case-insensitive)" do
|
76
|
+
bot.add_responses_for_phrase("good afternoon", "afternoon response")
|
77
|
+
tweet.stub(:text) { "this is a Good Afternoon" }
|
78
|
+
bot.response_for(tweet).should =~ /afternoon response/
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#should_i_respond_to?" do
|
83
|
+
before do
|
84
|
+
bot.stub(:rand) { 1 }
|
85
|
+
bot.stub(:tweet_matches?) { true }
|
86
|
+
end
|
87
|
+
|
88
|
+
context "Under rate limit" do
|
89
|
+
let(:now) { Time.now }
|
90
|
+
let(:status) { stub }
|
91
|
+
before do
|
92
|
+
Timecop.freeze(now)
|
93
|
+
bot.rate_limited!
|
94
|
+
end
|
95
|
+
|
96
|
+
it "won't allow response for 1 hour" do
|
97
|
+
bot.should_i_respond_to?(status).should be_false
|
98
|
+
Timecop.travel(now + 60 * 59) do
|
99
|
+
bot.should_i_respond_to?(status).should be_false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it "will allow response after an hour" do
|
104
|
+
Timecop.travel(now + 3600) do
|
105
|
+
bot.should_i_respond_to?(status).should be_true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "only responds if rand is less than response_frequency" do
|
111
|
+
bot.response_frequency = 30
|
112
|
+
bot.stub(:rand) { 29 }
|
113
|
+
bot.should_i_respond_to?(stub).should be_true
|
114
|
+
bot.stub(:rand) { 30 }
|
115
|
+
bot.should_i_respond_to?(stub).should be_false
|
116
|
+
bot.stub(:rand) { 31 }
|
117
|
+
bot.should_i_respond_to?(stub).should be_false
|
118
|
+
end
|
119
|
+
|
120
|
+
it "only responds if phrase matches" do
|
121
|
+
bot.stub(:tweet_matches?) { true }
|
122
|
+
bot.should_i_respond_to?(stub).should be_true
|
123
|
+
bot.stub(:tweet_matches?) { false }
|
124
|
+
bot.should_i_respond_to?(stub).should be_false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#respond_to_phrase" do
|
129
|
+
it "stores the given responses" do
|
130
|
+
bot.respond_to_phrase "morning fun" do |responses|
|
131
|
+
responses << "evening delight" << "afternoon rockets"
|
132
|
+
end
|
133
|
+
bot.responses_for_tweet(stub(:text => "morning fun")).should =~ ["evening delight", "afternoon rockets"]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/tweetbot.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "tweetbot/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "tweetbot"
|
7
|
+
s.version = Tweetbot::VERSION
|
8
|
+
s.authors = ["coreyhaines"]
|
9
|
+
s.email = ["coreyhaines@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Tweetbot makes writing twitter bots twivial!}
|
12
|
+
s.description = %q{Using tweetbot, you can easily create twitter bots that respond to key phrases that people say on the twitters}
|
13
|
+
|
14
|
+
s.rubyforge_project = "tweetbot"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
s.add_development_dependency "timecop"
|
24
|
+
s.add_runtime_dependency "twitter"
|
25
|
+
s.add_runtime_dependency "tweetstream"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tweetbot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- coreyhaines
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-13 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &2153278820 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2153278820
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: timecop
|
27
|
+
requirement: &2153278400 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2153278400
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: twitter
|
38
|
+
requirement: &2153277980 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2153277980
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: tweetstream
|
49
|
+
requirement: &2153277540 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2153277540
|
58
|
+
description: Using tweetbot, you can easily create twitter bots that respond to key
|
59
|
+
phrases that people say on the twitters
|
60
|
+
email:
|
61
|
+
- coreyhaines@gmail.com
|
62
|
+
executables: []
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- .gitignore
|
67
|
+
- .rspec
|
68
|
+
- .rvmrc
|
69
|
+
- Gemfile
|
70
|
+
- README
|
71
|
+
- Rakefile
|
72
|
+
- example/run_bot.rb
|
73
|
+
- example/twitter_auth.rb
|
74
|
+
- lib/tweetbot.rb
|
75
|
+
- lib/tweetbot/bot.rb
|
76
|
+
- lib/tweetbot/talk.rb
|
77
|
+
- lib/tweetbot/version.rb
|
78
|
+
- spec/tweetbot_config_spec.rb
|
79
|
+
- spec/tweetbot_spec.rb
|
80
|
+
- tweetbot.gemspec
|
81
|
+
homepage: ''
|
82
|
+
licenses: []
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project: tweetbot
|
101
|
+
rubygems_version: 1.8.10
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
summary: Tweetbot makes writing twitter bots twivial!
|
105
|
+
test_files:
|
106
|
+
- spec/tweetbot_config_spec.rb
|
107
|
+
- spec/tweetbot_spec.rb
|