grinch 1.0.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 (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