twitter_ebooks_poll 3.2.0
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.
- checksums.yaml +7 -0
- data/.gitattributes +2 -0
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +167 -0
- data/Rakefile +2 -0
- data/bin/ebooks +449 -0
- data/data/adjectives.txt +1466 -0
- data/data/nouns.txt +2193 -0
- data/lib/twitter_ebooks/archive.rb +116 -0
- data/lib/twitter_ebooks/bot.rb +521 -0
- data/lib/twitter_ebooks/model.rb +336 -0
- data/lib/twitter_ebooks/nlp.rb +195 -0
- data/lib/twitter_ebooks/suffix.rb +104 -0
- data/lib/twitter_ebooks/sync.rb +52 -0
- data/lib/twitter_ebooks/version.rb +3 -0
- data/lib/twitter_ebooks.rb +22 -0
- data/skeleton/Gemfile +4 -0
- data/skeleton/Procfile +1 -0
- data/skeleton/bots.rb +65 -0
- data/skeleton/corpus/.gitignore +0 -0
- data/skeleton/gitignore +1 -0
- data/skeleton/image/.gitignore +0 -0
- data/skeleton/model/.gitignore +0 -0
- data/skeleton/stopwords.txt +843 -0
- data/spec/bot_spec.rb +216 -0
- data/spec/data/0xabad1dea.json +203945 -0
- data/spec/data/0xabad1dea.model +6158 -1
- data/spec/memprof.rb +37 -0
- data/spec/model_spec.rb +88 -0
- data/spec/spec_helper.rb +6 -0
- data/twitter_ebooks.gemspec +37 -0
- metadata +309 -0
data/spec/bot_spec.rb
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'memory_profiler'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'timecop'
|
5
|
+
|
6
|
+
class TestBot < Ebooks::Bot
|
7
|
+
attr_accessor :twitter
|
8
|
+
|
9
|
+
def configure
|
10
|
+
end
|
11
|
+
|
12
|
+
def on_message(dm)
|
13
|
+
reply dm, "echo: #{dm.text}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_mention(tweet)
|
17
|
+
reply tweet, "echo: #{meta(tweet).mentionless}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_timeline(tweet)
|
21
|
+
reply tweet, "fine tweet good sir"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Ebooks::Test
|
26
|
+
# Generates a random twitter id
|
27
|
+
# Or a non-random one, given a string.
|
28
|
+
def twitter_id(seed = nil)
|
29
|
+
if seed.nil?
|
30
|
+
(rand*10**18).to_i
|
31
|
+
else
|
32
|
+
id = 1
|
33
|
+
seed.downcase.each_byte do |byte|
|
34
|
+
id *= byte/10
|
35
|
+
end
|
36
|
+
id
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Creates a mock direct message
|
41
|
+
# @param username User sending the DM
|
42
|
+
# @param text DM content
|
43
|
+
def mock_dm(username, text)
|
44
|
+
Twitter::DirectMessage.new(id: twitter_id,
|
45
|
+
sender: { id: twitter_id(username), screen_name: username},
|
46
|
+
text: text)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Creates a mock tweet
|
50
|
+
# @param username User sending the tweet
|
51
|
+
# @param text Tweet content
|
52
|
+
def mock_tweet(username, text, extra={})
|
53
|
+
mentions = text.split.find_all { |x| x.start_with?('@') }
|
54
|
+
tweet = Twitter::Tweet.new({
|
55
|
+
id: twitter_id,
|
56
|
+
in_reply_to_status_id: 'mock-link',
|
57
|
+
user: { id: twitter_id(username), screen_name: username },
|
58
|
+
text: text,
|
59
|
+
created_at: Time.now.to_s,
|
60
|
+
entities: {
|
61
|
+
user_mentions: mentions.map { |m|
|
62
|
+
{ screen_name: m.split('@')[1],
|
63
|
+
indices: [text.index(m), text.index(m)+m.length] }
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}.merge!(extra))
|
67
|
+
tweet
|
68
|
+
end
|
69
|
+
|
70
|
+
# Creates a mock user
|
71
|
+
def mock_user(username)
|
72
|
+
Twitter::User.new(id: twitter_id(username), screen_name: username)
|
73
|
+
end
|
74
|
+
|
75
|
+
def twitter_spy(bot)
|
76
|
+
twitter = spy("twitter")
|
77
|
+
allow(twitter).to receive(:update).and_return(mock_tweet(bot.username, "test tweet"))
|
78
|
+
allow(twitter).to receive(:user).with(no_args).and_return(mock_user(bot.username))
|
79
|
+
twitter
|
80
|
+
end
|
81
|
+
|
82
|
+
def simulate(bot, &b)
|
83
|
+
bot.twitter = twitter_spy(bot)
|
84
|
+
bot.update_myself # Usually called in prepare
|
85
|
+
b.call
|
86
|
+
end
|
87
|
+
|
88
|
+
def expect_direct_message(bot, content)
|
89
|
+
expect(bot.twitter).to have_received(:create_direct_message).with(anything(), content, {})
|
90
|
+
bot.twitter = twitter_spy(bot)
|
91
|
+
end
|
92
|
+
|
93
|
+
def expect_tweet(bot, content)
|
94
|
+
expect(bot.twitter).to have_received(:update).with(content, anything())
|
95
|
+
bot.twitter = twitter_spy(bot)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
describe Ebooks::Bot do
|
101
|
+
include Ebooks::Test
|
102
|
+
let(:bot) { TestBot.new('Test_Ebooks') }
|
103
|
+
|
104
|
+
before { Timecop.freeze }
|
105
|
+
after { Timecop.return }
|
106
|
+
|
107
|
+
it "responds to dms" do
|
108
|
+
simulate(bot) do
|
109
|
+
bot.receive_event(mock_dm("m1sp", "this is a dm"))
|
110
|
+
expect_direct_message(bot, "echo: this is a dm")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it "ignores its own dms" do
|
115
|
+
simulate(bot) do
|
116
|
+
expect(bot).to_not receive(:on_message)
|
117
|
+
bot.receive_event(mock_dm("Test_Ebooks", "why am I talking to myself"))
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it "responds to mentions" do
|
122
|
+
simulate(bot) do
|
123
|
+
bot.receive_event(mock_tweet("m1sp", "@test_ebooks this is a mention"))
|
124
|
+
expect_tweet(bot, "@m1sp echo: this is a mention")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "ignores its own mentions" do
|
129
|
+
simulate(bot) do
|
130
|
+
expect(bot).to_not receive(:on_mention)
|
131
|
+
expect(bot).to_not receive(:on_timeline)
|
132
|
+
bot.receive_event(mock_tweet("Test_Ebooks", "@m1sp i think that @test_ebooks is best bot"))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
it "responds to timeline tweets" do
|
137
|
+
simulate(bot) do
|
138
|
+
bot.receive_event(mock_tweet("m1sp", "some excellent tweet"))
|
139
|
+
expect_tweet(bot, "@m1sp fine tweet good sir")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
it "ignores its own timeline tweets" do
|
144
|
+
simulate(bot) do
|
145
|
+
expect(bot).to_not receive(:on_timeline)
|
146
|
+
bot.receive_event(mock_tweet("Test_Ebooks", "pudding is cute"))
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
it "links tweets to conversations correctly" do
|
151
|
+
tweet1 = mock_tweet("m1sp", "tweet 1", id: 1, in_reply_to_status_id: nil)
|
152
|
+
|
153
|
+
tweet2 = mock_tweet("m1sp", "tweet 2", id: 2, in_reply_to_status_id: 1)
|
154
|
+
|
155
|
+
tweet3 = mock_tweet("m1sp", "tweet 3", id: 3, in_reply_to_status_id: nil)
|
156
|
+
|
157
|
+
bot.conversation(tweet1).add(tweet1)
|
158
|
+
expect(bot.conversation(tweet2)).to eq(bot.conversation(tweet1))
|
159
|
+
|
160
|
+
bot.conversation(tweet2).add(tweet2)
|
161
|
+
expect(bot.conversation(tweet3)).to_not eq(bot.conversation(tweet2))
|
162
|
+
end
|
163
|
+
|
164
|
+
it "stops mentioning people after a certain limit" do
|
165
|
+
simulate(bot) do
|
166
|
+
bot.receive_event(mock_tweet("spammer", "@test_ebooks @m1sp 1"))
|
167
|
+
expect_tweet(bot, "@spammer @m1sp echo: 1")
|
168
|
+
|
169
|
+
Timecop.travel(Time.now + 60)
|
170
|
+
bot.receive_event(mock_tweet("spammer", "@test_ebooks @m1sp 2"))
|
171
|
+
expect_tweet(bot, "@spammer @m1sp echo: 2")
|
172
|
+
|
173
|
+
Timecop.travel(Time.now + 60)
|
174
|
+
bot.receive_event(mock_tweet("spammer", "@test_ebooks @m1sp 3"))
|
175
|
+
expect_tweet(bot, "@spammer echo: 3")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it "doesn't stop mentioning them if they reply" do
|
180
|
+
simulate(bot) do
|
181
|
+
bot.receive_event(mock_tweet("spammer", "@test_ebooks @m1sp 4"))
|
182
|
+
expect_tweet(bot, "@spammer @m1sp echo: 4")
|
183
|
+
|
184
|
+
Timecop.travel(Time.now + 60)
|
185
|
+
bot.receive_event(mock_tweet("m1sp", "@spammer @test_ebooks 5"))
|
186
|
+
expect_tweet(bot, "@m1sp @spammer echo: 5")
|
187
|
+
|
188
|
+
Timecop.travel(Time.now + 60)
|
189
|
+
bot.receive_event(mock_tweet("spammer", "@test_ebooks @m1sp 6"))
|
190
|
+
expect_tweet(bot, "@spammer @m1sp echo: 6")
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
it "doesn't get into infinite bot conversations" do
|
195
|
+
simulate(bot) do
|
196
|
+
bot.receive_event(mock_tweet("spammer", "@test_ebooks @m1sp 7"))
|
197
|
+
expect_tweet(bot, "@spammer @m1sp echo: 7")
|
198
|
+
|
199
|
+
Timecop.travel(Time.now + 2)
|
200
|
+
bot.receive_event(mock_tweet("spammer", "@test_ebooks @m1sp 8"))
|
201
|
+
expect_tweet(bot, "@spammer @m1sp echo: 8")
|
202
|
+
|
203
|
+
Timecop.travel(Time.now + 2)
|
204
|
+
bot.receive_event(mock_tweet("spammer", "@test_ebooks @m1sp 9"))
|
205
|
+
expect(bot.twitter).to_not have_received(:update)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
it "blocks blacklisted users on contact" do
|
210
|
+
simulate(bot) do
|
211
|
+
bot.blacklist = ["spammer"]
|
212
|
+
bot.receive_event(mock_tweet("spammer", "@test_ebooks @m1sp 7"))
|
213
|
+
expect(bot.twitter).to have_received(:block).with("spammer")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|