boty 0.0.17.1 → 0.1.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +559 -54
  4. data/bin/bot +10 -13
  5. data/docs/images/readme-01-screen-integration.png +0 -0
  6. data/docs/images/readme-02-screen-integration.png +0 -0
  7. data/docs/images/readme-03-screen-integration.png +0 -0
  8. data/lib/boty/action.rb +1 -1
  9. data/lib/boty/bot.rb +46 -63
  10. data/lib/boty/dsl.rb +52 -0
  11. data/lib/boty/eventable.rb +41 -0
  12. data/lib/boty/http.rb +33 -0
  13. data/lib/boty/locale.rb +17 -4
  14. data/lib/boty/logger.rb +21 -4
  15. data/lib/boty/rspec.rb +2 -3
  16. data/lib/boty/script_loader.rb +1 -1
  17. data/lib/boty/session.rb +21 -17
  18. data/lib/boty/slack/chat.rb +2 -2
  19. data/lib/boty/slack/message.rb +29 -0
  20. data/lib/boty/slack/users.rb +13 -0
  21. data/lib/boty/slack.rb +6 -0
  22. data/lib/boty/version.rb +1 -1
  23. data/lib/boty.rb +4 -4
  24. data/spec/boty/bot_spec.rb +105 -174
  25. data/spec/boty/dsl_spec.rb +125 -0
  26. data/spec/boty/http_spec.rb +5 -0
  27. data/spec/boty/logger_spec.rb +33 -0
  28. data/spec/boty/rspec_spec.rb +1 -1
  29. data/spec/boty/script_loader_spec.rb +27 -0
  30. data/spec/boty/session_spec.rb +9 -11
  31. data/spec/boty/slack/message_spec.rb +34 -0
  32. data/spec/boty/slack/users_spec.rb +41 -15
  33. data/spec/happy_path_spec.rb +22 -12
  34. data/spec/script/i18n_spec.rb +10 -4
  35. data/spec/script/pug_spec.rb +1 -1
  36. data/spec/spec_helper.rb +5 -2
  37. data/spec/support/logger_support.rb +20 -0
  38. data/spec/support/session_support.rb +2 -2
  39. data/template/project/bot.tt +4 -13
  40. data/template/project/script/ping.rb +3 -3
  41. metadata +14 -5
  42. data/lib/boty/message.rb +0 -27
  43. data/lib/boty/script_dsl.rb +0 -80
  44. data/spec/boty/message_spec.rb +0 -32
data/README.md CHANGED
@@ -3,18 +3,128 @@
3
3
 
4
4
  `Boty` is a utilitary to create bots (at this time, specificaly Slack bots).
5
5
 
6
- A bot is this context is a ordinary ruby application, that knows how to receive
7
- messages. Boty will give you a nice way to bind your own logic to specific
8
- messages of your own interest.
6
+ A bot in the context of this gem is an ordinary ruby application that knows how
7
+ to connect and receive messages in a Slack company room. `Boty` will give you a
8
+ nice api to bind your own logic to specific messages of your interest.
9
9
 
10
- ## Slack Bot Integration<a id="integration" />
10
+ ## Usage TL;DR version:<a id="tldr" />
11
+
12
+ - create [new slack bot integration](#integration) (http://[company].slack.com/services)
13
+ - `$ gem install boty`
14
+ - `$ boty new jeeba` (where `jeeba` it's a name that you will choose for the bot in the integration step)
15
+ - type your company name (the one used in the slack url: http://[company].slack.com)
16
+ - type the api key created on the [bot integration step](#integration)
17
+ - `$ cd jeeba` (the dir created after the name passed as parameter to the `new` command
18
+ - ./bot
19
+
20
+ Your bot should be up and running, which means: connected to your Slack room
21
+ under the name configured in the Slack Bot integration.
22
+
23
+ ### Custom scripts
24
+
25
+ On the `script` dir of your bot there is a example `ping` script. But you will
26
+ want to create your own scripts:
27
+
28
+ - stop the bot (if it's already running)
29
+ - add a new file named `hello.rb` into the `script` dir
30
+ - add a `command` to made it available via bot mention (`@jeeba` in my case)
31
+ - add a `hear` instruction so the `bot` listen to any message with the pattern configured
32
+ - use the method `#say` to instruct the `bot` to send a message in the channel
33
+ - use the method `#im` to instruct the `bot` to send a private message
34
+
35
+ ```ruby
36
+ # script/hello.rb
37
+ command "hi" do
38
+ say "hi #{user.name}"
39
+ end
40
+
41
+ command "im me" do
42
+ im "want something?"
43
+ end
44
+
45
+ hear "say something" do
46
+ say "something"
47
+ end
48
+ ```
49
+
50
+ - run the bot `./bot`
51
+ - on the slack room, issue the commands and send messages:
52
+
53
+ ```
54
+ valeriano 12:14 AM
55
+ @jeeba: hi
56
+
57
+ jeeba BOT 12:14 AM
58
+ hi valeriano
59
+
60
+ valeriano 12:14 AM
61
+ @jeeba: im me
62
+
63
+ # a private message will arrive:
64
+ jeeba BOT 12:14 AM
65
+ want something?
66
+
67
+ # back to the general channel:
68
+ valeriano 12:16 AM
69
+ say something
70
+
71
+ jeeba BOT 12:16 AM
72
+ something
73
+ ```
74
+
75
+ #### Regexes
76
+
77
+ There is an api to capture matches when regexes are used on `hear` and `command`
78
+ configurations:
79
+
80
+ - stop the bot (if it's already running)
81
+ - add a new file named `math.rb` into the `script` dir
82
+ - add the `command` `/sum (\d+) (\d+)/`:
83
+
84
+ ```ruby
85
+ # script/math.rb
86
+ command(/sum (\d+) (\d+)/) do |augend, addend|
87
+ say "(#{augend} plus #{addend}) = #{augend.to_i + addend.to_i}"
88
+ end
89
+ ```
90
+
91
+ - run the bot: `./bot`
92
+ - on the slack room, issue the command:
93
+
94
+ ```
95
+ valeriano 12:30 AM
96
+ @jabberu: sum 100 200
97
+
98
+ jabberu BOT 12:30 AM
99
+ (100 plus 200) = 300
100
+ ```
101
+
102
+ And this is pretty much it! :tada:
103
+
104
+ If you need more details about any of the features in `Boty`, you probably will
105
+ find it in this README, on the sections that follow.
106
+ If you don't find what you need, please contact us or even create an issue. Our
107
+ goals with this project are to make it usefull and easy to use, check the
108
+ [contributing](#contributing) info for more.
109
+
110
+ ## Usage (long version)<a id="usage" />
111
+
112
+ Now you will learn how to create a custom bot application for your needs, how to
113
+ configure it to allow the bot say stuff in your slack channels and finally, will
114
+ see how to run the bot properly.
115
+
116
+ ### Slack Bot Integration<a id="integration" />
11
117
 
12
118
  The first thing to do is to create a Slack Bot integration.
13
119
  Go to `http://[your-company-name].slack.com/services` to add a new one.
14
120
  In the process an `API Token` will be generated. That will be used in the [next
15
121
  step](#installation).
16
122
 
17
- ## Installation<a id="installation" />
123
+ - ![](docs/images/readme-01-screen-integration.png)
124
+ - ![](docs/images/readme-02-screen-integration.png)
125
+ - ![](docs/images/readme-03-screen-integration.png)
126
+
127
+ ### Installation<a id="installation" />
18
128
 
19
129
  Now you can install `Boty`:
20
130
 
@@ -26,15 +136,9 @@ This will give you an executable `boty`, which ships with a command `help` so
26
136
  you can know all the stuff that it can do. But the main one is to [create your
27
137
  new shiny bot](#usage).
28
138
 
29
- ## Usage<a id="usage" />
30
-
31
- In this section you will learn how to create a custom bot application for your
32
- needs, how to configure it to allow the bot say stuff in your slack channels and
33
- finally, will see how to run the bot properly.
34
-
35
139
  ### Creating a new bot
36
140
 
37
- To create a new bot, execute:
141
+ To create a new bot, execute this on your terminal:
38
142
 
39
143
  ```sh
40
144
  $ boty new jeeba
@@ -45,7 +149,7 @@ integration](#integration).
45
149
 
46
150
  The command will create a new directory after your bot name (`jeeba` in my
47
151
  example). Your _bot application_ will live in this directory. Feel free to check
48
- the directory, it will have some ruby files, some directories... it's just an
152
+ the contents, it will have some ruby files, some directories... it's just an
49
153
  ordinary ruby application.
50
154
 
51
155
  But first, let's see something about the [configurations](#configuration).
@@ -62,7 +166,360 @@ recently created dir.
62
166
 
63
167
  If you want to understand how this configuration is managed locally, you can
64
168
  check de [`Dotenv` gem documentation](https://github.com/bkeepers/dotenv), but
65
- you don't need to worry about it.
169
+ you don't need to worry about it, if you don't want.
170
+
171
+ Now, let's create some commands and message listeners on your bot.
172
+
173
+ ### Creating a Session (and the `bot` file).
174
+
175
+ Since you already have a `Boty` project configured with your company name and
176
+ api key, you should be able to start a new session for your bot by calling
177
+ `Session#start`.
178
+
179
+ This is a "blocking" call. It will hang to allow the bot to listen for messages
180
+ and send them. You can pass a block to it in order to configure your bot
181
+ preferences, or knowledge if you prefer =).
182
+
183
+ The block passed to `#start` will be _yielded_ in the scope of a `Bot`. In other
184
+ words, you can call any bot method inside this context. Note that at this time,
185
+ you can consider your `Bot` already connected to the Slack room.
186
+
187
+ ```ruby
188
+ session = Boty::Session.new
189
+ session.start do
190
+ # configure your bot here
191
+ end
192
+ ```
193
+
194
+ In your project there is a `bot` executable file. This file already creates a
195
+ `Session` with a minimum bot configuration: a listener with the bot name. Which
196
+ means that any message with the bot name will trigger the behavior in this
197
+ configuration.
198
+
199
+ This is just to save you time. You could start a Session by hand, if you wanted,
200
+ so feel free to check the code on this file and change it at will =).
201
+
202
+ Now it's time to better understand what is a listener, a command and how to use
203
+ regexes to configure the patterns that trigger the bot.
204
+
205
+ #### Command - a bot mention followed by a instruction pattern<a name="command" />
206
+
207
+ A `command` can be understood as a direct instruction to the bot. To be issued
208
+ the bot should be mentioned by the message using the default Slack mention
209
+ "operator" *`@`*.
210
+
211
+ To create a command, call the method `#command` on the bot passed as parameter
212
+ in the `Session#start` method. The `command` method receive the pattern for the
213
+ command, and the _block_ that should be executed when the command is issued.
214
+
215
+ See how to teach your bot to flip tables like a pro.
216
+
217
+ ```ruby
218
+ session = Boty::Session.new
219
+ session.start do
220
+ # ...
221
+
222
+ command("flip") do
223
+ say "HEY! (╯°□°)╯︵ ┻━┻"
224
+ end
225
+ end
226
+ ```
227
+
228
+ Now, to see the result, with the bot running, send in any channel where the bot
229
+ is (the #general is the default):
230
+
231
+ @jeeba: flip
232
+
233
+ (remember: `jeeba` is the name that I choose for my bot, you should use the
234
+ correct name here).
235
+
236
+ The previous command will result in the following response:
237
+
238
+ jeeba BOT 2:25 AM
239
+ HEY! (╯°□°)╯︵ ┻━┻
240
+
241
+ There is an alternative method to create a `command`: `bot#response`. Use the
242
+ one more appealing to you, they are the same.
243
+
244
+ The `bot#say` method used in this example is [better explained here](#bot_say).
245
+
246
+ Wrapping up:
247
+
248
+ - a command is a pattern triggered by a bot mention
249
+ - you can configure your bot patterns in the block passed to `Session#start`
250
+
251
+ Now, let's see how a listener works.
252
+
253
+ #### Listener - a message pattern that the bot should respond to<a name="listenter" />
254
+
255
+ A listener is used when the bot is interested in ANY messages containing some
256
+ pattern. Note that a listener will not be triggered only when there is a bot
257
+ mention, but anytime a message containing the pattern is sent on a channel where
258
+ the bot is.
259
+
260
+ Simple enough, let's get to the code:
261
+
262
+ ```ruby
263
+ session = Boty::Session.new
264
+ session.start do
265
+ # ...
266
+
267
+ hear("what's going on here?") do
268
+ say "I don't know. But something is always wrong. :scream:"
269
+ end
270
+ end
271
+ ```
272
+
273
+ This configuration says that anytime a message containing the string "what's
274
+ going on here?" is sent, the bot will respond. So a valid test could be send the
275
+ following message in the _#general_ channel:
276
+
277
+ valeriano 3:57 AM
278
+ OMG guys, what's going on here?
279
+
280
+ And the response will be, as expected:
281
+
282
+ jeeba BOT 3:57 AM
283
+ I don't know. But something is always wrong. :scream:
284
+
285
+ Wrapping up:
286
+
287
+ - A listener is triggered for any message containing the pattern
288
+ - A listener don't need a bot mention, so careful: the range of this config is wide
289
+
290
+ Before we start to study the "script" way of configuring `command` and
291
+ `listener` binds, let's see how we can use ruby regexps to capture message
292
+ parameters.
293
+
294
+ ##### Regexes - a pattern that allow capture parameters within a message<a name="regexes" />
295
+
296
+ What is a bot if it can't annoy people when we want it to? So let's teach our
297
+ bot to send private messages to people in the Slack room.
298
+
299
+ Let's create an `im` _command_ that will be capable of extract the person to
300
+ whom we want to send a message, and the message that we want the bot send. Our
301
+ bot will be capable of understand the following instruction:
302
+
303
+ valeriano 2:44 PM
304
+ @jeeba: im julian with omg! lol! bbq!
305
+
306
+ The _command_ configuration can be like this:
307
+
308
+ ```ruby
309
+ command /im (\w+) with (.*)/ do |person, message|
310
+ im message, to: person
311
+ end
312
+ ```
313
+
314
+ The regex matched portions will be passed as parameter to the block given to
315
+ _command_.
316
+
317
+ And this is it! :tada:
318
+
319
+ ### Adding custom scripts<a name="custom_scripts" />
320
+
321
+ Now you already know what are [listeners](#listeners) and
322
+ [commands](#command). It's time to know another way to create those "binders",
323
+ it's what we call `scripts`.
324
+
325
+ Any ruby file available on `scripts` will be loaded when a `Session` starts.
326
+ Your bot ships with an example script named `script/ping.rb`, with a very simple
327
+ example of what you can do. But let's create a new script from scratch.
328
+
329
+ Create a new file `script/flip.rb` on your bot directory. Any method available
330
+ in a bot will be available in this file, which means you can use `command`,
331
+ `hear`, `im`, `say`, `message`, etc.
332
+
333
+ Let's code:
334
+
335
+ ```ruby
336
+ # script/flip.rb
337
+ command "flip" do
338
+ say "(╯°□°)╯︵ ┻━┻"
339
+ end
340
+ ```
341
+
342
+ And this is pretty much it. When your bot runs, it will be able to perform the
343
+ command `flip`:
344
+
345
+ valeriano 3:36 PM
346
+ @jeeba: flip
347
+
348
+ jeeba BOT 3:36 PM
349
+ (╯°□°)╯︵ ┻━┻
350
+
351
+ So feel free to customize the `bot` file or create your own scripts. What please
352
+ you more is what you should use.
353
+
354
+ ### DSL for bot scripting<a name="bot_dsl" />
355
+
356
+ In this section you will see all the methods available to configure your `bot`.
357
+
358
+ #### `bot#say` - Sending public messages on Slack channels<a name="bot_say" />
359
+
360
+ Use `#say` when the bot should send a message in the channel that triggered the
361
+ configuration block:
362
+
363
+ ```ruby
364
+ command "flip" do
365
+ say "(╯°□°)╯︵ ┻━┻"
366
+ end
367
+ ```
368
+
369
+ If the bot wants to start a conversation, or even just say something in a
370
+ channel without have received a message (via `#hear` or `#command`), just call
371
+ `#say` inside a script.
372
+
373
+ ```ruby
374
+ say "ready to turn tables", channel: "#general"
375
+
376
+ command "flip" do
377
+ say "(╯°□°)╯︵ ┻━┻"
378
+ end
379
+ ```
380
+
381
+ If a channel isn't passed to `#say` it will defaults to `"#general"`. You can
382
+ use any [Slack RTM postMessage](https://api.slack.com/methods/chat.postMessage)
383
+ parameter when calling `#say`.
384
+
385
+ #### `bot#im`<a name="bot_im" />
386
+
387
+ Bots can send private messages. Use the `#im` method:
388
+
389
+ ```ruby
390
+ command "who am I?" do
391
+ im "you are #{user.name}!"
392
+ end
393
+ ```
394
+
395
+ In the previous example, the private message will be sent to the user that
396
+ issued the command, this is a default. If you want the bot to send a message to
397
+ a specific user, just indicate the user name via the `to` option:
398
+
399
+ ```ruby
400
+ command "annoys julian" do
401
+ im "Loren Ipsum, Julian boy!", to: "julian"
402
+ end
403
+ ```
404
+
405
+ #### `bot#message`<a name="bot_message" />
406
+
407
+ The message that triggered a block is made available in the block's scope in the
408
+ method `#message`:
409
+
410
+ ```ruby
411
+ command "what did you say?" do
412
+ say "Well: #{message.text}"
413
+ end
414
+ ```
415
+
416
+ Execute the previous command will be as follows:
417
+
418
+ valeriano 12:07 AM
419
+ @jeeba: what did you say?
420
+
421
+ jeeba BOT 12:07 AM
422
+ Well: @jeeba: what did you say?
423
+
424
+ Note that the `#text` returns the raw message that triggered the handler,
425
+ including the bot mention itself.
426
+
427
+ #### `bot#user`<a name="bot_user" />
428
+
429
+ If the bot need to access the data about the user that send the message that
430
+ triggered the handler, use the `#user` method.
431
+
432
+ Let me borrow an already used example:
433
+
434
+
435
+ ```ruby
436
+ command "who am I?" do
437
+ im "you are #{user.name}!"
438
+ end
439
+ ```
440
+
441
+ #### `bot#http`<a name="bot_http" />
442
+
443
+ There is an utilitary method `#http` available on the handler block. This guy is
444
+ useful to make, well... http requests. It supports all http verbs and return a
445
+ `Hash` if the http response contains a `"application/json"` _Content-Type_
446
+ header, or else the raw body.
447
+
448
+ Let's create a `command` that fetches a [xkcd](http://xkcd.com/) strip for us:
449
+
450
+ ```ruby
451
+ command /xkcd(\s\d+)?/ do |number|
452
+ number = number ? number.strip : "1"
453
+ xkcd = http.get "http://xkcd.com/#{number}/info.0.json"
454
+ say "#{xkcd["alt"]}\n<#{xkcd["img"]}>"
455
+ end
456
+ ```
457
+
458
+ To execute this command:
459
+
460
+ valeriano 12:40 AM
461
+ @jabberu: xkcd 2
462
+
463
+ The strip number 2 of [xkcd](http://xkcd.com/) will be brought to the room. If
464
+ we don't pass a number parameter, the strip number 1 will be assumed as default.
465
+
466
+ If something goes wrong with the request, you can use the `http#response` method
467
+ to access the inner response object. It'll be a
468
+ [faraday](https://github.com/lostisland/faraday) http response object.
469
+
470
+ #### `bot#desc` - Describing your bindings<a name="bot_desc" />
471
+
472
+ A bot list all the commands and message handlers that it knows in the moment. If
473
+ you want to give a nice description and/or a usage tip on command you can use
474
+ the `desc` method.
475
+
476
+ Given that your bot has the following script:
477
+
478
+ ```ruby
479
+ desc "pug me", "Send some nice pug in the channel."
480
+ respond(/pug me/i) do
481
+ # ...
482
+ end
483
+ ```
484
+
485
+ The follow text will be part of the response for a `@bot: knows` command:
486
+
487
+ pug me: Send some nice pug in the channel.
488
+
489
+ You can use just the description if you want. In this case the `regex` itself
490
+ will be used as the command name.
491
+
492
+ ```ruby
493
+ desc "Send some nice pug in the channel."
494
+ respond(/pug me/i) do
495
+ # ...
496
+ end
497
+ ```
498
+
499
+ valeriano 2:25PM
500
+ @bot: knows
501
+
502
+ bot 2:25PM
503
+ knows: List all the commands known by this bot.
504
+ /pug me/i: Send some nice pug in the channel.
505
+
506
+ We strongly recommend that you describe all of your scripts. But if you don't,
507
+ the bot will be capable of tell you what `regexes` are binded to it:
508
+
509
+ valeriano 2:47PM
510
+ @jabberu: knows
511
+
512
+ jabberu 2:47PM
513
+ knows: List all the commands known by this bot.
514
+ /pug me/i
515
+ /jabberu, are you there\?/i
516
+
517
+ #### Testing your own scripts
518
+
519
+ **todo: document**
520
+
521
+ For now, check the `spec/script/ping_spec.rb` and follow it's leads.
522
+
66
523
 
67
524
  ### Running locally<a id="running" />
68
525
 
@@ -125,77 +582,125 @@ On the tab _Resources_, find a line with the information:
125
582
 
126
583
  Turn on this resource. And done, your bot is up and running!
127
584
 
585
+ ### Using the logger
128
586
 
129
- ## Adding custom scripts
587
+ `Boty` ships with a builtin logger that can be used in your own scripts. It is
588
+ made available via `#logger`.
589
+ This will return a instance of a [Ruby Logger](http://ruby-doc.org/stdlib-2.2.3/libdoc/logger/rdoc/Logger.html).
130
590
 
131
- **todo: document**
591
+ Note that the default logger implementation will write to the `STDOUT` .Let's
592
+ see a usage example:
132
593
 
133
- For now, check the `script/ping.rb` and follow it's leads.
594
+ ```ruby
595
+ session.start do
596
+ command(/hello/i) do
597
+ logger.debug "saying hello"
598
+ say "hello there."
599
+ end
600
+ end
601
+ ```
134
602
 
135
- ### Describing script usage
603
+ By default the logger will write on the standard output, the previous command,
604
+ when triggered, will produce the following log line:
136
605
 
137
- A bot list all the commands and message handlers that it knows in the moment. If
138
- you want to give a nice description and/or a usage tip on command you can use
139
- the `desc` method.
606
+ D, [2015-12-11T00:13:28.712380 #40369] DEBUG -- : saying hello
140
607
 
141
- Given that your bot has the following script:
608
+ Of course, if you need to write to a file, instead of the STDOUT, just change
609
+ the adapter for your logger.
610
+
611
+ #### Log into files (instead of STDOUT)
612
+
613
+ Before start your bot session, configure the file log:
142
614
 
143
615
  ```ruby
144
- desc "pug me", "Send some nice pug in the channel."
145
- respond(/pug me/i) do
146
- # ...
147
- end
616
+ Boty::Logger.adapter = Logger.new("log/output.log")
148
617
  ```
149
618
 
150
- The follow text will be part of the response for a `@bot: knows` command:
619
+ And this is all you need! :tada:
151
620
 
152
- pug me: Send some nice pug in the channel.
621
+ #### Logger adapters
153
622
 
154
- You can use just the description if you want. In this case the `regex` itself
155
- will be used as the command name.
623
+ There is an adapter included on `Boty` that can be used by you and is also a
624
+ good example of how to create a custom logger adapter for `Boty`.
625
+
626
+ Supose that you want to write to a file and still send the logs to the `STDOUT`.
627
+ You can use the `Multi` adapter like this:
156
628
 
157
629
  ```ruby
158
- desc "Send some nice pug in the channel."
159
- respond(/pug me/i) do
160
- # ...
630
+ Boty::Logger.adapter = Boty::Logger::Multi.new([
631
+ Logger.new(STDOUT),
632
+ Logger.new("log/output.log")
633
+ ])
634
+ ```
635
+
636
+ And this is it. Now when you call `logger.debug "some message"` from your bot,
637
+ this log line will be writen to the `"log/output.log"` file and also in the
638
+ `STDOUT`.
639
+
640
+ You can write you own log adapter if you want. The `Multi` adapter
641
+ implementation is fairly simple. Let's use it as an example of how to write your
642
+ own adapter.
643
+
644
+ You can extend the ruby _Logger_ class and worry yourself on write the `#add`
645
+ overrite:
646
+
647
+ ```ruby
648
+ class Multi < ::Logger
649
+ def initialize(adapters)
650
+ @adapters = adapters
651
+ end
652
+
653
+ def add(*args, &block)
654
+ @adapters.each do |adapter|
655
+ adapter.add(*args, &block)
656
+ end
657
+ end
161
658
  end
162
659
  ```
163
660
 
164
- valeriano 2:25PM
165
- @bot: knows
661
+ The add method is called internaly by _Logger_ and has all the information that
662
+ the auxiliary methods like `#debug`, `#info` etc received when called.
166
663
 
167
- bot 2:25PM
168
- knows: List all the commands known by this bot.
169
- /pug me/i: Send some nice pug in the channel.
664
+ The _Multi_ adapter implementation just delegate this call to the underlying
665
+ adapters passed as parameters for the constructor.
170
666
 
171
- We strongly recommend that you describe all of your scripts. But if you don't,
172
- the bot will be capable of tell you what `regexes` are binded to it:
667
+ For more information on the `#add` parameters, [check the ruby doc](http://ruby-doc.org/stdlib-2.1.0/libdoc/logger/rdoc/Logger.html#method-i-add).
173
668
 
174
- valeriano 2:47PM
175
- @jabberu: knows
669
+ _Multi_ also allows you to change the level for all the underlying adapters at
670
+ once, the `#level=` overrite implementation is like this:
176
671
 
177
- jabberu 2:47PM
178
- knows: List all the commands known by this bot.
179
- /pug me/i
180
- /jabberu, are you there\?/i
672
+ ```ruby
673
+ def level=(level)
674
+ @adapters.each do |adapter|
675
+ adapter.level = level
676
+ end
677
+ end
678
+ ```
181
679
 
182
- ### Testing your own scripts
680
+ ### I18n
183
681
 
184
682
  **todo: document**
185
683
 
186
- For now, check the `spec/script/ping_spec.rb` and follow it's leads.
187
-
188
684
  ## Development
189
685
 
190
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
686
+ After checking out the repo, run `bin/setup` to install dependencies. You can
687
+ also run `bin/console` for an interactive prompt that will allow you to
688
+ experiment.
689
+
690
+ To install this gem onto your local machine, run `bundle exec rake install`.
191
691
 
192
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
692
+ ### The local ./bin/bot
193
693
 
194
- ## Contributing
694
+ ### Code guidelines
195
695
 
196
- Bug reports and pull requests are welcome on GitHub at https://github.com/ricardovaleriano/boty. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
696
+ ## Contributing<a name="contributing" />
197
697
 
698
+ Bug reports and pull requests are very welcome on GitHub at
699
+ https://github.com/ricardovaleriano/boty. This project is intended to be a safe,
700
+ welcoming space for collaboration, and contributors are expected to adhere to
701
+ the [Contributor Covenant](contributor-covenant.org) code of conduct.
198
702
 
199
703
  ## License
200
704
 
201
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
705
+ The gem is available as open source under the terms of the
706
+ [MIT License](http://opensource.org/licenses/MIT).