commit
bab8d77556
2 changed files with 80 additions and 34 deletions
|
@ -144,6 +144,8 @@ module Ebooks
|
||||||
attr_accessor :access_token
|
attr_accessor :access_token
|
||||||
# @return [String] OAuth access secret from `ebooks auth`
|
# @return [String] OAuth access secret from `ebooks auth`
|
||||||
attr_accessor :access_token_secret
|
attr_accessor :access_token_secret
|
||||||
|
# @return [Twitter::User] Twitter user object of bot
|
||||||
|
attr_accessor :user
|
||||||
# @return [String] Twitter username of bot
|
# @return [String] Twitter username of bot
|
||||||
attr_accessor :username
|
attr_accessor :username
|
||||||
# @return [Array<String>] list of usernames to block on contact
|
# @return [Array<String>] list of usernames to block on contact
|
||||||
|
@ -247,31 +249,18 @@ module Ebooks
|
||||||
# Receive an event from the twitter stream
|
# Receive an event from the twitter stream
|
||||||
# @param ev [Object] Twitter streaming event
|
# @param ev [Object] Twitter streaming event
|
||||||
def receive_event(ev)
|
def receive_event(ev)
|
||||||
if ev.is_a? Array # Initial array sent on first connection
|
case ev
|
||||||
|
when Array # Initial array sent on first connection
|
||||||
log "Online!"
|
log "Online!"
|
||||||
|
fire(:connect, ev)
|
||||||
return
|
return
|
||||||
end
|
when Twitter::DirectMessage
|
||||||
|
return if ev.sender.id == @user.id # Don't reply to self
|
||||||
if ev.is_a? Twitter::DirectMessage
|
|
||||||
return if ev.sender.screen_name.downcase == @username.downcase # Don't reply to self
|
|
||||||
log "DM from @#{ev.sender.screen_name}: #{ev.text}"
|
log "DM from @#{ev.sender.screen_name}: #{ev.text}"
|
||||||
fire(:message, ev)
|
fire(:message, ev)
|
||||||
|
when Twitter::Tweet
|
||||||
elsif ev.respond_to?(:name)
|
|
||||||
if ev.name == :follow
|
|
||||||
return if ev.source.screen_name.downcase == @username.downcase
|
|
||||||
log "Followed by #{ev.source.screen_name}"
|
|
||||||
fire(:follow, ev.source)
|
|
||||||
|
|
||||||
elsif ev.name == :favorite || ev.name == :unfavorite
|
|
||||||
return if ev.source.screen_name.downcase == @username.downcase # Ignore our own favorites
|
|
||||||
log "@#{ev.source.screen_name} #{ev.name.to_s}d: #{ev.target_object.text}"
|
|
||||||
fire(ev.name, ev.source, ev.target_object)
|
|
||||||
end
|
|
||||||
|
|
||||||
elsif ev.is_a? Twitter::Tweet
|
|
||||||
return unless ev.text # If it's not a text-containing tweet, ignore it
|
return unless ev.text # If it's not a text-containing tweet, ignore it
|
||||||
return if ev.user.screen_name.downcase == @username.downcase # Ignore our own tweets
|
return if ev.user.id == @user.id # Ignore our own tweets
|
||||||
|
|
||||||
meta = meta(ev)
|
meta = meta(ev)
|
||||||
|
|
||||||
|
@ -295,15 +284,34 @@ module Ebooks
|
||||||
else
|
else
|
||||||
fire(:timeline, ev)
|
fire(:timeline, ev)
|
||||||
end
|
end
|
||||||
|
when Twitter::Streaming::Event
|
||||||
elsif ev.is_a?(Twitter::Streaming::DeletedTweet) ||
|
case ev.name
|
||||||
ev.is_a?(Twitter::Streaming::Event)
|
when :follow
|
||||||
# pass
|
return if ev.source.id == @user.id
|
||||||
|
log "Followed by #{ev.source.screen_name}"
|
||||||
|
fire(:follow, ev.source)
|
||||||
|
when :favorite, :unfavorite
|
||||||
|
return if ev.source.id == @user.id # Ignore our own favorites
|
||||||
|
log "@#{ev.source.screen_name} #{ev.name.to_s}d: #{ev.target_object.text}"
|
||||||
|
fire(ev.name, ev.source, ev.target_object)
|
||||||
|
when :user_update
|
||||||
|
update_myself ev.source
|
||||||
|
end
|
||||||
|
when Twitter::Streaming::DeletedTweet
|
||||||
|
# Pass
|
||||||
else
|
else
|
||||||
log ev
|
log ev
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Updates @user and calls on_user_update.
|
||||||
|
def update_myself(new_me = twitter.user)
|
||||||
|
@user = new_me if @user.nil? || new_me.id == @user.id
|
||||||
|
@username = user.screen_name
|
||||||
|
log 'User information updated'
|
||||||
|
fire(:user_update)
|
||||||
|
end
|
||||||
|
|
||||||
# Configures client and fires startup event
|
# Configures client and fires startup event
|
||||||
def prepare
|
def prepare
|
||||||
# Sanity check
|
# Sanity check
|
||||||
|
@ -323,12 +331,12 @@ module Ebooks
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
real_name = twitter.user.screen_name
|
# Save old name
|
||||||
|
old_name = username
|
||||||
if real_name != @username
|
# Load user object and actual username
|
||||||
log "connected to @#{real_name}-- please update config to match Twitter account name"
|
update_myself
|
||||||
@username = real_name
|
# Warn about mismatches unless it was clearly intentional
|
||||||
end
|
log "warning: bot expected to be @#{old_name} but connected to @#{username}" unless username == old_name || old_name.empty?
|
||||||
|
|
||||||
fire(:startup)
|
fire(:startup)
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,8 +24,17 @@ end
|
||||||
|
|
||||||
module Ebooks::Test
|
module Ebooks::Test
|
||||||
# Generates a random twitter id
|
# Generates a random twitter id
|
||||||
def twitter_id
|
# Or a non-random one, given a string.
|
||||||
(rand*10**18).to_i
|
def twitter_id(seed = nil)
|
||||||
|
if seed.nil?
|
||||||
|
(rand*10**18).to_i
|
||||||
|
else
|
||||||
|
id = 1
|
||||||
|
seed.downcase.each_byte do |byte|
|
||||||
|
id *= byte/10
|
||||||
|
end
|
||||||
|
id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a mock direct message
|
# Creates a mock direct message
|
||||||
|
@ -33,7 +42,7 @@ module Ebooks::Test
|
||||||
# @param text DM content
|
# @param text DM content
|
||||||
def mock_dm(username, text)
|
def mock_dm(username, text)
|
||||||
Twitter::DirectMessage.new(id: twitter_id,
|
Twitter::DirectMessage.new(id: twitter_id,
|
||||||
sender: { id: twitter_id, screen_name: username},
|
sender: { id: twitter_id(username), screen_name: username},
|
||||||
text: text)
|
text: text)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -45,7 +54,7 @@ module Ebooks::Test
|
||||||
tweet = Twitter::Tweet.new({
|
tweet = Twitter::Tweet.new({
|
||||||
id: twitter_id,
|
id: twitter_id,
|
||||||
in_reply_to_status_id: 'mock-link',
|
in_reply_to_status_id: 'mock-link',
|
||||||
user: { id: twitter_id, screen_name: username },
|
user: { id: twitter_id(username), screen_name: username },
|
||||||
text: text,
|
text: text,
|
||||||
created_at: Time.now.to_s,
|
created_at: Time.now.to_s,
|
||||||
entities: {
|
entities: {
|
||||||
|
@ -58,14 +67,21 @@ module Ebooks::Test
|
||||||
tweet
|
tweet
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Creates a mock user
|
||||||
|
def mock_user(username)
|
||||||
|
Twitter::User.new(id: twitter_id(username), screen_name: username)
|
||||||
|
end
|
||||||
|
|
||||||
def twitter_spy(bot)
|
def twitter_spy(bot)
|
||||||
twitter = spy("twitter")
|
twitter = spy("twitter")
|
||||||
allow(twitter).to receive(:update).and_return(mock_tweet(bot.username, "test tweet"))
|
allow(twitter).to receive(:update).and_return(mock_tweet(bot.username, "test tweet"))
|
||||||
|
allow(twitter).to receive(:user).with(no_args).and_return(mock_user(bot.username))
|
||||||
twitter
|
twitter
|
||||||
end
|
end
|
||||||
|
|
||||||
def simulate(bot, &b)
|
def simulate(bot, &b)
|
||||||
bot.twitter = twitter_spy(bot)
|
bot.twitter = twitter_spy(bot)
|
||||||
|
bot.update_myself # Usually called in prepare
|
||||||
b.call
|
b.call
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -95,6 +111,13 @@ describe Ebooks::Bot do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "ignores its own dms" do
|
||||||
|
simulate(bot) do
|
||||||
|
expect(bot).to_not receive(:on_message)
|
||||||
|
bot.receive_event(mock_dm("Test_Ebooks", "why am I talking to myself"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "responds to mentions" do
|
it "responds to mentions" do
|
||||||
simulate(bot) do
|
simulate(bot) do
|
||||||
bot.receive_event(mock_tweet("m1sp", "@test_ebooks this is a mention"))
|
bot.receive_event(mock_tweet("m1sp", "@test_ebooks this is a mention"))
|
||||||
|
@ -102,6 +125,14 @@ describe Ebooks::Bot do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "ignores its own mentions" do
|
||||||
|
simulate(bot) do
|
||||||
|
expect(bot).to_not receive(:on_mention)
|
||||||
|
expect(bot).to_not receive(:on_timeline)
|
||||||
|
bot.receive_event(mock_tweet("Test_Ebooks", "@m1sp i think that @test_ebooks is best bot"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "responds to timeline tweets" do
|
it "responds to timeline tweets" do
|
||||||
simulate(bot) do
|
simulate(bot) do
|
||||||
bot.receive_event(mock_tweet("m1sp", "some excellent tweet"))
|
bot.receive_event(mock_tweet("m1sp", "some excellent tweet"))
|
||||||
|
@ -109,6 +140,13 @@ describe Ebooks::Bot do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "ignores its own timeline tweets" do
|
||||||
|
simulate(bot) do
|
||||||
|
expect(bot).to_not receive(:on_timeline)
|
||||||
|
bot.receive_event(mock_tweet("Test_Ebooks", "pudding is cute"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "links tweets to conversations correctly" do
|
it "links tweets to conversations correctly" do
|
||||||
tweet1 = mock_tweet("m1sp", "tweet 1", id: 1, in_reply_to_status_id: nil)
|
tweet1 = mock_tweet("m1sp", "tweet 1", id: 1, in_reply_to_status_id: nil)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue