boty 0.0.17 → 0.0.17.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d60d83658211dd0b17fdfeb269033ce2c73ee291
4
- data.tar.gz: 29148f8ba9a8d4dfa83d36f612c2a97959f5e5ef
3
+ metadata.gz: 0ebb5950dfa8625a01e2aca017fbd5ed259c499d
4
+ data.tar.gz: 463e6b73167a63d36ec7441c9205784bf74a5520
5
5
  SHA512:
6
- metadata.gz: 4e583ec20c26d42226cf1e52bedfebab6b184bbccca3a3ecab576fe305a0adb96ea1a6d56a1d19d0e115cb1e1c5682c81ddb15b8505956b8a6e32f2a525269b9
7
- data.tar.gz: cef240051671e266025c744489090c199c54177305da4dd0343b131076c270ad8278c1350be895e8d9b726c5af8224658cac95fc774fc3e8deb49f63cbfd0d91
6
+ metadata.gz: 5ad60851ef2067df1eaafc8a6bf9be654c2494cf1be814a33a920df05f1b702a8f818d4661d4144c5771bb5dfde15b7e6054227ece9d3208fd296b413bab6577
7
+ data.tar.gz: 9fa330463454c9be3297c034a4189d7f6663d8a5ad6bfff6b474d0f9866ab33fbc2d1bf6a541431e70771545f5ee46bd97cb4356f6111ddcde0d6d8a438976c6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boty (0.0.17)
4
+ boty (0.0.17.1)
5
5
  eventmachine
6
6
  faraday
7
7
  faye-websocket
data/boty.gemspec CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = "http://github.com/ricardovaleriano/boty"
15
15
  spec.license = "MIT"
16
16
 
17
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(features)/}) }
18
18
  spec.bindir = "exe"
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
data/lib/boty/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Boty
2
- VERSION = "0.0.17"
2
+ VERSION = "0.0.17.1"
3
3
  end
@@ -0,0 +1,419 @@
1
+ module Boty
2
+ RSpec.describe "happy brighty shiny path", :session do
3
+ before do
4
+ start_session
5
+ end
6
+
7
+ let(:user_id) { "U5678" }
8
+
9
+ before do
10
+ bot.hear(/jeeba/i) do
11
+ say "Ohay <@#{user.id}>! I'm here, that's for sure."
12
+ end
13
+
14
+ bot.hear(/anybody there\?/i) do
15
+ say "Me! Here."
16
+ end
17
+
18
+ bot.match(/with match/i) do
19
+ say "Ohay <@#{user.id}>! It matched."
20
+ end
21
+
22
+ bot.command(/do stuff/i) do
23
+ say "Doing some stuff"
24
+ end
25
+
26
+ bot.command(/exec command/i) do
27
+ say "Command issued."
28
+ end
29
+ end
30
+
31
+ it "responds to a message" do
32
+ expect(bot).to receive(:say).
33
+ with "Ohay <@U5678>! I'm here, that's for sure."
34
+ faye.message "jeeba, are you there?", user: "U5678"
35
+ end
36
+
37
+ it "responds to a match" do
38
+ expect(bot).to receive(:say).
39
+ with "Ohay <@U5678>! It matched."
40
+ faye.message "called with match?", user: "U5678"
41
+ end
42
+
43
+ it "does not respond to a message not binded" do
44
+ expect(bot).to_not receive(:say)
45
+ faye.message "are you there?"
46
+ end
47
+
48
+ it "understands #hear as a message binding" do
49
+ expect(bot).to receive(:say).with("Me! Here.")
50
+ faye.message "anybody there?"
51
+ end
52
+
53
+ context "Direct message" do
54
+ it "responds when mentioned by name" do
55
+ expect(bot).to receive(:say).with "Doing some stuff"
56
+ faye.message "<@jeeba>: do stuff!"
57
+ end
58
+
59
+ it "responds when mentioned by id" do
60
+ expect(bot).to receive(:say).with "Doing some stuff"
61
+ faye.message "<@U1234>: do stuff!"
62
+ end
63
+
64
+ it "responds just once" do
65
+ expect(bot).to receive(:im).once
66
+ faye.message "<@U1234>: knows"
67
+ end
68
+
69
+ it "responds when mentioned by both name and id in the same message" do
70
+ expect(bot).to receive(:im).once
71
+ faye.message "<@U1234|jabber>: knows"
72
+ end
73
+
74
+ it "understands `#command` bindings" do
75
+ expect(bot).to receive(:say).with "Command issued."
76
+ faye.message "<@U1234>: exec command xpto"
77
+ end
78
+ end
79
+ end
80
+
81
+ RSpec.describe Bot do
82
+ subject(:bot) { described_class.new bot_info, Session.new }
83
+
84
+ let(:bot_info) {{
85
+ "id" => "666",
86
+ "name" => "jabber"
87
+ }}
88
+
89
+ describe "#on" do
90
+ it "binds an event `'type'` to a block" do
91
+ data = {
92
+ "type" => "omg",
93
+ "text" => "lol"
94
+ }
95
+
96
+ expect { |b|
97
+ bot.on :omg, &b
98
+ bot.event data
99
+ }.to yield_with_args data
100
+ end
101
+ end
102
+
103
+ describe "#off" do
104
+ let(:data) {{
105
+ "type" => "bbq",
106
+ "text" => "omg. wtf."
107
+ }}
108
+
109
+ it "unbounds an event by type AND block, just if the block is the same" do
110
+ @permanent_executed = false
111
+ permanent_block = ->(_){ @permanent_executed = true }
112
+ bot.on :bbq, &permanent_block
113
+
114
+ @ephemeral_executed = false
115
+ ephemeral_block = ->(_){ @ephemeral_executed = true }
116
+ bot.on :bbq, &ephemeral_block
117
+ bot.off :bbq, &ephemeral_block
118
+
119
+ bot.event data
120
+
121
+ expect(@permanent_executed).to eq true
122
+ expect(@ephemeral_executed).to eq false
123
+ end
124
+
125
+ it "unbounds all events by type" do
126
+ @first_block = @second_block = @third_block = false
127
+ bot.on(:bbq) { |_| @first_block = true }
128
+ bot.on(:bbq) { |_| @second_block = true }
129
+ bot.on(:bbq) { |_| @third_block = true }
130
+ bot.off(:bbq)
131
+
132
+ bot.event data
133
+
134
+ expect(@first_block).to eq false
135
+ expect(@second_block).to eq false
136
+ expect(@third_block).to eq false
137
+ end
138
+ end
139
+
140
+ describe "#match", :users do
141
+ let(:data) { {"type" => "message", "text" => "bbq omg lol"} }
142
+
143
+ it "binds a regex to events of `type => message`" do
144
+ _message = nil
145
+ bot.match(/omg/i) do
146
+ _message = message
147
+ end
148
+ bot.event data
149
+
150
+ expect(_message).to be_a Message
151
+ expect(_message.text).to eq "bbq omg lol"
152
+ expect(_message.match[0]).to eq "omg"
153
+ end
154
+
155
+ it "binds various actions to events of type message" do
156
+ iterations = []
157
+ bot.match(/omg/i) do iterations << "first" end
158
+ bot.match(/omg/i) do iterations << "second" end
159
+ bot.event data
160
+
161
+ expect(iterations).to eq ["first", "second"]
162
+ end
163
+
164
+ it "passes the matched strings as parameters to block action" do
165
+ _lol, _bbq = nil
166
+ bot.match(/(bbq) omg (lol)/i) do |bbq, lol|
167
+ _lol, _bbq = lol, bbq
168
+ end
169
+ bot.event data
170
+
171
+ expect(_lol).to eq "lol"
172
+ expect(_bbq).to eq "bbq"
173
+ end
174
+ end
175
+
176
+ describe "#respond", :users do
177
+ let(:data) {{
178
+ "type" => "message",
179
+ "text" => "hey <@jabber>, omg me"
180
+ }}
181
+
182
+ it "binds actions for messages only when there is a mention (@bot)" do
183
+ expect { |b|
184
+ bot.respond(/omg me/, &b)
185
+ bot.event data
186
+ }.to yield_control
187
+ end
188
+
189
+ it "recognizes the id when it's mentioned" do
190
+ data["text"] = "hey <@666>: omg me"
191
+ expect { |b|
192
+ bot.respond(/omg me/, &b)
193
+ bot.event data
194
+ }.to yield_control
195
+ end
196
+
197
+ it "does not bind when regex matches but there is no mention" do
198
+ data["text"] = "hey <@other_bot>, omg me"
199
+
200
+ expect { |b|
201
+ bot.respond(/omg me/, &b)
202
+ bot.event data
203
+ }.to_not yield_control
204
+ end
205
+
206
+ it "ignores mentions from itself" do
207
+ data["user"] = "666"
208
+
209
+ expect { |b|
210
+ bot.respond(/omg me/, &b)
211
+ bot.event data
212
+ }.to_not yield_control
213
+ end
214
+
215
+ it "evals the block in the context of the bot" do
216
+ dsl = nil
217
+ bot.respond(/omg me/) { dsl = self }
218
+ bot.event data
219
+
220
+ expect(dsl.bot).to eq bot
221
+ end
222
+ end
223
+
224
+ context "removing binds for messages and responses", :session do
225
+ before do
226
+ start_session
227
+ end
228
+
229
+ describe "#no_message" do
230
+ let(:data) { {"type" => "message", "text" => "bbq omg lol"} }
231
+
232
+ it "removes a message based on the regex AND the block" do
233
+ permanent_executed = false
234
+ permanent_block = ->() { permanent_executed = true }
235
+ bot.hear(/omg/i, &permanent_block)
236
+
237
+ ephemeral_executed = false
238
+ ephemeral_block = ->() { ephemeral_executed = true }
239
+ bot.hear(/omg/i, &ephemeral_block)
240
+ bot.no_match(/omg/i, &ephemeral_block)
241
+
242
+ dsl.bot.event data
243
+
244
+ expect(permanent_executed).to eq true
245
+ expect(ephemeral_executed).to eq false
246
+ end
247
+
248
+ it "removes all binds for a specific regex" do
249
+ first = second = false
250
+ bot.hear(/omg/i) { first = true }
251
+ bot.hear(/omg/i) { second = true }
252
+ bot.no_match(/omg/i)
253
+
254
+ dsl.bot.event data
255
+
256
+ expect(first).to eq false
257
+ expect(second).to eq false
258
+ end
259
+ end
260
+
261
+ describe "#no_respond" do
262
+ let(:data) {{
263
+ "type" => "message",
264
+ "text" => "hey <@#{bot.name}>, omg me"
265
+ }}
266
+
267
+ it "removes a message based on the regex AND the block" do
268
+ permanent_executed = false
269
+ permanent_block = ->() { permanent_executed = true }
270
+ bot.respond(/omg/i, &permanent_block)
271
+
272
+ ephemeral_executed = false
273
+ ephemeral_block = ->() { ephemeral_executed = true }
274
+ bot.respond(/omg/i, &ephemeral_block)
275
+ bot.no_respond(/omg/i, &ephemeral_block)
276
+
277
+ dsl.bot.event data
278
+
279
+ expect(permanent_executed).to eq true
280
+ expect(ephemeral_executed).to eq false
281
+ end
282
+
283
+ it "removes all binds for a specific regex" do
284
+ first = second = false
285
+ bot.respond(/omg/i) { first = true }
286
+ bot.respond(/omg/i) { second = true }
287
+ bot.no_respond(/omg/i)
288
+
289
+ dsl.bot.event data
290
+
291
+ expect(first).to eq false
292
+ expect(second).to eq false
293
+ end
294
+ end
295
+ end
296
+
297
+ describe "#say", :users do
298
+ let(:data) {{
299
+ "type" => "message",
300
+ "text" => "hey <@jabber>, omg me",
301
+ "channel" => "omg"
302
+ }}
303
+
304
+ it "sends a string using the slack api to general (default) channel" do
305
+ expect(Slack.chat).to receive(:post_message).
306
+ with "something", channel: "general"
307
+ bot.say "something"
308
+ end
309
+
310
+ it "send a message to the channel specified by a current binded message" do
311
+ expect(Slack.chat).to receive(:post_message).
312
+ with "omg pugs!", channel: "omg"
313
+
314
+ bot.respond(/omg me/) { say "omg pugs!" }
315
+ bot.event data
316
+ end
317
+ end
318
+
319
+ describe "#im", :session, :users do
320
+ before do
321
+ start_session
322
+ end
323
+
324
+ let(:user_id) { "U4321" }
325
+ let(:data) {{
326
+ "type" => "message",
327
+ "text" => "<@#{bot.name}>: omg",
328
+ "user" => "U4321"
329
+ }}
330
+
331
+ it "sends a message in the back channel (particular, im...)" do
332
+ bot.respond(/omg/) { im "lol" }
333
+ expect(Boty::Slack.chat).to receive(:post_im).with "U4321", "lol"
334
+
335
+ dsl.bot.event data
336
+ end
337
+ end
338
+
339
+ describe "#brain", :users do
340
+ it "exposes a hash that lives while bot is alive. =)" do
341
+ bot.brain[:something] = "going on"
342
+ expect(bot.brain[:something]).to eq "going on"
343
+ end
344
+ end
345
+
346
+ context "loading script/**/*.rb files", :fakefs, :users do
347
+ let(:data) {{
348
+ "type" => "message",
349
+ "text" => "hey <@jabber>, pug me"
350
+ }}
351
+
352
+ before do
353
+ FileUtils.mkdir "script" unless Dir.exists? "script"
354
+ File.open "script/omg.rb", "w" do |f|
355
+ f.write <<-RUBY
356
+ respond(/pug me/i) do
357
+ say "omg"
358
+ end
359
+ RUBY
360
+ end
361
+ end
362
+
363
+ it "uses the logic in the script located at script/omg.rb" do
364
+ expect(bot).to receive(:say).with "omg"
365
+ bot.event data
366
+ end
367
+
368
+ context "describing commands", :fakefs, :users do
369
+ before do
370
+ File.open "script/omg.rb", "w" do |f|
371
+ f.write <<-RUBY
372
+ desc "pug me", "show some pretty random pug"
373
+ respond(/pug me/i) do
374
+ say "omg"
375
+ end
376
+
377
+ desc "just a description"
378
+ respond(/just desc/i) do
379
+ say "just description, raw command"
380
+ end
381
+
382
+ respond(/without desc/i) do
383
+ say "no desc, raw command"
384
+ end
385
+
386
+ respond(/without desc sensitive/) do
387
+ say "no desc, raw command"
388
+ end
389
+ RUBY
390
+ end
391
+ end
392
+
393
+ it "stores the description within command usage" do
394
+ expect(bot.know_how).to include({
395
+ "pug me" => "show some pretty random pug"
396
+ })
397
+ end
398
+
399
+ it "stores the description for a regex when no command usage is given" do
400
+ expect(bot.know_how).to include({
401
+ "/just desc/i" => "just a description"
402
+ })
403
+ end
404
+
405
+ it "presents the commands without description as regexes" do
406
+ expect(bot.know_how).to include({
407
+ "/without desc/i" => nil
408
+ })
409
+ end
410
+
411
+ it "knows when a regex is case sensitive" do
412
+ expect(bot.know_how).to include({
413
+ "/without desc sensitive/" => nil
414
+ })
415
+ end
416
+ end
417
+ end
418
+ end
419
+ end