autumn 3.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/AUTHORS +11 -0
  2. data/CHANGELOG +567 -0
  3. data/MANIFEST +110 -0
  4. data/README +1114 -0
  5. data/README.textile +1153 -0
  6. data/Rakefile +75 -0
  7. data/autumn.gemspec +44 -0
  8. data/bin/autumn +11 -0
  9. data/lib/autumn.rb +8 -0
  10. data/lib/autumn/authentication.rb +238 -0
  11. data/lib/autumn/channel_leaf.rb +107 -0
  12. data/lib/autumn/coder.rb +166 -0
  13. data/lib/autumn/console_boot.rb +10 -0
  14. data/lib/autumn/ctcp.rb +250 -0
  15. data/lib/autumn/daemon.rb +207 -0
  16. data/lib/autumn/datamapper_hacks.rb +290 -0
  17. data/lib/autumn/foliater.rb +231 -0
  18. data/lib/autumn/formatting.rb +236 -0
  19. data/lib/autumn/generator.rb +231 -0
  20. data/lib/autumn/genesis.rb +190 -0
  21. data/lib/autumn/inheritable_attributes.rb +162 -0
  22. data/lib/autumn/leaf.rb +738 -0
  23. data/lib/autumn/log_facade.rb +49 -0
  24. data/lib/autumn/misc.rb +87 -0
  25. data/lib/autumn/resources/daemons/Anothernet.yml +3 -0
  26. data/lib/autumn/resources/daemons/AustHex.yml +29 -0
  27. data/lib/autumn/resources/daemons/Bahamut.yml +67 -0
  28. data/lib/autumn/resources/daemons/Dancer.yml +3 -0
  29. data/lib/autumn/resources/daemons/GameSurge.yml +3 -0
  30. data/lib/autumn/resources/daemons/IRCnet.yml +3 -0
  31. data/lib/autumn/resources/daemons/Ithildin.yml +7 -0
  32. data/lib/autumn/resources/daemons/KineIRCd.yml +56 -0
  33. data/lib/autumn/resources/daemons/PTlink.yml +6 -0
  34. data/lib/autumn/resources/daemons/QuakeNet.yml +20 -0
  35. data/lib/autumn/resources/daemons/RFC1459.yml +158 -0
  36. data/lib/autumn/resources/daemons/RFC2811.yml +16 -0
  37. data/lib/autumn/resources/daemons/RFC2812.yml +36 -0
  38. data/lib/autumn/resources/daemons/RatBox.yml +25 -0
  39. data/lib/autumn/resources/daemons/Ultimate.yml +24 -0
  40. data/lib/autumn/resources/daemons/Undernet.yml +6 -0
  41. data/lib/autumn/resources/daemons/Unreal.yml +110 -0
  42. data/lib/autumn/resources/daemons/_Other.yml +7 -0
  43. data/lib/autumn/resources/daemons/aircd.yml +33 -0
  44. data/lib/autumn/resources/daemons/bdq-ircd.yml +3 -0
  45. data/lib/autumn/resources/daemons/hybrid.yml +38 -0
  46. data/lib/autumn/resources/daemons/ircu.yml +67 -0
  47. data/lib/autumn/resources/daemons/tr-ircd.yml +8 -0
  48. data/lib/autumn/script.rb +74 -0
  49. data/lib/autumn/speciator.rb +165 -0
  50. data/lib/autumn/stem.rb +919 -0
  51. data/lib/autumn/stem_facade.rb +176 -0
  52. data/lib/autumn/tool/bin.rb +301 -0
  53. data/lib/autumn/tool/create.rb +48 -0
  54. data/lib/autumn/tool/project_creator.rb +110 -0
  55. data/lib/autumn/version.rb +3 -0
  56. data/lib/skel/Rakefile +163 -0
  57. data/lib/skel/config/global.yml +2 -0
  58. data/lib/skel/config/seasons/testing/database.yml +4 -0
  59. data/lib/skel/config/seasons/testing/leaves.yml +9 -0
  60. data/lib/skel/config/seasons/testing/season.yml +2 -0
  61. data/lib/skel/config/seasons/testing/stems.yml +10 -0
  62. data/lib/skel/leaves/administrator/README +20 -0
  63. data/lib/skel/leaves/administrator/controller.rb +67 -0
  64. data/lib/skel/leaves/administrator/views/autumn.txt.erb +1 -0
  65. data/lib/skel/leaves/administrator/views/reload.txt.erb +11 -0
  66. data/lib/skel/leaves/insulter/README +17 -0
  67. data/lib/skel/leaves/insulter/controller.rb +65 -0
  68. data/lib/skel/leaves/insulter/views/about.txt.erb +1 -0
  69. data/lib/skel/leaves/insulter/views/help.txt.erb +1 -0
  70. data/lib/skel/leaves/insulter/views/insult.txt.erb +1 -0
  71. data/lib/skel/leaves/scorekeeper/README +34 -0
  72. data/lib/skel/leaves/scorekeeper/config.yml +2 -0
  73. data/lib/skel/leaves/scorekeeper/controller.rb +104 -0
  74. data/lib/skel/leaves/scorekeeper/helpers/general.rb +64 -0
  75. data/lib/skel/leaves/scorekeeper/models/channel.rb +12 -0
  76. data/lib/skel/leaves/scorekeeper/models/person.rb +14 -0
  77. data/lib/skel/leaves/scorekeeper/models/pseudonym.rb +11 -0
  78. data/lib/skel/leaves/scorekeeper/models/score.rb +14 -0
  79. data/lib/skel/leaves/scorekeeper/tasks/stats.rake +17 -0
  80. data/lib/skel/leaves/scorekeeper/views/about.txt.erb +1 -0
  81. data/lib/skel/leaves/scorekeeper/views/change.txt.erb +5 -0
  82. data/lib/skel/leaves/scorekeeper/views/history.txt.erb +11 -0
  83. data/lib/skel/leaves/scorekeeper/views/points.txt.erb +5 -0
  84. data/lib/skel/leaves/scorekeeper/views/usage.txt.erb +1 -0
  85. data/lib/skel/log/README +1 -0
  86. data/lib/skel/script/console +28 -0
  87. data/lib/skel/script/destroy +48 -0
  88. data/lib/skel/script/generate +48 -0
  89. data/lib/skel/shared/README +1 -0
  90. data/lib/skel/tmp/README +1 -0
  91. data/spec/authentication_spec.rb +328 -0
  92. data/spec/channel_leaf_spec.rb +142 -0
  93. data/spec/coder_spec.rb +146 -0
  94. data/spec/ctcp_spec.rb +222 -0
  95. data/spec/daemon_spec.rb +202 -0
  96. data/spec/datamapper_hacks_spec.rb +164 -0
  97. data/tasks/authors.rake +30 -0
  98. data/tasks/changelog.rake +18 -0
  99. data/tasks/copyright.rake +21 -0
  100. data/tasks/doc.rake +7 -0
  101. data/tasks/gem.rake +23 -0
  102. data/tasks/gem_installer.rake +76 -0
  103. data/tasks/install_dependencies.rake +6 -0
  104. data/tasks/manifest.rake +4 -0
  105. data/tasks/rcov.rake +23 -0
  106. data/tasks/release.rake +52 -0
  107. data/tasks/reversion.rake +8 -0
  108. data/tasks/setup.rake +24 -0
  109. data/tasks/spec.rake +7 -0
  110. data/tasks/yard.rake +4 -0
  111. metadata +188 -0
@@ -0,0 +1,1153 @@
1
+ h1. Autumn: A Ruby IRC Bot Framework
2
+
3
+ *Version 3.1.5 (May 3, 2009)*
4
+
5
+ | Author | Tim Morgan (riscfuture@gmail.com) |
6
+ | Copyright | Copyright (c)2007-2009 Tim Morgan |
7
+ | License | Distributed under the same terms as Ruby. Portions of this code are copyright (c)2004 David Heinemeier Hansson; please see <tt>libs/inheritable_attributes.rb</tt> for more information. |
8
+
9
+ Autumn is a full-featured framework on top of which IRC bots (called "leaves")
10
+ can be quickly and easily built. It features a very Ruby-like approach to
11
+ bot-writing, a complete framework for loading and daemonizing your bots,
12
+ multiple environment contexts, a database-backed model, and painless logging
13
+ support.
14
+
15
+ h2. Requirements
16
+
17
+ Autumn requires "RubyGems":http://www.rubygems.org and the Daemons and Facets*
18
+ gems, as well as some of the gems spun off from Facets. Install RubyGems then
19
+ run @sudo gem install daemons facets anise english@ in a command line in order
20
+ to run Autumn.
21
+
22
+ If you wish to use a database backend for your bot, you will need the DataMapper
23
+ gem. To install, see the "DataMapper website":http://www.datamapper.org.
24
+
25
+ The included example bot Scorekeeper requires the DataMapper gem. It can
26
+ optionally use the Chronic gem to enhance its textual date parsing. The other
27
+ example bot, Insulter, is much simpler and can run under any Autumn
28
+ configuration.
29
+
30
+ h2. Directory Structure
31
+
32
+ An Autumn installation is like a Ruby on Rails installation: There is a
33
+ certain directory structure where your files go. A lot of files and folders will
34
+ seem confusing to people who have never used Autumn before, but bear with me. In
35
+ a bit I will explain in detail what all of this stuff is. For now, here is an
36
+ overview you can consult for future reference:
37
+
38
+ * *config/* - Configuration files and season definitions
39
+ ** global.yml - Universal settings that apply to every season
40
+ *** *seasons/* - Contains directories for each season (see *Seasons*)
41
+ **** *testing/* - Example season
42
+ ***** database.yml - Example database configuration file
43
+ ***** leaves.yml - Example bot configuration file
44
+ ***** season.yml - Season configuration
45
+ ***** stems.yml - Example IRC configuration file
46
+ * *doc/* - HTML documentation generated by RDoc
47
+ ** *leaves/* - Autumn leaves documentation
48
+ * *leaves/* - Autumn leaves. Each subdirectory contains all the code and
49
+ data for a leaf.
50
+ ** *insulter/* - Very simple example leaf
51
+ *** _See the *scorekeeper* directory_
52
+ ** *scorekeeper/* - Database-backed, full-featured example leaf
53
+ *** config.yml - Optional leaf-global configuration options
54
+ *** controller.rb - The leaf's controller object
55
+ *** *data/* - Optional directory for data storage (not used by Autumn)
56
+ *** *helpers/* - Modules that extend the controller and views
57
+ *** *models/* - Active record-type database objects
58
+ *** *tasks/* - Additional rake tasks for this leaf (see *Custom leaf tasks*)
59
+ *** *views/* - ERb views for each of the leaf's commands
60
+ * *log/* - Directory where (most) Autumn logs are written (see the *Logs*
61
+ section)
62
+ * Rakefile - Contains the rake tasks used to control Autumn (see the *Tasks*
63
+ section)
64
+ * README - RDoc-formatted readme
65
+ * README.textile - This file
66
+ * *script/* - Helper scripts for controlling Autumn
67
+ ** destroy - Destroys Autumn objects
68
+ ** generate - Creates Autumn objects
69
+ * *shared/* - Shared code libraries available to all leaves
70
+ * *tmp/* - Temporary files, such as PID files
71
+
72
+ h2. Configuring Autumn for Your First Launch
73
+
74
+ Before you can run Autumn and try out the example leaves, you'll need to set up
75
+ a few things. Here are the steps:
76
+
77
+ h3. Creating your bot's tree
78
+
79
+ To create a new tree, change to a directory where you want your bot to run from,
80
+ then use <tt>autumn create PROJECT</tt> to create the directory (PROJECT should
81
+ be replaced with your bot's name) with the structure outlined above.
82
+
83
+ h3. Configure Your Testing Season
84
+
85
+ In Autumn, your leaves run in an environment, called a "season." Each season has
86
+ different leaves and different settings for those leaves. By default, Autumn
87
+ comes with a season called "testing" already set up for you. You can edit that
88
+ season or create a new one with @script/generate season [season name]@. The
89
+ files for your season are stored in the <tt>config/seasons</tt> directory.
90
+
91
+ First, edit the <tt>stems.yml</tt> file. This file stores information about your
92
+ IRC connection. Edit it to connect to an IRC server of your choosing. For more
93
+ information, see *Stems* below.
94
+
95
+ Next, edit the <tt>database.yml</tt> file. As mentioned previously, Scorekeeper
96
+ requires the DataMapper gem because it uses a persistent store. By default it's
97
+ set up to use a SQLite 3 database, but you can use PostgreSQL or MySQL if you'd
98
+ like. If you'd prefer not to install any of these database solutions, delete the
99
+ <tt>database.yml</tt> file and remove the Scorekeeper leaf from the
100
+ <tt>leaves.yml</tt> and <tt>stems.yml</tt> files.
101
+
102
+ If you do choose to set up a database, you will have to run @rake db:migrate@
103
+ after your <tt>database.yml</tt> file is configured and your database is
104
+ created.
105
+
106
+ Lastly, view the <tt>leaves.yml</tt> file. You shouldn't have to make any
107
+ changes to this file, but it's a good idea to look at it to see how leaves are
108
+ configured. You can do the same with the <tt>season.yml</tt> file. See *Seasons*
109
+ and *Leaves* below for more.
110
+
111
+ h3. Starting the Server
112
+
113
+ Run the shell command @autumn start@ to start the server. After a short
114
+ while, your leaf should appear in the channel you specified. You can type
115
+ "!points Coolguy +5" and then "!points" to get started using Scorekeeper, or
116
+ "!insult" to play with Insulter. Have some fun, and when you're satisfied, stop
117
+ the server by typing "!quit".
118
+
119
+ If you'd like to daemonize your server, you can use the shell commands
120
+ @rake app:start@ and @rake app:stop@. For more information, see *Tasks* below.
121
+
122
+ h2. Making Your Own Leaf
123
+
124
+ Making your own leaf using Autumn is easy. In this tutorial, I'll show you how
125
+ to make a simple Fortune bot that responds to a few basic commands.
126
+
127
+ h3. Step 1: Subclass Leaf
128
+
129
+ Create a new leaf by typing @script/generate leaf fortune@. This will create a
130
+ <tt>fortune</tt> directory in the <tt>leaves</tt> directory, along with the bare
131
+ bones of files needed within that directory. Edit the <tt>controller.rb</tt>
132
+ file. First we'll create an array to hold our fortunes:
133
+
134
+ <pre><code>
135
+ FORTUNES = [
136
+ "You will make someone happy today.",
137
+ "Someone you don't expect will be important to you today.",
138
+ "Today will bring unexpected hardships."
139
+ ]
140
+ </code></pre>
141
+
142
+ As you can see, our 3 meager fortunes are stored in the @FORTUNES@ class
143
+ constant. Now, we'll want it to respond to the "!fortune" command, and all you
144
+ have to do is create a method called @fortune_command@ to make it work:
145
+
146
+ <pre><code>
147
+ def fortune_command(stem, sender, reply_to, msg)
148
+ FORTUNES.pick
149
+ end
150
+ </code></pre>
151
+
152
+ The @pick@ method is provided by Facets, so you may need to add a <code>require
153
+ 'facets/random'</code> line at the top of your file. Our method returns a
154
+ fortune at random, which is automatically transmitted to the channel or nick
155
+ where the command was received.
156
+
157
+ Of course, any self-respecting fortune bot announces its presence when it starts
158
+ up, so, in your @Controller@ class, override the @Autumn::Leaf#did_start_up@
159
+ method to display a cheerful greeting:
160
+
161
+ <pre><code>
162
+ def did_start_up
163
+ stems.message 'FortuneBot at your service! Type "!fortune" to get your fortune!'
164
+ end
165
+ </code></pre>
166
+
167
+ ...and that's it! You now have a fully functional fortune bot featuring -- not
168
+ two -- but _three_ unique and exciting fortunes!
169
+
170
+ (For more on that @stems.message@ bit, see *Stems*.)
171
+
172
+ h3. Step 2: Add the Leaf to Your Season
173
+
174
+ If you want, you can add the fortune bot to your <tt>leaves.yml</tt> and
175
+ <tt>stems.yml</tt> files to try it out. Adding a leaf is easy; simply duplicate
176
+ the structure used for another leaf's entry and change the values as
177
+ appropriate. A typical two-leaf configuration will look like:
178
+
179
+ <pre><code>
180
+ Scorekeeper:
181
+ class: Scorekeeper
182
+ respond_to_private_messages: false
183
+ Fortune:
184
+ class: Fortune
185
+ respond_to_private_messages: true
186
+ </code></pre>
187
+
188
+ As you notice, each leaf instance is given a name. In this example the name
189
+ happens to be the same as the leaf's type name, but you could run two copies of
190
+ a leaf like so:
191
+
192
+ <pre><code>
193
+ Fortune1:
194
+ class: Fortune
195
+ Fortune2:
196
+ class: Fortune
197
+ </code></pre>
198
+
199
+ This doesn't make a whole lot of sense for our fortune bot, but for more
200
+ complicated bots it can be useful.
201
+
202
+ We've created the leaf, but we have to add it to the stem for it to work.
203
+ (Remember, a stem is an IRC connection and a leaf is a bot.) So, in your
204
+ <tt>stems.yml</tt> file, add an entry for this leaf. Your new config will appear
205
+ something like:
206
+
207
+ <pre><code>
208
+ Example:
209
+ nick: Scorekeeper
210
+ leaves:
211
+ - Scorekeeper
212
+ - Insulter
213
+ - Fortune
214
+ rejoin: true
215
+ channel: somechannel
216
+ server: irc.someserver.com
217
+ </code></pre>
218
+
219
+ When you restart the server, the bot will come back online and will now also
220
+ respond to the "!fortune" command. This is a helpful tutorial on how stems and
221
+ leaves are separate. One leaf can have many stems, and one stem can have many
222
+ leaves. You can combine these two entities however you need.
223
+
224
+ h3. Step 3: Upgrade to ERb Views
225
+
226
+ You've already learned that for your @[word]_command@-type methods, the bot
227
+ responds with whatever string your method returns. For more complicated
228
+ commands, however, you may want to upgrade to full view abstraction, a la Ruby
229
+ on Rails. This is what the <tt>views</tt> directory is for.
230
+
231
+ If you place a <tt>.txt.erb</tt> file in the <tt>views</tt> directory named
232
+ after your command, it will be parsed by ERb and rendered as the result. You can
233
+ pass variables to the ERb parser by using the @Autumn::Leaf#var@ method. Let's
234
+ upgrade our @fortune_command@ method for that:
235
+
236
+ <pre><code>
237
+ def fortune_command(stem, sender, reply_to, msg)
238
+ var :fortune => FORTUNES.pick
239
+ end
240
+ </code></pre>
241
+
242
+ We can then write a view, <tt>fortune.txt.erb</tt>, which will render the
243
+ fortune:
244
+
245
+ <code><%= var :fortune %></code>
246
+
247
+ OK, so admittedly, this doesn't really get us anywhere, but for more complicated
248
+ bots, this well help separate view and controller concerns.
249
+
250
+ For more information on view rendering, see the @Autumn::Leaf#render@ method.
251
+
252
+ h2. Seasons
253
+
254
+ Each time you start Autumn, the process launches in a certain season (a.k.a.
255
+ environment context). This season is defined in the <tt>config/global.yml</tt>
256
+ file. You can temporarily override it by setting the @SEASON@ environment
257
+ variable (e.g., @SEASON=production autumn start@).
258
+
259
+ It's important to realize that an season is just a name, nothing more. You can
260
+ have as many seasons as you like, and name them anything that you like. Autumn
261
+ will load the config files for the season you've indicated as active. Autumn
262
+ doesn't really care if it's named "production" or "live" or
263
+ "testing-on-jeffs-machine"; it's all the same to Autumn.
264
+
265
+ Your season's configuration is stored in the <tt>season.yml</tt> file within
266
+ your season directory. Currently it supports one directive, @logging@. This sets
267
+ the minimum log level (such as @debug@ or @warn@). If the log level is set to
268
+ @debug@, it also enables console output parroting. (See the *Logging* section.)
269
+
270
+ The power of seasons comes in custom configuration options. For instance,
271
+ consider that you have a testing and production season. In your testing season,
272
+ your <tt>season.yml</tt> file contains:
273
+
274
+ <code>dont_http: true</code>
275
+
276
+ and in production, it contains:
277
+
278
+ <code>dont_http: false</code>
279
+
280
+ Now, in your code, you might have a method like:
281
+
282
+ <pre><code>
283
+ def scores_command(stem, sender, reply_to, msg)
284
+ if options[:dont_http] then
285
+ return "Some fake sports scores."
286
+ else
287
+ # go on the web and find real sports scores
288
+ end
289
+ end
290
+ </code></pre>
291
+
292
+ h3. Standard Configuration Options
293
+
294
+ h4. Global
295
+
296
+ System-wide configuration is done in the <tt>config/global.yml</tt> file. It
297
+ supports by default the following directives:
298
+
299
+ | @season@ | The season to launch in. |
300
+ | @log_history@ | The number of historical logfiles to keep (default 10). |
301
+
302
+ In addition, the following options are available (but cannot be set in the yml
303
+ file):
304
+
305
+ | @root@ | The root directory of the Autumn installation. |
306
+ | @system_logger@ | The @Autumn::LogFacade@ instance that records system messages. |
307
+
308
+ h4. Season
309
+
310
+ Season-specific configuration is done in the
311
+ <tt>config/seasons/[season]/season.yml</tt> file. Currently it only supports one
312
+ directive, @logging@, which takes log levels like @debug@ or @warn@.
313
+
314
+ h4. Stem
315
+
316
+ Stem-specific configuration is done in the
317
+ <tt>config/seasons/[season]/stems.yml</tt> file. It's important to note that
318
+ stem and leaf configurations are completely independent of each other. (In other
319
+ words, stem options do not override leaf options, nor vice versa.) Therefore,
320
+ you generally won't add custom directives to the <tt>stems.yml</tt> file,
321
+ because you generally won't be working with stems directly. The standard options
322
+ are:
323
+
324
+ | @server@ | The address of the IRC server. |
325
+ | @port@ | The IRC server port (default 6667). |
326
+ | @local_ip@ | The IP address to connect on (for virtual hosting). |
327
+ | @nick@ | The nick to request. |
328
+ | @password@ | The nick's password, if it is registered. |
329
+ | @channel@ | A channel to join. |
330
+ | @channels@ | A list of channels to join. |
331
+ | @leaf@ | The name of a leaf to run. |
332
+ | @leaves@ | A list of leaves to run. (These are the names of leaf configurations in <tt>leaves.yml</tt>, not leaf subclasses.) |
333
+ | @rejoin@ | If true, the stem will rejoin any channels it is kicked from. |
334
+ | @server_password@ | The password for the IRC server, if necessary. |
335
+ | @ssl@ | If true, the connection to the IRC server will be made over SSL. |
336
+ | @server_type@ | The IRC server type. See <tt>resources/daemons</tt> for a list of valid server types. If you do not manually set this value, it will be guessed automatically. |
337
+ | @case_sensitive_channel_names@ | If true, channel names will be compared with case sensitivity. |
338
+ | @dont_ghost@ | If true, the stem will not try to GHOST a registered nick if it's taken. |
339
+ | @ghost_without_password@ | If true, the stem will use the GHOST command without a password. Set this for servers that use some other form of nick authentication, such as hostname-based. |
340
+ | @user@ | The username to send (optional). |
341
+ | @name@ | The user's real name (optional). |
342
+ | @throttle@ | If enabled, the stem will throttle large amounts of simultaneous messages. |
343
+ | @throttle_rate@ | Sets the number of seconds that pass between consecutive PRIVMSG's when the leaf's output is throttled. |
344
+ | @throttle_threshold@ | Sets the number of simultaneous messages that must be queued before the leaf begins throttling output. |
345
+ | @nick_regex@ | The regular expression used to match nicknames in server messages. By default, it conforms to the RFC-1459 definition. |
346
+
347
+ The @channel@ and @channels@ directives can also be used to specify a password
348
+ for a password protected channel, like so:
349
+
350
+ <pre><code>
351
+ channel:
352
+ channelname: channelpassword
353
+ </code></pre>
354
+
355
+ or
356
+
357
+ <pre><code>
358
+ channels:
359
+ - channel1: password1
360
+ - channel2: password2
361
+ </code></pre>
362
+
363
+ The @port@, @server_type@, and @channel@/@channels@ options are set in the
364
+ config file but not available in the @options@ hash. They are accessed directly
365
+ from attributes in the @Autumn::Stem@ instance, such as the @channels@
366
+ attribute.
367
+
368
+ h4. Leaf
369
+
370
+ Leaf-specific configuration is done in the
371
+ <tt>config/seasons/[season]/leaves.yml</tt> file and the
372
+ <tt>leaves/[leaf]/config.yml</tt> file, with the former taking precedence over
373
+ the latter. As mentioned above, leaf and stem configurations are completely
374
+ separate, so one does not override the other. The standard options are:
375
+
376
+ | @class@ | The type of the leaf. It must be a subdirectory in the <tt>leaves</tt> directory. |
377
+ | @command_prefix@ | The text that must precede each command. Defaults to "!". |
378
+ | @respond_to_private_messages@ | If true, the leaf will parse commands in whispers, and respond over whispers to those commands. |
379
+ | @database@ | A database connection to use (as defined in <tt>database.yml</tt>). By default Autumn will choose a connection named after your leaf. |
380
+ | @formatter@ | The name of a module in @Autumn::Formatting@ that will handle output formatting and colorization. This defaults to mIRC-style formatting. |
381
+
382
+ In addition, the following options are available (but cannot be set in the yml
383
+ file):
384
+
385
+ | @root@ | The root directory of the leaf installation. |
386
+
387
+ The <tt>leaves.yml</tt> file is optional. When not included, each leaf in the
388
+ <tt>leaves</tt> directory will be automatically instantiated once.
389
+
390
+ h3. Custom Configuration Options
391
+
392
+ All configuration files support user-generated directives. You can set options
393
+ at any level. Options at a more narrow level override those at a broader level.
394
+
395
+ Options are maintained and cataloged by the @Autumn::Speciator@ singleton. You
396
+ could access the singleton directly, but most objects have an @options@
397
+ attribute providing simpler access to the Speciator.
398
+
399
+ For example, to access options in a leaf, all you do is call, for example,
400
+ @options[:my_custom_option]@. @my_custom_option@ can be set at the
401
+ global, season, or leaf level.
402
+
403
+ h2. Leaves
404
+
405
+ The @Autumn::Leaf@ class has many tools to help you write your leaves. These
406
+ include things like filters, helpers, loggers, and an easy to use IRC library.
407
+ The @Autumn::Leaf@ and @Autumn::Stem@ class docs are the most thorough way of
408
+ learning about each of these features, but I'll walk you through the basics
409
+ here.
410
+
411
+ h3. The Many Methods of Leaf
412
+
413
+ By subclassing @Autumn::Leaf@, you gain access to a number of neat utilities.
414
+ These generally come in three classes: IRC commands that have already been
415
+ written for you, utility methods you can call, and invoked methods you can
416
+ override. Utility methods do things like add filters. Invoked methods are called
417
+ when certain events happen, like when your leaf starts up or when a private
418
+ message is received. You override them in your leaf to customize how it responds
419
+ to these events.
420
+
421
+ | *Invoked methods* | @will_start_up@, @did_start_up@, @did_receive_channel_message@, etc. |
422
+ | *Utility methods* | @before_filter@, @database@, etc. |
423
+ | *IRC commands* | @quit_command@, @reload_command@, @autumn_command@, etc. |
424
+
425
+ See the class docs for more information on these methods.
426
+
427
+ In addition, your leaf is designated as a listener for its @Autumn::Stem@
428
+ instances. In short, this means if you want even finer control over the IRC
429
+ connection, you can implement listener methods. See the
430
+ @Autumn::Stem#add_listener@ method for examples of such methods.
431
+
432
+ Finally, your leaf can implement methods that are broadcast by listener plugins.
433
+ An example of such a plugin is the @Autumn::CTCP@ class, which is included in
434
+ all stems by default. Visit its class docs to learn more about how to send and
435
+ receive CTCP requests.
436
+
437
+ h3. Filters
438
+
439
+ Filters are methods that are run either before or after a command is executed.
440
+ In the former case, they can also prevent the command from being run. This is
441
+ useful for authentication, for instance: A filter could determine if someone is
442
+ authorized to run a command, and prevent the command from being run if not.
443
+
444
+ Use filters to save yourself the effort of rewriting code that will run before
445
+ or after a command is executed. Filter methods are named @[word]_filter@ and
446
+ they are added to the filter chain using the @before_filter@ and @after_filter@
447
+ methods (like in Ruby on Rails). As an example, imagine you wanted your bot to
448
+ say something after each command:
449
+
450
+ <pre><code>
451
+ class Controller > Autumn::Leaf
452
+ after_filter :outro
453
+
454
+ private
455
+
456
+ def outro_filter(stem, channel, sender, command, msg, opts)
457
+ stem.message "This has been a production of OutroBot!", channel
458
+ end
459
+ end
460
+ </code></pre>
461
+
462
+ The result of this is that after each command, the leaf will make a dramatic
463
+ exit. (Why did I use @after_filter@ and not @before_filter@? Because as I said
464
+ earlier, a @before_filter@ can stop the command from being executed; the only
465
+ way we know for sure that the command was executed -- and therefore should be
466
+ outroed -- is to use an @after_filter@.)
467
+
468
+ I made the @outro_filter@ method private because I felt it shouldn't be exposed
469
+ to other classes; this is not a requirement of the filter framework, though.
470
+
471
+ Now let's say you wanted to prevent the command from being run in some cases.
472
+ The most obvious application of this feature is authentication. Autumn already
473
+ includes a robust authentication module, but for the sake of example, let's
474
+ pretend you wanted to do your own authentication in your leaf. So, you write a
475
+ @before_filter@ to determine if the user is authenticated. @before_filter@
476
+ methods have return values; if they return false, the filter chain is halted and
477
+ the command is suppressed. If you want to have your leaf display some sort of
478
+ message (like "Nice try!"), you need to include that in your filter.
479
+
480
+ As an example, here's a simple form of authentication that just checks a
481
+ person's nick:
482
+
483
+ <pre><code>
484
+ class Controller < Autumn::Leaf
485
+ before_filter :authenticate, :only => :quit, :admin => 'Yournick'
486
+
487
+ def authenticate_filter(stem, channel, sender, command, msg, opts)
488
+ sender == opts[:admin]
489
+ end
490
+ end
491
+ </code></pre>
492
+
493
+ I'm introducing you to three new features with this sample:
494
+
495
+ * You can use the @:only@ option to limit your filter to certain commands. Note
496
+ that you specify the _command_ name as a symbol, _not_ the method name (which
497
+ would be @quit_command@ in this case).
498
+ * You can pass your own options to @before_filter@ and @after_filter@; they are
499
+ passed through to your method via the last parameter, @opts@.
500
+ * The return value of a @before_filter@ is used to determine if the command
501
+ should be run. So be careful that your method does not return @nil@ or @false@
502
+ unless you really mean for the command to be suppressed.
503
+
504
+ Both of these examples use the parameters sent to your filter method. They are,
505
+ in order:
506
+
507
+ # the @Autumn::Stem@ instance that received the command,
508
+ # the name of the channel to which the command was sent (or @nil@ if it was a
509
+ private message),
510
+ # the sender hash,
511
+ # the name of the command that was typed, as a symbol,
512
+ # any additional parameters after the command (same as the @msg@ parameter in
513
+ the <tt>[word]_command</tt> methods),
514
+ # the custom options that were given to @before_filter@ or @after_filter@.
515
+
516
+ There are two built-in options that you can specify for @before_filter@ and
517
+ @after_filter@, and those are @only@ and @except@. They work just like in Rails:
518
+ The @only@ option limits the filter to running only on the given command or list
519
+ of commands, and the @except@ option prevents the filter from being run on the
520
+ given command or list. All other options are passed to the filter for you to
521
+ use.
522
+
523
+ Filters are run in the order they are added to the filter chain. Therefore, a
524
+ superclass's filters will run before a subclass's filters, and filters added
525
+ later in a class definition will be run after those added earlier.
526
+
527
+ If you subclass one of your leaves, it inherits your superclass's filters. The
528
+ @Autumn::Leaf@ superclass does not have any filters by default, though by
529
+ default new leaves come with a simple authentication filter that checks the
530
+ user's privilege level.
531
+
532
+ h3. Authentication
533
+
534
+ You don't need to write a @before_filter@ as shown above, because Autumn already
535
+ includes a robust authentication module. The @Autumn::Authentication@ module
536
+ includes the @Base@ class and four different subclasses of it. Each of these
537
+ subclasses handles a different type of authentication. You can choose the
538
+ authentication strategy you want on a leaf-by-leaf basis or for a whole season.
539
+
540
+ To specify the kind of authentication you want, you must add an @authentication@
541
+ directive to your config. If you want to set it for an individual leaf, add it
542
+ to the <tt>leaves.yml</tt> file. If you want all leaves to have the same
543
+ authentication strategy, add it to the <tt>season.yml</tt> or
544
+ <tt>global.yml</tt> file.
545
+
546
+ The @authentication@ directive should be a hash that, at a minimum, includes a
547
+ key called @type@. This is the snake_cased name of subclass in
548
+ @Autumn::Authentication@ that you wish to use. As an example, here is an entry
549
+ for an Administrator bot in a <tt>leaves.yml</tt> file, with ops-based
550
+ authentication.
551
+
552
+ <pre><code>
553
+ Administrator:
554
+ class: Administrator
555
+ authentication:
556
+ type: op
557
+ </code></pre>
558
+
559
+ This will instantiate the @Autumn::Authentication::Op@ class for use with the
560
+ Administrator bot.
561
+
562
+ Other authentication strategies may require additional information. For
563
+ instance, if you want to used nick-based authentication, your
564
+ <tt>leaves.yml</tt> file might look like:
565
+
566
+ <pre><code>
567
+ Administrator:
568
+ class: Administrator
569
+ authentication:
570
+ type: nick
571
+ nick: MyNick
572
+ </code></pre>
573
+
574
+ See the class docs for each subclass in @Autumn::Authentication@ for more info
575
+ on how you should set up your configs.
576
+
577
+ h3. Persistent Stores
578
+
579
+ If you would like to use a persistent store for your leaf, you should install
580
+ the DataMapper gem and a DataObjects gem for your database of choice (MySQL,
581
+ PostgreSQL, or SQLite). DataMapper works almost identically to ActiveRecord, so
582
+ if you have any Rails programming experience, you should be able to dive right
583
+ in.
584
+
585
+ Once you've got DataMapper installed, you should create one or more database
586
+ connections in your <tt>config/seasons/[season]/database.yml</tt> file. A sample
587
+ database connection looks like:
588
+
589
+ <pre><code>
590
+ connection_name:
591
+ adapter: mysql
592
+ host: localhost
593
+ username: root
594
+ password: pass
595
+ database: database_name
596
+ </code></pre>
597
+
598
+ or, in a smaller syntax:
599
+
600
+ <code>connection_name: mysql://root@pass:localhost/database_name</code>
601
+
602
+ If you are using the "sqlite3" adapter, the @database@ option is the path to the
603
+ file where the data should be written (example:
604
+ @leaves/fortune/data/my_database.db@). You can name your connection however you
605
+ want, but you _should_ name it after either your leaf or your leaf subclass.
606
+ (More on this below.)
607
+
608
+ You should also create DataMapper model classes for each of your model objects.
609
+ You can place them within your leaf's <tt>models</tt> directory. This works
610
+ almost exactly the same as the <tt>app/models</tt> directory in Rails.
611
+
612
+ Once your database, data models, and leaves have been configured, you can use
613
+ the @rake db:migrate@ task to automatically populate your database.
614
+
615
+ Now, unlike Rails, Autumn supports multiple database connections. Two leaves can
616
+ use two different database connections, or share the same database connection.
617
+ Because of this, it's important to understand how to manage your connections.
618
+ Autumn tries to do this for you by guessing which connection belongs to which
619
+ leaf, based on their names.
620
+
621
+ For example, imagine you have a leaf named "Fortune" and an instance of that
622
+ leaf in <tt>leaves.yml</tt> named "MyFortune". If you name your database
623
+ connection either "Fortune" or "MyFortune" (or "fortune" or "my_fortune"), it
624
+ will automatically be associated with that leaf. What this means is that for the
625
+ leaf's command methods (such as @about_command@) and invoked methods (such as
626
+ @did_receive_private_message@), the database connection will already be set for
627
+ you, and you can start using your DataMapper objects just like ActiveRecord
628
+ objects.
629
+
630
+ If, on the other hand, you either *named your database connection differently
631
+ from your leaf or subclass name* or you are *writing a method outside of the
632
+ normal flow of leaf methods* (for instance, one that is directly called by a
633
+ @Stem@, or a different listener), you will need to call the @database@ method
634
+ and pass it a block containing your code.
635
+
636
+ This is terribly confusing, so let me give you an example. Let's assume you've
637
+ got a fortune bot running a leaf named "FortuneLeaf", so your
638
+ <tt>leaves.yml</tt> configuration is:
639
+
640
+ <pre><code>
641
+ FortuneBot:
642
+ class: FortuneLeaf
643
+ </code></pre>
644
+
645
+ And you have a database connection for that leaf, named after the leaf's class:
646
+
647
+ <pre><code>
648
+ fortune_leaf:
649
+ adapter: sqlite3
650
+ database: leaves/fortune_leaf/data/development.db
651
+ </code></pre>
652
+
653
+ Let's further assume you have a simple DataMapper object:
654
+
655
+ <pre><code>
656
+ class Fortune
657
+ include DataMapper::Resource
658
+ property :id, Integer, :serial => true
659
+ property :text, String
660
+ end
661
+ </code></pre>
662
+
663
+ Now, if we wanted to write a "!fortune" command, it would appear something like
664
+ this:
665
+
666
+ <pre><code>
667
+ def fortune_command(stem, sender, reply_to, msg)
668
+ fortunes = Fortune.all
669
+ fortunes[rand(fortunes.size)].text
670
+ end
671
+ </code></pre>
672
+
673
+ Autumn automatically knows to execute this DataMapper code in the correct
674
+ database context. It knows this because your leaf's name is @FortuneLeaf@, and
675
+ your database context is named the same.
676
+
677
+ But what if you wanted to use that connection for other leaves too, so you named
678
+ it something like "local_database"? Now, Autumn won't be able to guess that you
679
+ want to use that DB context, so you have to specify it manually:
680
+
681
+ <pre><code>
682
+ def fortune_command(stem, sender, reply_to, msg)
683
+ database(:local_database) do
684
+ fortunes = Fortune.all
685
+ return fortunes[rand(fortunes.size)].text
686
+ end
687
+ end
688
+ </code></pre>
689
+
690
+ If that is too tedious, you can specify the database connection manually in the
691
+ <tt>leaves.yml</tt> file:
692
+
693
+ <pre><code>
694
+ FortuneBot:
695
+ class: FortuneLeaf
696
+ database: local_database
697
+ </code></pre>
698
+
699
+ OK, now onto the second special case. Imagine you want your fortune bot to also
700
+ send a fortune in response to a CTCP VERSION request. So, you'd implement a
701
+ method like so:
702
+
703
+ <pre><code>
704
+ def ctcp_version_request(handler, stem, sender, arguments)
705
+ fortune = random_fortune # Loads a random fortune
706
+ send_ctcp_reply stem, sender[:nick], 'VERSION', fortune.text
707
+ end
708
+ </code></pre>
709
+
710
+ This will break -- why? Because the @ctcp_version_request@ method is in the
711
+ realm of the @Autumn::CTCP@ class, _not_ the @Autumn::Leaf@ class. (You can see
712
+ this by investigating the CTCP class docs; it shows you what methods you can
713
+ implement for CTCP support.) Basically, the @CTCP@ class calls your method
714
+ directly, giving the @Autumn::Leaf@ class no chance to set up the database
715
+ first. So to fix it, make a call to @database@ first:
716
+
717
+ <pre><code>
718
+ def ctcp_version_request(handler, stem, sender, arguments)
719
+ fortune = database { random_fortune }
720
+ send_ctcp_reply stem, sender[:nick], 'VERSION', fortune.text
721
+ end
722
+ </code></pre>
723
+
724
+ This will execute those methods in the scope of the database connection guessed
725
+ by @Autumn::Leaf@. Of course, you can manually pass in a connection name if
726
+ necessary.
727
+
728
+ *Another important note:* You will need to make a call to @database@ in any
729
+ child threads your leaf creates. The database context is not automatically
730
+ carried over to such threads.
731
+
732
+ h3. Your Leaf's Module; or, "What Do I Do About Namespace Conflicts?"
733
+
734
+ So, if you have two database-backed leaves, it's entirely likely that both of
735
+ them will use some sort of DataMapper resource named @Channel@, or something
736
+ similar. You can't define the class @Channel@ twice in two different ways, so
737
+ how do you deal with this?
738
+
739
+ The answer is: It's already dealt with for you. Go ahead and define the class
740
+ twice. Or three times.
741
+
742
+ The longer explanation is: Secretly, behind the scenes, *all your leaf code is
743
+ being cleverly loaded into a module named after your leaf*. So, when, in your
744
+ <tt>controller.rb</tt> code, it says @class Controller < Autumn::Leaf@, you
745
+ should read it as @class MyLeafName::Controller < Autumn::Leaf@. When you define
746
+ your model with @class Channel@, it's really read as <code>class
747
+ MyLeafName::Channel</code>.
748
+
749
+ Don't worry about table names or associations or anything, either. Just go ahead
750
+ and use it as if it weren't in a module. The <tt>libs/datamapper_hacks.rb</tt>
751
+ file has all the necessary code changes to make this bit of trickery work.
752
+
753
+ h3. Using Support Modules
754
+
755
+ Helper modules placed in your leaf's <tt>helpers</tt> directory will
756
+ automatically be loaded and included in your leaf controller and views. To
757
+ create a helper module, place Ruby files to be loaded into the <tt>helpers</tt>
758
+ directory. Make sure your helper modules' names end with the word "Helper".
759
+
760
+ For instance, if your leaf's name is "Fortune", and you needed two helpers, a
761
+ database helper and a network helper, you could create two modules named
762
+ @DatabaseHelper@ and @NetworkHelper@. Any modules named in this fashion and
763
+ placed in the <tt>helpers</tt> subdirectory will be loaded and appended to the
764
+ controller and its views automatically.
765
+
766
+ h3. Debugging Your Leaf
767
+
768
+ If you make a simple code change to your leaf, you can reload it without having
769
+ to restart the whole process. See the @Autumn::Leaf#reload_command@
770
+ documentation for more information on when and how you can reload your leaf's
771
+ code.
772
+
773
+ If an error occurs on a live production instance, it will be logged to the log
774
+ file for your season. You can inspect the log file to determine what went wrong.
775
+
776
+ If the error happens before the logger is available, oftentimes it will appear
777
+ in the <tt>autumn.output</tt> or <tt>autumn.log</tt> files. These files are
778
+ generated by the daemon library and note any uncaught exceptions or standard
779
+ outs. They are in the <tt>tmp</tt> directory.
780
+
781
+ The most tricky of errors can happen before the process is daemonized. If your
782
+ process is quitting prematurely, and you don't see anything in either log file,
783
+ consider running @autumn start@, allowing you to see any exceptions for
784
+ yourself.
785
+
786
+ Unfortunately, it's still possible that the bug might not appear when you do
787
+ this, but only appear when the process is daemonized. In this situation, I'd
788
+ recommend installing rdebug (@sudo gem install rdebug@) and stepping through the
789
+ code to figure out what's going wrong. In particular, make sure you step into
790
+ the @Foliater@'s @start_stems@ method, when it creates the new threads. It's
791
+ possible your exception will rear its head once you step into that line of code.
792
+
793
+ h2. Stems
794
+
795
+ @Autumn::Stem@ is a full-featured IRC client library, written from the ground up
796
+ for Autumn. It makes extensive use of implicit protocols, meaning that most
797
+ features are accessed by implementing the methods you feel are necessary.
798
+
799
+ Most of the time, you will only work with stems indirectly via leaves. For
800
+ instance, if you want an "!opped" command that returns true if the sender is an
801
+ operator, it would look like this:
802
+
803
+ <pre><code>
804
+ def opped_command(stem, sender, reply_to, msg)
805
+ stem.channel_members[reply_to][sender[:nick]] == :operator ? "You are opped." : "You are not opped."
806
+ end
807
+ </code></pre>
808
+
809
+ Let's break this down. In order to figure out if someone is opped or not, we
810
+ need three pieces of information: their nick, the channel they are in, and the
811
+ IRC server they are connected to.
812
+
813
+ The @stem@ parameter contains the @Autumn::Stem@ instance that received this
814
+ message. It is our link to that server. Through it we can perform IRC actions
815
+ and make requests.
816
+
817
+ @Autumn::Stem@ includes an attribute @channel_members@, a hash of channels
818
+ mapped to their members. The channel that received the message is passed via the
819
+ @reply_to@ parameter. So we call @channel_members[reply_to]@ and we receive a
820
+ hash of member names to their privilege levels. The @sender@ parameter contains
821
+ information about the person who sent the command, including their nick. So we
822
+ use their nick to resolve their privilege level.
823
+
824
+ Complicated? Sure it is. That's the price we pay for separating stems from
825
+ leaves. But what if you, like probably 90% of the people out there who use
826
+ Autumn, only have one stem? Why should you have to call the same damn stem each
827
+ and every time?
828
+
829
+ Fortunately, your pleas are not in vain. For leaves that run off only one stem,
830
+ the stem's methods are rolled right into the leaf. So, that "!opped" command
831
+ method becomes:
832
+
833
+ <pre><code>
834
+ def opped_command(stem, sender, reply_to, msg)
835
+ channel_members[reply_to][sender[:nick]] == :operator ? "You are opped." : "You are not opped."
836
+ end
837
+ </code></pre>
838
+
839
+ OK, so it's not like a world-class improvement, but it helps.
840
+
841
+ The primary thing your leaf will probably do with a @Stem@ instance is use it to
842
+ send messages, like so:
843
+
844
+ <pre><code>
845
+ def about_command(stem, sender, reply_to, msg)
846
+ stem.message "I am a pretty awesome bot!", reply_to
847
+ end
848
+ </code></pre>
849
+
850
+ Fortunately, if you just return a string, @Autumn::Leaf@ will automatically send
851
+ it for you, simplifying our method:
852
+
853
+ <pre><code>
854
+ def about_command(stem, sender, reply_to, msg)
855
+ "I am a pretty awesome bot!"
856
+ end
857
+ </code></pre>
858
+
859
+ You would still interact with the stem directly if you wanted to do something
860
+ like announce your leaf's presence to everyone. To do this, you'd have to send
861
+ a message to every channel of every stem the leaf is a listener for:
862
+
863
+ <code>stems.each { |stem| stem.channels.each { |channel| stem.message "Hello!", channel } }</code>
864
+
865
+ But! @Autumn::Stem#message@ will automatically send a message to every channel
866
+ if you don't specify any channels, simplifying our code to:
867
+
868
+ <code>stems.each { |stem| stem.message "Hello!" }</code>
869
+
870
+ It gets even better. *You can call methods on the @stems@ array as if it were a
871
+ stem itself!* This simplifies the line significantly:
872
+
873
+ <code>stems.message "Hello!"</code>
874
+
875
+ Pretty nifty, huh? This also works for functions as well as methods; for
876
+ instance, the @Autumn::Stem#ready?@ function, which returns true if a stem is
877
+ ready:
878
+
879
+ <code>stems.ready? #=> [ true, true, false, true ]</code> (for example)
880
+
881
+ h3. The nitty-gritty of stems
882
+
883
+ The section above dealt with stems as they relate to leaves. But when would you
884
+ need to deal with a stem directly? Generally, never. However, if you find that
885
+ @Autumn::Leaf@ doesn't have what you need, you may have to turn to
886
+ @Autumn::Stem@ to get the functionality you are looking for. So let's take a
887
+ look at how Stem works.
888
+
889
+ A stem interacts with interested parties via the listener protocol. Your leaf
890
+ signals its interest to a stem by calling @Autumn::Stem#add_listener@. When a
891
+ leaf or any other object becomes a stem's listener, that stem then invokes
892
+ methods on the listener whenever an IRC event occurs.
893
+
894
+ Let's take a simple example. Assume you wanted to build a basic textual IRC
895
+ client using Stem. You'd first want to indicate that your client is a listener:
896
+
897
+ <pre><code>
898
+ class MyClient
899
+ def initialize(stem)
900
+ @stem = stem
901
+ @stem.add_listener self
902
+ end
903
+ end
904
+ </code></pre>
905
+
906
+ Now the stem will send method calls to your @MyClient@ instance every time an
907
+ IRC event occurs. None of these methods are required -- you can implement as few
908
+ or as many as you want. The different methods that @Stem@ will send are
909
+ documented in the @Autumn::Stem#add_listener@ method docs. One very important
910
+ method is the @irc_privmsg_event@ method. Let's implement it:
911
+
912
+ <pre><code>
913
+ def irc_privmsg_event(stem, sender, arguments)
914
+ puts "#{arguments[:channel]} <#{sender[:nick]}> #{arguments[:message]}"
915
+ end
916
+ </code></pre>
917
+
918
+ Now we've got the most important part of our IRC client done -- receiving
919
+ messages.
920
+
921
+ You can also send IRC events using stem. It's simple: Every IRC command (such as
922
+ JOIN and PRIVMSG and MODE) has a corresponding method in @Stem@ (such as @join@
923
+ and @privmsg@ and @mode@). These methods aren't in the API docs because they're
924
+ implemented using @method_missing@. Their arguments are exactly the same as the
925
+ arguments the IRC command expects, and in the same order.
926
+
927
+ So how do we send a message? Well according to RFC-1459, the basic IRC spec, the
928
+ PRIVMSG command takes two arguments: a list of receivers, and the text to be
929
+ sent. So, we know our method call should look something like this:
930
+
931
+ @stem.privmsg recipient, message
932
+
933
+ Astute readers will note that the spec shows a _list_ of recipients, and indeed,
934
+ you can call the method like so:
935
+
936
+ @stem.privmsg [ recipient1, recipient2 ], message
937
+
938
+ That's the basics of how @Autumn::Stem@ works, but there's one other thing worth
939
+ mentioning, and that's listener plugins. The details are in the
940
+ @Autumn::Stem#add_listener@ method docs, but the short of it is that these are
941
+ special listeners that bestow their powers onto other listeners.
942
+
943
+ The best example of this is the @Autumn::CTCP@ class. This class is indeed a
944
+ @Stem@ listener: It listens to PRIVMSG events from the stem, and checks them to
945
+ see if they are CTCP requests. However, it _also_ gives you, the author of
946
+ another listener (such as your leaf) the ability to implement methods according
947
+ to _its_ protocol.
948
+
949
+ For example, say you wanted to respond to CTCP VERSION requests with your own
950
+ version information. You do it like so:
951
+
952
+ <pre><code>
953
+ def ctcp_version_request(handler, stem, sender, arguments)
954
+ send_ctcp_reply stem, sender[:nick], 'VERSION', "AwesomeBot 2.0 by Sancho Sample"
955
+ end
956
+ </code></pre>
957
+
958
+ What's going on here? Because the @Autumn::CTCP@ class is a listener plugin, it
959
+ is sending its own method calls as well as implementing @Stem@'s method calls.
960
+ One such call is the @ctcp_version_request@ method, which you can see in the
961
+ @CTCP@ class docs. Somewhere deep in the annals of @Autumn::Foliater@, there is
962
+ some code similar to the following:
963
+
964
+ <pre><code>
965
+ ctcp = Autumn::CTCP.new
966
+ stem.add_listener ctcp
967
+ </code></pre>
968
+
969
+ Thus, every stem comes pre-fab with a CTCP listener plugin. That plugin is
970
+ intercepting PRIVMSG events and checking if they're CTCP requests. If they are,
971
+ it is invoking methods, such as @ctcp_version_request@, in all of the stem's
972
+ other listeners, among which is your leaf. Hopefully you understand how this all
973
+ fits together.
974
+
975
+ The lesson to take home here is two-fold: Firstly, if you'd like CTCP support in
976
+ your leaf, know that it's the @Autumn::CTCP@ class that is providing the method
977
+ calls to your leaf, not the @Autumn::Stem@ class. Secondly, this should
978
+ hopefully give you some ideas should you want to write your own listener plugin
979
+ to enhance @Stem@'s functionality.
980
+
981
+ h2. Autumn's Logging
982
+
983
+ Autumn uses Ruby's @Logger@ class to log; however, it uses @Autumn::LogFacade@
984
+ to prepend additional information to each log entry. The @LogFacade@ class has
985
+ the exact same external API as @Logger@, so you can use it like a typical Ruby
986
+ or Ruby on Rails logger. Many objects (such as @Leaf@ and @Stem@) include a
987
+ @logger@ attribute:
988
+
989
+ <pre><code>
990
+ logger.debug "Debug statement"
991
+ logger.fatal $!
992
+ </code></pre>
993
+
994
+ See the @LogFacade@ class docs for details.
995
+
996
+ h2. Tasks
997
+
998
+ The included Rakefile contains a number of useful tasks to help you develop and
999
+ deploy your leaves. You can always get a list of tasks by typing @rake --tasks@.
1000
+ The various commands you can run are:
1001
+
1002
+ Application tasks:
1003
+
1004
+ | @rake app:start@ | Starts the Autumn daemon in the background. |
1005
+ | @rake app:stop@ | Stops the Autumn daemon. |
1006
+ | @rake app:restart@ | Reloads the Autumn daemons. |
1007
+ | @rake app:run@ | Starts the Autumn daemon in the foreground. |
1008
+ | @rake app:zap@ | Forces the daemon to a stopped state. Use this command if your daemon is not running but <tt>autumn</tt> thinks it still is. |
1009
+
1010
+ Database tasks:
1011
+
1012
+ | @LEAF=[leaf name] rake db:migrate@ | Creates all the tables for a leaf, as specified by the leaf's model objects |
1013
+
1014
+ Documentation tasks:
1015
+
1016
+ | @rake doc:api@ | Generates HTML documentation for Autumn, found in the <tt>doc/api</tt> directory. |
1017
+ | @rake doc:leaves@ | Generates HTML documentation for your leaves, found in the <tt>doc/leaves</tt> directory. |
1018
+ | @rake doc:clear@ | Removes all HTML documentation. |
1019
+
1020
+ Logging tasks:
1021
+
1022
+ | @rake log:clear@ | Clears the log files for all seasons. |
1023
+ | @rake log:errors@ | Prints a list of error-level log messages for the current season, and uncaught exceptions in all seasons. |
1024
+
1025
+ h3. Custom leaf tasks
1026
+
1027
+ You can define your own leaf-specific tasks in the <tt>tasks</tt> subdirectory
1028
+ within your leaf's directory. Any <tt>.rake</tt> files there will be loaded by
1029
+ rake. The tasks will be added within a task-group named after your leaf. Use
1030
+ Scorekeeper as an example: If you type @rake --tasks@, you'll see one other
1031
+ task, @rake scorekeeper:scores@. The "scores" task is defined in the
1032
+ <tt>leaves/scorekeeper/tasks/stats.rake</tt> file, and placed in the
1033
+ "scorekeeper" task group by Autumn.
1034
+
1035
+ Also, if you open that file up, you'll notice that you have to refer to your
1036
+ leaf's classes by their _full_ names, including the leaf module. (See *Your
1037
+ Leaf's Module* if you're confused.)
1038
+
1039
+ h2. Scripts
1040
+
1041
+ Autumn includes some scripts to help you control it.
1042
+
1043
+ h3. <tt>script/console</tt>
1044
+
1045
+ Bootstraps an IRb console with the Autumn environment configured. Stems and
1046
+ leaves are accessile from the Foliater instance. DataMapper models can be used.
1047
+ Does not start any stems (in other words, no actual server login occurs).
1048
+
1049
+ Usage: @script/console [options]@
1050
+
1051
+ where [options] may contain:
1052
+
1053
+ | @--irb@ | Invoke a different Ruby terminal. |
1054
+
1055
+ You can alter the season by setting the @SEASON@ environment variable.
1056
+
1057
+ h3. <tt>autumn start|stop|status|restart PROJECT [options]</tt>
1058
+
1059
+ The @autumn@ command controls the Autumn daemon.
1060
+ PROJECT is the path to your autumn bot's root directory.
1061
+
1062
+ Usage: @autumn [command] [options] -- [application options]@
1063
+
1064
+ where [command] is one of:
1065
+
1066
+ | @start@ | start an instance of the application |
1067
+ | @stop@ | stop all instances of the application |
1068
+ | @restart@ | stop all instances and restart them afterwards |
1069
+ | @status@ | show the status of an application |
1070
+
1071
+ and where [options] are:
1072
+
1073
+ | @-D, --daemonize@ | Daemonize the bot |
1074
+ | @-m, --monitor@ | Try to restart from crashes in daemon mode |
1075
+
1076
+ Common options:
1077
+
1078
+ | @-h, --help@ | Show usage |
1079
+
1080
+ h3. <tt>script/destroy</tt>
1081
+
1082
+ Destroys the files for leaves, seasons, and other objects of the Autumn
1083
+ framework.
1084
+
1085
+ Usage: @script/destroy [options] [object] [name]@
1086
+
1087
+ | [object] | The object type to destroy. Valid types are "leaf" and "season". |
1088
+ | [name] | The name of the object to destroy. For example, you can call @script/destroy leaf Scorekeeper@ to remove a leaf named Scorekeeper. |
1089
+
1090
+ | @--help, -h@ | Displays this usage information. |
1091
+ | @--vcs, -c@ | Remove any created files or directories from the project's version control system. (Autodetects CVS, Git, and Subversion.) |
1092
+
1093
+ h3. <tt>script/generate</tt>
1094
+
1095
+ Generates template files for leaves, seasons, and other Autumn objects.
1096
+
1097
+ Usage: @script/generate [options] [template] [name]@
1098
+
1099
+ | [template] | The template to create. Valid templates are "leaf" and "season". |
1100
+ | [name] | The name to give the created template. For example, you can call @script/generate leaf Scorekeeper@ to create a leaf named Scorekeeper. |
1101
+
1102
+ | @--help, -h@ | Displays this usage information. |
1103
+ | @--vcs, -c@ | Add any created files or directories to the project's version control system. (Autodetects CVS, Git, and Subversion.) |
1104
+
1105
+ h3. <tt>autumn start</tt>
1106
+
1107
+ Runs Autumn from the command line. This script will not exit until all leaves
1108
+ have exited. You can set the @SEASON@ environment variable to override the
1109
+ season.
1110
+
1111
+ h2. Thread Safety
1112
+
1113
+ Autumn is a multi-threaded IRC client. When a message is received, a new thread
1114
+ is spawned to process the message. In this thread, the message will be parsed,
1115
+ and all listener hooks will be invoked, including your leaf's methods. The
1116
+ thread will terminate once the message has been fully processed and all methods
1117
+ invoked.
1118
+
1119
+ I have made every effort to ensure that @Autumn::Stem@ and @Autumn::Leaf@ are
1120
+ thread-safe, as well as other relevant support classes such as @Autumn::CTCP@.
1121
+ It is now in your hands to ensure your leaves are thread-safe! This basically
1122
+ means recognizing that, while your leaf is churning away at whatever command it
1123
+ received, things can and will change in the background. If your command requires
1124
+ your leaf to have operator privileges, write your code under the assumption that
1125
+ operator could be taken from your leaf in the middle of executing the command.
1126
+ Write data in critical blocks, use transactions in your database calls ... you
1127
+ know the deal. Don't assume things will be the same between one line of code and
1128
+ the next.
1129
+
1130
+ h2. Getting Ready for Deployment
1131
+
1132
+ There's only a few things you need to do once your leaf is ready to greet
1133
+ the Real World:
1134
+
1135
+ # Create a new production season. Configure your stems, leaves, and database
1136
+ as necessary for your production environment.
1137
+ # In <tt>config/global.yml</tt>, set the season to your production season.
1138
+ # If desired, in <tt>autumn start -D</tt>, set the -m option.
1139
+ This will spawn a monitor process that will relaunch Autumn if it crashes.
1140
+
1141
+ h2. Other Information
1142
+
1143
+ Please consult the "list of known bugs":http://github.com/RISCfuture/autumn/wikis/known-bugs
1144
+ and "version history":http://github.com/RISCfuture/autumn/wikis/version-history
1145
+ for more information.
1146
+
1147
+ *_Why do you require Facets?_, I hear you ask. Facets doesn't add any super
1148
+ awesome new features to Ruby like Daemons or DataMapper does. It does, however,
1149
+ improve code reuse, and I'm a big fan of that. Why should a million different
1150
+ Ruby projects all write the same @Symbol#to_proc@ method or the same
1151
+ @Hash#symbolize_keys@ method? I use Facets because that job has already been
1152
+ done, and staying DRY means staying DRY _between_ codebases, not just within
1153
+ them.