grinch 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/LICENSE +22 -0
  4. data/README.md +180 -0
  5. data/docs/bot_options.md +454 -0
  6. data/docs/changes.md +541 -0
  7. data/docs/common_mistakes.md +60 -0
  8. data/docs/common_tasks.md +57 -0
  9. data/docs/encodings.md +69 -0
  10. data/docs/events.md +273 -0
  11. data/docs/getting_started.md +184 -0
  12. data/docs/logging.md +90 -0
  13. data/docs/migrating.md +267 -0
  14. data/docs/plugins.md +4 -0
  15. data/docs/readme.md +20 -0
  16. data/examples/basic/autovoice.rb +32 -0
  17. data/examples/basic/google.rb +35 -0
  18. data/examples/basic/hello.rb +15 -0
  19. data/examples/basic/join_part.rb +34 -0
  20. data/examples/basic/memo.rb +39 -0
  21. data/examples/basic/msg.rb +16 -0
  22. data/examples/basic/seen.rb +36 -0
  23. data/examples/basic/urban_dict.rb +35 -0
  24. data/examples/basic/url_shorten.rb +35 -0
  25. data/examples/plugins/autovoice.rb +37 -0
  26. data/examples/plugins/custom_prefix.rb +23 -0
  27. data/examples/plugins/dice_roll.rb +38 -0
  28. data/examples/plugins/google.rb +36 -0
  29. data/examples/plugins/hello.rb +22 -0
  30. data/examples/plugins/hooks.rb +36 -0
  31. data/examples/plugins/join_part.rb +42 -0
  32. data/examples/plugins/lambdas.rb +35 -0
  33. data/examples/plugins/last_nick.rb +24 -0
  34. data/examples/plugins/msg.rb +22 -0
  35. data/examples/plugins/multiple_matches.rb +32 -0
  36. data/examples/plugins/own_events.rb +37 -0
  37. data/examples/plugins/seen.rb +45 -0
  38. data/examples/plugins/timer.rb +22 -0
  39. data/examples/plugins/url_shorten.rb +33 -0
  40. data/lib/cinch.rb +5 -0
  41. data/lib/cinch/ban.rb +50 -0
  42. data/lib/cinch/bot.rb +479 -0
  43. data/lib/cinch/cached_list.rb +19 -0
  44. data/lib/cinch/callback.rb +20 -0
  45. data/lib/cinch/channel.rb +463 -0
  46. data/lib/cinch/channel_list.rb +29 -0
  47. data/lib/cinch/configuration.rb +73 -0
  48. data/lib/cinch/configuration/bot.rb +48 -0
  49. data/lib/cinch/configuration/dcc.rb +16 -0
  50. data/lib/cinch/configuration/plugins.rb +41 -0
  51. data/lib/cinch/configuration/sasl.rb +19 -0
  52. data/lib/cinch/configuration/ssl.rb +19 -0
  53. data/lib/cinch/configuration/timeouts.rb +14 -0
  54. data/lib/cinch/constants.rb +533 -0
  55. data/lib/cinch/dcc.rb +12 -0
  56. data/lib/cinch/dcc/dccable_object.rb +37 -0
  57. data/lib/cinch/dcc/incoming.rb +1 -0
  58. data/lib/cinch/dcc/incoming/send.rb +147 -0
  59. data/lib/cinch/dcc/outgoing.rb +1 -0
  60. data/lib/cinch/dcc/outgoing/send.rb +122 -0
  61. data/lib/cinch/exceptions.rb +46 -0
  62. data/lib/cinch/formatting.rb +125 -0
  63. data/lib/cinch/handler.rb +118 -0
  64. data/lib/cinch/handler_list.rb +90 -0
  65. data/lib/cinch/helpers.rb +231 -0
  66. data/lib/cinch/irc.rb +924 -0
  67. data/lib/cinch/isupport.rb +98 -0
  68. data/lib/cinch/log_filter.rb +21 -0
  69. data/lib/cinch/logger.rb +168 -0
  70. data/lib/cinch/logger/formatted_logger.rb +97 -0
  71. data/lib/cinch/logger/zcbot_logger.rb +22 -0
  72. data/lib/cinch/logger_list.rb +85 -0
  73. data/lib/cinch/mask.rb +69 -0
  74. data/lib/cinch/message.rb +392 -0
  75. data/lib/cinch/message_queue.rb +107 -0
  76. data/lib/cinch/mode_parser.rb +76 -0
  77. data/lib/cinch/network.rb +104 -0
  78. data/lib/cinch/open_ended_queue.rb +26 -0
  79. data/lib/cinch/pattern.rb +65 -0
  80. data/lib/cinch/plugin.rb +515 -0
  81. data/lib/cinch/plugin_list.rb +38 -0
  82. data/lib/cinch/rubyext/float.rb +3 -0
  83. data/lib/cinch/rubyext/module.rb +26 -0
  84. data/lib/cinch/rubyext/string.rb +33 -0
  85. data/lib/cinch/sasl.rb +34 -0
  86. data/lib/cinch/sasl/dh_blowfish.rb +71 -0
  87. data/lib/cinch/sasl/diffie_hellman.rb +47 -0
  88. data/lib/cinch/sasl/mechanism.rb +6 -0
  89. data/lib/cinch/sasl/plain.rb +26 -0
  90. data/lib/cinch/syncable.rb +83 -0
  91. data/lib/cinch/target.rb +199 -0
  92. data/lib/cinch/timer.rb +145 -0
  93. data/lib/cinch/user.rb +488 -0
  94. data/lib/cinch/user_list.rb +87 -0
  95. data/lib/cinch/utilities/deprecation.rb +16 -0
  96. data/lib/cinch/utilities/encoding.rb +37 -0
  97. data/lib/cinch/utilities/kernel.rb +13 -0
  98. data/lib/cinch/version.rb +4 -0
  99. metadata +140 -0
@@ -0,0 +1,184 @@
1
+ # @title Getting Started
2
+ # @markup kramdown
3
+
4
+ # Getting Started
5
+
6
+ This short guide will show you how to easily and quickly write your
7
+ own IRC bot with Cinch.
8
+
9
+ # What Cinch really is
10
+
11
+ First and foremost, it is important to understand that Cinch is more
12
+ of an API for IRC access than a full-blown bot framework like Autumn
13
+ or Rbot.
14
+
15
+ There will be no enforced directory structures, no magical places from
16
+ which plugins will be loaded and no obscure, "fancy" names. Plugins
17
+ will be plugins and not "leaves".
18
+
19
+ This, however, does not mean that Cinch requires you to be familiar
20
+ with the internals of the IRC protocol. Quite the opposite: A very
21
+ high-level abstraction is provided, allowing things such as
22
+
23
+ Channel("#cinch").users.each do |user, modes|
24
+ user.send "I am watching you!"
25
+ end
26
+
27
+ to work.
28
+
29
+
30
+ Furthermore, the API has been designed in a way that it sticks true to
31
+ the way Ruby looks and behaves. Plugins are normal classes that mix-in
32
+ a module, functions of the bot are implemented as normal methods and
33
+ so on.
34
+
35
+ # Hello, World
36
+
37
+ The following will describe one of the most basic IRC bots you can
38
+ write in Cinch: One that joins a specific channel and responds to
39
+ "hello" by saying "Hello, World".
40
+
41
+
42
+ require "cinch"
43
+
44
+ bot = Cinch::Bot.new do
45
+ configure do |c|
46
+ c.server = "irc.freenode.net"
47
+ c.channels = ["#cinch-bots"]
48
+ end
49
+
50
+ on :message, "hello" do |m|
51
+ m.reply "Hello, World"
52
+ end
53
+ end
54
+
55
+ bot.start
56
+
57
+
58
+ Note that this is the entire file and all you need for the basic bot
59
+ to work. Save the above example to a file and run it with Ruby.
60
+
61
+ ## In Detail
62
+
63
+ So, what are we actually doing in that short piece of code? First, we
64
+ create a new bot in line 3 and conigure it in lines 4–6 –
65
+ {Cinch::Bot#configure configure} simply yields the configuration
66
+ object, which allows you to configure various things. In this example,
67
+ we only set which server to connect to and which channel to join.
68
+ Another often-used option is the nickname of the bot
69
+ ({file:docs/bot_options.md#nick c.nick}). For an overview of all
70
+ available options, see {file:docs/bot_options.md the list of options}.
71
+
72
+ Following, we define a basic message handler. In its simplest form,
73
+ {Cinch::Bot#on on} expects two arguments: The kind of message to react
74
+ to and the pattern to match. In this case, the kind is
75
+ {file:docs/events.md#message :message}, which means that the bot will
76
+ respond to both messages in channels as well as messages sent directly
77
+ to the bot. For a list of all kinds, called events, see
78
+ {file:docs/events.md the list of events}.
79
+
80
+ For the pattern we use a basic string, which means that the message
81
+ has to be exactly that string. It mustn't have anything before or
82
+ after the word "hello". Another way of using {Cinch::Bot#on on} is by using
83
+ regular expressions:
84
+
85
+ on :message, /^\d{4}$/ do |m|
86
+ # ...
87
+ end
88
+
89
+ will match all messages that consist of exactly four digits and
90
+ nothing else.
91
+
92
+ Whenever a message matches the handler we just defined, the block we
93
+ provided will be called, with the message object, and optionally
94
+ capture groups of the regular expression, passed to it.
95
+
96
+ The message object allows insight into the nature of the message, i.e.
97
+ who sent it, when was it sent etc, and also provides the
98
+ {Cinch::Message#reply reply} method, an easy way of responding to a
99
+ message. If the message was sent to a channel, {Cinch::Message#reply
100
+ reply} will respond to the channel, otherwise directly to the user.
101
+
102
+ We then use exactly that {Cinch::Message#reply reply} method to send back "Hello, World"
103
+ whenever someone says "hello".
104
+
105
+ That's it!
106
+
107
+ # on-handlers vs. plugins
108
+
109
+ Using `on` might be nice and handy for writing simple bots, but if you
110
+ want to write a more complex bot, providing lots of different features
111
+ to its users, then using plugins might be a better solution.
112
+
113
+ But what are plugins, exactly? Technically, plugins are implemented as
114
+ Ruby classes that mix-in a {Cinch::Plugin specific module} to get
115
+ access to various methods.
116
+
117
+ To have an example to work with, we'll convert our "Hello, World" bot
118
+ to using the plugin API:
119
+
120
+ require "cinch"
121
+
122
+ class HelloWorld
123
+ include Cinch::Plugin
124
+
125
+ match "hello"
126
+ def execute(m)
127
+ m.reply "Hello, World"
128
+ end
129
+ end
130
+
131
+ bot = Cinch::Bot.new do
132
+ configure do |c|
133
+ c.server = "irc.freenode.net"
134
+ c.channels = ["#cinch-bots"]
135
+ c.plugins.plugins = [HelloWorld]
136
+ end
137
+ end
138
+
139
+ bot.start
140
+
141
+ The first thing to notice is that we wrote a new class called
142
+ `HelloWorld`, and that we use {Cinch::Plugin::ClassMethods#match
143
+ match} instead of `on` to define our handler. Furthermore, we didn't
144
+ specify a message type nor did we provide any blocks.
145
+
146
+ But let's back up and proceed in smaller steps to see how plugins are built.
147
+
148
+ First thing after defining a new class is to include {Cinch::Plugin} –
149
+ This module will provide methods like
150
+ {Cinch::Plugin::ClassMethods#match match} and also allows Cinch to
151
+ control the class in specific ways required for plugins to work.
152
+
153
+ Then we use aforementioned `match`, instead of `on`, to specify what
154
+ messages we want to react to. We didn't have to specify the message
155
+ type because plugins default to {file:docs/events.md#message :message}.
156
+
157
+ We then define a method called `execute`, which is pretty much the
158
+ same as blocks are to on-handlers. And from here on, everything is the
159
+ same.
160
+
161
+ The only thing left to do is to tell Cinch to use our plugin, by
162
+ adding it to {file:docs/bot_options.md#pluginsplugins c.plugins.plugins}.
163
+
164
+ One important thing remains to note: Plugins have a
165
+ {file:docs/bot_options.md#pluginsprefix prefix}, a string (or pattern)
166
+ that gets appended to all patterns you define, and by default this
167
+ prefix is `/^!/`. This means that in order to invoke our HelloWorld
168
+ plugin, a user has to say "!hello" instead of "hello". This prefix can
169
+ be configured on a per-plugin or global basis, but that's not in the
170
+ scope of this document.
171
+
172
+ # Final Words
173
+
174
+ This short guide only explains the basics of using Cinch, so that you
175
+ can get started as quickly as possible. For more advanced topics, you
176
+ will want to read the specific documents:
177
+
178
+ - {file:docs/plugins.md Plugins}
179
+ - {file:docs/bot_options.md A list of all available bot options}
180
+ - {file:docs/events.md A list of all available events}
181
+ - {file:docs/encodings.md Dealing with encodings}
182
+ - {file:docs/logging.md Logging in Cinch}
183
+ - {file:docs/common_tasks.md A cookbook for common tasks}
184
+ - {file:docs/common_mistakes.md A list of common mistakes and how to avoid them}
data/docs/logging.md ADDED
@@ -0,0 +1,90 @@
1
+ # @title Logging
2
+ # @markup kramdown
3
+
4
+ # Using the logger
5
+
6
+ Plugins can use the logging facility for logging their own messages,
7
+ either by using the logging related helper methods (#debug, #info, and
8
+ so on) or by directly interfacing with {Cinch::LoggerList}, which is
9
+ available via `@bot.loggers`.
10
+
11
+ Example:
12
+
13
+ class MyPlugin
14
+ include Cinch::Plugin
15
+
16
+ match "foo"
17
+ def execute(m)
18
+ debug "Starting handler..."
19
+ info "Some more important information"
20
+ debug "Done."
21
+ end
22
+ end
23
+
24
+ # Logger levels
25
+
26
+ Cinch uses a priority-based logging system, using the types `:debug`,
27
+ `:log`, `:info`, `:warn`, `:error` and `:fatal`, each of them
28
+ displaying less information than the previous.
29
+
30
+ By default, the logging level to display is set to `:debug`, which
31
+ will include all possible kinds of log events, including the rather
32
+ verbose debug output caused by plugins.
33
+
34
+ `:log` will hide debug output but still contain the raw IRC log and
35
+ from there on, the levels are rather self-explanatory.
36
+
37
+ ## Changing the level
38
+
39
+ The level can be changed for single loggers or all loggers at once, by either using {Cinch::Logger#level=} or {Cinch::LoggerList#level=} respectively.
40
+
41
+ Example:
42
+
43
+ bot = Cinch::Bot.new { }
44
+ bot.loggers << Cinch::Logger::FormattedLogger.new(File.open("/tmp/log.log", "a"))
45
+ bot.loggers.level = :debug
46
+ bot.loggers.first.level = :info
47
+
48
+ This will set all loggers to the `:debug` level (which actually is the
49
+ default already) and the first logger (which is the default STDOUT
50
+ logger) to `:info`.
51
+
52
+ # Log filtering
53
+
54
+ Sometimes it is undesirable to log a message unchanged. For example
55
+ when identifying to the network, passwords might be sent in plain
56
+ text. To prevent such information from appearing in logs, {Cinch::LogFilter log filters}
57
+ can be employed.
58
+
59
+ Log filters take a log message as input and return a new message. This
60
+ allows removing/masking out passwords or other undesired information.
61
+ Additionally, messages can be dropped entirely by returning nil.
62
+
63
+ It is possible to use more than one filter, in which case they will be
64
+ called in order, each acting on the previous filter's output.
65
+
66
+ Filters can be installed by adding them to {Cinch::LoggerList#filters}.
67
+
68
+ An example (and very simple) password filter might look like this:
69
+
70
+ class PasswordFilter
71
+ def initialize(bot)
72
+ @bot = bot
73
+ end
74
+
75
+ def filter(message, event)
76
+ message.gsub(@bot.config.password, "*" * @bot.config.password.size)
77
+ end
78
+ end
79
+
80
+ This filter will replace the password in all log messages (except for
81
+ exceptions). It could further discriminate by looking at `event` and
82
+ only modify outgoing IRC messages. It could also use the
83
+ {Cinch::Message} class to parse the message and only operate on the
84
+ actual message component, not channel names and similar. How fancy
85
+ your filtering needs to be depends on you.
86
+
87
+ # Writing your own logger
88
+
89
+ This section will follow soon. For now just look at the code of
90
+ already implemented loggers.
data/docs/migrating.md ADDED
@@ -0,0 +1,267 @@
1
+ # @title Migration Guide
2
+ # @markup kramdown
3
+
4
+ # Migration Guide
5
+
6
+ This document explains how to migrate between API incompatible
7
+ versions of Cinch.
8
+
9
+ ## Migrating from 1.x to 2.x
10
+
11
+ ## Plugins
12
+
13
+ ### New methods
14
+
15
+ Plugins have the following (new) instance and class methods, which you
16
+ shouldn't and usually mustn't overwrite:
17
+
18
+ - `#bot`
19
+ - `#config`
20
+ - `#handlers`
21
+ - `#synchronize`
22
+ - `#timers`
23
+ - `#unregister`
24
+ - `::call_hooks`
25
+ - `::check_for_missing_options`
26
+ - `::ctcp`
27
+ - `::ctcps`
28
+ - `::help=`
29
+ - `::help`
30
+ - `::hook`
31
+ - `::hooks`
32
+ - `::listen_to`
33
+ - `::listeners`
34
+ - `::match`
35
+ - `::matchers`
36
+ - `::plugin_name=`
37
+ - `::plugin_name`
38
+ - `::prefix=`
39
+ - `::prefix`
40
+ - `::react_on=`
41
+ - `::react_on`
42
+ - `::required_options=`
43
+ - `::required_options`
44
+ - `::set`
45
+ - `::suffix=`
46
+ - `::suffix`
47
+ - `::timer`
48
+ - `::timers`
49
+
50
+ Note: The list does also include methods from prior versions.
51
+
52
+
53
+ ### Plugin options
54
+
55
+ Previously, plugins used a DSL-like way of setting options like the
56
+ plugin prefix. This contradicts with the general idea of plugins being
57
+ ordinary Ruby classes and also caused a lot of code and documentation
58
+ smell.
59
+
60
+ Instead of having methods like `#prefix` double as both attribute
61
+ getter and setter, options can now be set in two different ways: Using
62
+ ordinary attribute setters or using the
63
+ {Cinch::Plugin::ClassMethods#set #set} method.
64
+
65
+ #### Cinch 1.x
66
+
67
+ class MyPlugin
68
+ include Cinch::Plugin
69
+
70
+ prefix /^!/
71
+ help "some help message"
72
+ match /foo/
73
+ def execute(m)
74
+ # ...
75
+ end
76
+ end
77
+
78
+ #### Cinch 2.x, attribute setters
79
+
80
+ class MyPlugin
81
+ include Cinch::Plugin
82
+
83
+ self.prefix = /^!/
84
+ self.help = "some help message"
85
+ match /foo/
86
+ def execute(m)
87
+ # ...
88
+ end
89
+ end
90
+
91
+ #### Cinch 2.x, `#set` method
92
+
93
+ class MyPlugin
94
+ include Cinch::Plugin
95
+
96
+ set :prefix, /^!/
97
+ set :help, "some help message"
98
+ match /foo/
99
+ def execute(m)
100
+ # ...
101
+ end
102
+ end
103
+
104
+ #### Cinch 2.x, `#set` method, alternative syntax
105
+
106
+ class MyPlugin
107
+ include Cinch::Plugin
108
+
109
+ set prefix: /^!/,
110
+ help: "some help message"
111
+ match /foo/
112
+ def execute(m)
113
+ # ...
114
+ end
115
+ end
116
+
117
+
118
+ ### No more automatic matcher with the plugin's name
119
+
120
+ Cinch does not add a default matcher with the plugin's name anymore.
121
+ If you've been relying on the following to work
122
+
123
+ class Footastic
124
+ include Cinch::Plugin
125
+
126
+ def execute(m)
127
+ # this will triger on "!footastic"
128
+ end
129
+ end
130
+
131
+ you will have to rewrite it using an explicit matcher:
132
+
133
+ class Footastic
134
+ include Cinch::Plugin
135
+
136
+ match "footastic"
137
+ def execute(m)
138
+ # ...
139
+ end
140
+ end
141
+
142
+ ### No more default `#execute` and `#listen` methods
143
+
144
+ Plugins do not come with default `#execute` and `#listen` methods
145
+ anymore, which means that specifying a matcher or listener without
146
+ providing the required methods will always result in an exception.
147
+
148
+ ### Programmatically registering plugins
149
+
150
+ If you're using the API to register plugins on your own, you will have
151
+ to use the new {Cinch::PluginList} class and its methods, instead of
152
+ using `Cinch::Bot#register_plugin` or `Cinch::Bot#register_plugins`,
153
+ which have been removed.
154
+
155
+ The PluginList instance is available via {Cinch::Bot#plugins}.
156
+
157
+ ## Logging
158
+
159
+ Logging in Cinch 2.x has been greatly improved. Instead of only
160
+ supporting one logger and having all logging-relevant methods in
161
+ {Cinch::Bot}, we've introduced the {Cinch::LoggerList} class, which
162
+ manages an infinite number of loggers. Included with Cinch are the
163
+ {Cinch::Logger::FormattedLogger formatted logger}, known from Cinch
164
+ 1.x, and a new {Cinch::Logger::ZcbotLogger Zcbot logger}, a logger
165
+ emulating the log output of Zcbot, a format which can be parsed by
166
+ {http://pisg.sourceforge.net/ pisg}.
167
+
168
+ ### Log levels
169
+
170
+ The old `@config.verbose` option has been replaced with a finely
171
+ tunable log level system. Each logger has {Cinch::Logger#level its own
172
+ level}, but it is also possible to {Cinch::LoggerList#level= set the
173
+ level for all loggers at once}.
174
+
175
+ The available levels, in ascending order of verbosity, are:
176
+
177
+ - fatal
178
+ - error
179
+ - warn
180
+ - info
181
+ - log
182
+ - debug
183
+
184
+ ### Methods
185
+
186
+ All logging related methods (`Cinch::Bot#debug` et al) have been
187
+ removed from the Bot class and instead moved to the loggers and the
188
+ {Cinch::LoggerList LoggerList}. If you want to log messages from your
189
+ plugins or handlers, you should use {Cinch::Bot#loggers} to access the
190
+ {Cinch::LoggerList LoggerList} and then call the right methods on
191
+ that. Alterntively you can also use the logging-related helper methods
192
+ provided by {Cinch::Helpers}.
193
+
194
+ For more information on the logging architecture as well as examples
195
+ on how to use it, check the {file:docs/logging.md Logging readme}.
196
+
197
+ ## Prefix/suffix + string semantics
198
+
199
+ Behaviour of string prefixes and suffixes has been adapted to match
200
+ that of matchers.
201
+
202
+ That means that if the prefix or suffix are strings, the ^ or $ anchor
203
+ will be prepended/appened.
204
+
205
+ ## Hooks and their return value
206
+
207
+ Hooks now behave as filters. If a hook returns `false`, the message
208
+ will not further be processed in a particular plugin.
209
+
210
+ ## Constants
211
+
212
+ All constants for numeric replies (e.g. `RPL_INFO`) have been moved from
213
+ {Cinch} to {Cinch::Constants}. Thus `Cinch::RPL_INFO` becomes
214
+ {Cinch::Constants::RPL_INFO}, same for all other numeric constants.
215
+
216
+ ## Bot configuration
217
+
218
+ Bot configuration now uses {Cinch::Configuration special classes}
219
+ instead of OpenStructs. Thus, assignments like
220
+
221
+ configure do |c|
222
+ c.timeouts = OpenStruct.new({:read => 240, :connect => 10})
223
+ end
224
+
225
+ are not possible anymore and have to be written as either
226
+
227
+ configure do |c|
228
+ c.timeouts.read = 240
229
+ c.timeouts.connect = 10
230
+ end
231
+
232
+ or
233
+
234
+ configure do |c|
235
+ c.timeouts.load({:read => 240, :connect => 10})
236
+ end
237
+
238
+ The second version is especially interesting to tools like
239
+ {https://github.com/netfeed/cinchize Cinchize}, which load the
240
+ configuration from a YAML file. For more information see
241
+ {file:docs/bot_options.md Bot options}.
242
+
243
+
244
+ ## Various removed methods
245
+
246
+ See {file:docs/changes.md#removedrenamed-methods What's changed}
247
+
248
+
249
+ ## `on`-handlers now only accepts one pattern
250
+
251
+ In previous versions, {Cinch::Bot#on} accepted a variable amount of patterns
252
+ to match against. This feature was rarely used and has hence been
253
+ removed. If you've been using constructs like
254
+
255
+ on :message, [/this/, /that/] do |m|
256
+ # ...
257
+ end
258
+
259
+ you will have to rewrite them as follows:
260
+
261
+ b = lambda { |m|
262
+ # ...
263
+ }
264
+
265
+ [/this/, /that/].each do |pattern|
266
+ on :message, pattern, &b
267
+ end