textwidth=70 reformatting along with some documentation fixes that I noticed

This commit is contained in:
James Vega 2004-02-19 16:06:16 +00:00
parent 940a934f6e
commit 5deb99192e
7 changed files with 271 additions and 262 deletions

View File

@ -1,107 +1,118 @@
Ok, some some explanation of the capabilities system is probably in order.
With most IRC bots (including the ones I've written myself prior to this one)
"what a user can do" is set in one of two ways. On the *really* simple bots,
each user has a numeric "level" and commands check to see if a user has a "high
enough level" to perform some operation. On bots that are slightly more
complicated, users have a list of "flags" whose meanings are hardcoded, and the
bot checks to see if a user possesses the necessary flag before performing some
operation. Both methods, IMO, are rather arbitrary, and force the user and the
programmer to be unduly confined to less expressive constructs.
Ok, some some explanation of the capabilities system is probably in
order. With most IRC bots (including the ones I've written myself
prior to this one) "what a user can do" is set in one of two ways. On
the *really* simple bots, each user has a numeric "level" and commands
check to see if a user has a "high enough level" to perform some
operation. On bots that are slightly more complicated, users have a
list of "flags" whose meanings are hardcoded, and the bot checks to
see if a user possesses the necessary flag before performing some
operation. Both methods, IMO, are rather arbitrary, and force the
user and the programmer to be unduly confined to less expressive
constructs.
This bot is different. Every user has a set of "capabilities" that is
consulted every time they give the bot a command. Commands, rather than
checking for a user level of 100, or checking if the user has an "o" flag, are
instead able to check if a user has the "owner" capability. At this point such
a difference might not seem revolutionary, but at least we can already tell
that this method is self-documenting, and easier for users and developers to
understand what's truly going on.
consulted every time they give the bot a command. Commands, rather
than checking for a user level of 100, or checking if the user has an
"o" flag, are instead able to check if a user has the "owner"
capability. At this point such a difference might not seem
revolutionary, but at least we can already tell that this method is
self-documenting, and easier for users and developers to understand
what's truly going on.
If that was all, well, the capability system would be "cool", but not many
people would say it was "awesome". But it *is* awesome! Several things are
happening behind the scene that make it awesome, and these are things that
couldn't happen if the bot was using numeric userlevels or single-character
flags. First, whenever a user issues the bot a command, the command dispatcher
checks to make sure the user doesn't have the "anticapability" for that
command. An anticapability is a capability that, instead of saying "what a
user can do", says what a user *cannot* do. It's formed rather simply by
adding a dash ("-") to the beginning of a capability; "rot13" is
a capability, and "-rot13" is an anticapability. Anyway, when a user issues
the bot a command, perhaps "calc" or "help", the bot first checks to make sure
the user doesn't have the "-calc" or the "-help" capabilities before even
considering responding to the user. So commands can be turned on or off on a
*per user* basis, offering finegrained control not often (if at all!) seen in
other bots.
If that was all, well, the capability system would be "cool", but not
many people would say it was "awesome". But it *is* awesome! Several
things are happening behind the scene that make it awesome, and these
are things that couldn't happen if the bot was using numeric
userlevels or single-character flags. First, whenever a user issues
the bot a command, the command dispatcher checks to make sure the user
doesn't have the "anticapability" for that command. An anticapability
is a capability that, instead of saying "what a user can do", says
what a user *cannot* do. It's formed rather simply by adding a dash
("-") to the beginning of a capability; "rot13" is a capability, and
"-rot13" is an anticapability. Anyway, when a user issues the bot a
command, perhaps "calc" or "help", the bot first checks to make sure
the user doesn't have the "-calc" or the "-help" capabilities before
even considering responding to the user. So commands can be turned on
or off on a *per user* basis, offering finegrained control not often
(if at all!) seen in other bots.
But that's not all! The capabilities system also supports *Channel*
capabilities, which are capabilities that only apply to a specific channel;
they're of the form "#channel.capability". Whenever a user issues a command to
the bot in a channel, the command dispatcher also checks to make sure the user
doesn't have the anticapability for that command *in that channel*, and if the
user does, the bot won't respond to the user in the channel. Thus now, in
addition to having the ability to turn individual commands on or off for an
individual user, we can now turn commands on or off for an individual user on
an individual channel!
capabilities, which are capabilities that only apply to a specific
channel; they're of the form "#channel,capability". Whenever a user
issues a command to the bot in a channel, the command dispatcher also
checks to make sure the user doesn't have the anticapability for that
command *in that channel*, and if the user does, the bot won't respond
to the user in the channel. Thus now, in addition to having the
ability to turn individual commands on or off for an individual user,
we can now turn commands on or off for an individual user on an
individual channel!
So when a user "foo" sends a command "bar" to the bot on channel "#baz", first
the bot checks to see if the user has the anticapability for the command by
itself, "-bar". If so, it returns right then and there, compltely ignoring the
fact that the user issued that command to it. If the user doesn't have that
anticapability, then the bot checks to see if the user issued the command over
a channel, and if so, checks to see if the user has the antichannelcapability
for that command, "#baz.-bar". If so, again, he returns right then and there
and doesn't even think about responding to the bot. If neither of these
anticapabilities are present, then the bot just responds to the user like
normal.
So when a user "foo" sends a command "bar" to the bot on channel
"#baz", first the bot checks to see if the user has the anticapability
for the command by itself, "-bar". If so, it returns right then and
there, compltely ignoring the fact that the user issued that command
to it. If the user doesn't have that anticapability, then the bot
checks to see if the user issued the command over a channel, and if
so, checks to see if the user has the antichannelcapability for that
command, "#baz,-bar". If so, again, he returns right then and there
and doesn't even think about responding to the bot. If neither of
these anticapabilities are present, then the bot just responds to the
user like normal.
From a programmatical perspective, capabilties are easy to use and flexible.
Any command can check if a user has any capability, even ones not thought of
when the bot was originally written. Commands/Callbacks can add their own
capabilities -- it's as easy as just checking for a capability and documenting
somewhere that a user needs that capability to do something.
From a programmatical perspective, capabilties are easy to use and
flexible. Any command can check if a user has any capability, even
ones not thought of when the bot was originally written.
Commands/Callbacks can add their own capabilities -- it's as easy as
just checking for a capability and documenting somewhere that a user
needs that capability to do something.
From an end-user perspective, capabilities remove a lot of the mystery and
esotery of bot control, in addition to giving the user absolutely finegrained
control over what users are allowed to do with the bot. Additionally, defaults
can be set by the end-user for both individual channels and for the bot as a
whole, letting an end-user set the policy he wants the bot to follow for users
that haven't yet registered in his user database.
It's really a revolution!
From an end-user perspective, capabilities remove a lot of the mystery
and esotery of bot control, in addition to giving the user absolutely
finegrained control over what users are allowed to do with the bot.
Additionally, defaults can be set by the end-user for both individual
channels and for the bot as a whole, letting an end-user set the
policy he wants the bot to follow for users that haven't yet
registered in his user database. It's really a revolution!
There are several default capabilities the bot uses. The most important of
these is the "owner" capability. This capability allows the person having it
to use *any* command. It's best to keep this capability reserved to people
who actually have access to the shell the bot is running on.
There are several default capabilities the bot uses. The most
important of these is the "owner" capability. This capability allows
the person having it to use *any* command. It's best to keep this
capability reserved to people who actually have access to the shell
the bot is running on.
There is also the "admin" capability for non-owners that are highly trusted
to administer the bot appropriately. They can do things such as change the
bot's nick, globally enable/disable commands, cause the bot to ignore a given
user, set the prefixchar, report bugs, etc. They generally cannot do
administration related to channels, which is reserved for people with the
next capability.
There is also the "admin" capability for non-owners that are highly
trusted to administer the bot appropriately. They can do things such
as change the bot's nick, globally enable/disable commands, cause the
bot to ignore a given user, set the prefixchar, report bugs, etc.
They generally cannot do administration related to channels, which is
reserved for people with the next capability.
People who are to administer channels with the bot should have the #channel.op
capability -- whatever channel they are to administrate, they should have that
channel capability for "op". For example, since I want inkedmn to be an
administrator in #supybot, I'll give him the #supybot.op capability. This is
in addition to his admin capability, since the admin capability doesn't give
the person having it control over channels. #channel.op is used for such
things as giving/receiving ops, kickbanning people, lobotomizing the bot,
ignoring users in the channel, and managing the channel capabilities. The
#channel.op capability is also basically the equivalent of the owner capability
for capabilities involving #channel -- basically anyone with the #channel.op
capability is considered to have all positive capabilities and no negative
capabilities for #channel.
People who are to administer channels with the bot should have the
#channel,op capability -- whatever channel they are to administrate,
they should have that channel capability for "op". For example, since
I want inkedmn to be an administrator in #supybot, I'll give him the
#supybot,op capability. This is in addition to his admin capability,
since the admin capability doesn't give the person having it control
over channels. #channel,op is used for such things as
giving/receiving ops, kickbanning people, lobotomizing the bot,
ignoring users in the channel, and managing the channel capabilities.
The #channel,op capability is also basically the equivalent of the
owner capability for capabilities involving #channel -- basically
anyone with the #channel,op capability is considered to have all
positive capabilities and no negative capabilities for #channel.
One other globally important capability exists: "trusted". This is a command
that basically says "This user can be trusted not to try and crash the bot."
It allows users to call commands like Math.icalc, which potentially could
cause the bot to begin a calculation that could potentially never return (a
calculation like 10**10**10**10). Another command that requires the trusted
capability is Utilties.re, which (due to the regular expression implementation
in Python (and any other language that uses NFA regular expressions, like
Perl or Ruby or Lua or ...) which can allow a regular expression to take
exponential time to process). Consider what would happen if the someone gave
the bot the command 're [strjoin "" s/./ [dict go] /] [dict go]'
One other globally important capability exists: "trusted". This is a
command that basically says "This user can be trusted not to try and
crash the bot." It allows users to call commands like Math.icalc,
which potentially could cause the bot to begin a calculation that
could potentially never return (a calculation like 10**10**10**10).
Another command that requires the trusted capability is Utilties.re,
which (due to the regular expression implementation in Python (and any
other language that uses NFA regular expressions, like Perl or Ruby or
Lua or ...) which can allow a regular expression to take exponential
time to process). Consider what would happen if the someone gave the
bot the command 're [strjoin "" s/./ [dict go] /] [dict go]'
Other plugins may require different capabilities; the Factoids plugin requires
#channel.factoids, the Topic plugin requires #channel.topic, etc.
Other plugins may require different capabilities; the Factoids plugin
requires #channel,factoids, the Topic plugin requires #channel,topic,
etc.

View File

@ -40,8 +40,8 @@ our example.
Using the Config plugin, you can list the values in a subgroup and get
or set any of the values anywhere in the configuration hierarchy. For
example, let's say you wanted to see what configuration values were
under the "supybot" (the base group) hierarchy. You would simply issue
this command:
under the "supybot" (the base group) hierarchy. You would simply
issue this command:
<jemfinch|lambda> @config list supybot
<supybot> jemfinch|lambda: nick, ident, user, server,
@ -80,25 +80,25 @@ modifying the configuration values. It's important to know that when
you provide the group argument to config list that you must always
provide the full name of the group. For example, "config list
commands" would be incorrect, even though we see "commands" in the
listing above. Remember, we just shorten the names by the group
we're listing so we can fit more such names in a single message. In
this case, that would be "supybot", so to list everything in
the commands subgroup of supybot, we do:
listing above. Remember, we just shorten the names by the group we're
listing so we can fit more such names in a single message. In this
case, that would be "supybot", so to list everything in the commands
subgroup of supybot, we do:
<jemfinch|lambda> @config list supybot.commands
<supybot> jemfinch|lambda: defaultPlugins
Okay, now that you've used the Config plugin to list configuration
variables, it's time that we start looking at individual variables
and their values.
variables, it's time that we start looking at individual variables and
their values.
The first (and perhaps most important) thing you should know about
each configuration variable is that they all have an associated help
string to tell you what they represent. So the first command we'll
cover is "config help". To see the help string for any value or
group, simply use the "config help" command. For example, to see
what this "supybot.prefixChars" configuration variable is all about,
we'd do this:
group, simply use the "config help" command. For example, to see what
this "supybot.prefixChars" configuration variable is all about, we'd
do this:
<jemfinch|lambda> @config help supybot.prefixChars
<supybot> jemfinch|lambda: Determines what prefix
@ -126,12 +126,11 @@ Now, check this out:
<jemfinch|lambda> $config supybot.prefixChars
<supybot> jemfinch|lambda: '@$'
Note that we used $ as our prefix character, and that the value of
the configuration variable changed. If I were to use the "flush"
command now, this change would be flushed to the registry file on
disk (this would also happen if I made the bot quit, or pressed
Ctrl-C in the terminal the bot was running in). Instead, I'll
revert the change:
Note that we used $ as our prefix character, and that the value of the
configuration variable changed. If I were to use the "flush" command
now, this change would be flushed to the registry file on disk (this
would also happen if I made the bot quit, or pressed Ctrl-C in the
terminal the bot was running in). Instead, I'll revert the change:
<jemfinch|lambda> $config supybot.prefixChars @
<supybot> jemfinch|lambda: The operation succeeded.
@ -153,9 +152,9 @@ simply say:
Simple, eh?
Now, let's say you want to find all configuration variables that
might be even remotely related to opping. For that, you'll want the
"config search" command. Check this out:
Now, let's say you want to find all configuration variables that might
be even remotely related to opping. For that, you'll want the "config
search" command. Check this out:
<jemfinch|lambda> @config search op
<supybot> jemfinch|lambda:
@ -174,16 +173,16 @@ there's no way for the bot to know what configuration variables it
registers.
Some people might like editing their registry file directly rather
than manipulating all these things through the bot. For those
people, we offer the "config reload" command, which reloads both
registry configuration and user/channel/ignore database
configuration. Just edit the interesting files and then give the bot
the "config reload" command and it'll work as expected. Do note,
however, that Supybot flushes his configuration files and databases
to disk every hour or so, and if this happens after you've edited
your configuration files but before you reload your changes, you
could lose the changes you made. To prevent this, set the
supybot.flush value to Off, and no automatic flushing will occur.
than manipulating all these things through the bot. For those people,
we offer the "config reload" command, which reloads both registry
configuration and user/channel/ignore database configuration. Just
edit the interesting files and then give the bot the "config reload"
command and it'll work as expected. Do note, however, that Supybot
flushes his configuration files and databases to disk every hour or
so, and if this happens after you've edited your configuration files
but before you reload your changes, you could lose the changes you
made. To prevent this, set the supybot.flush value to Off, and no
automatic flushing will occur.
Anyway, that's about it for configuration. Have fun, and enjoy your
configurable bot!

View File

@ -111,10 +111,10 @@ You'll probably want to change the copyright notice to be your name.
It wouldn't stick even if you kept my name, so you might as well :)
Describe what you want the plugin to do in the docstring. This is
used in supybot-wizard in order to explain to the user the purpose
of the module. It's also returned when someone asks the bot for help
for a given module (instead of help for a certain command). We'll
change this one to "Lots of stuff relating to random numbers."
used in supybot-wizard in order to explain to the user the purpose of
the module. It's also returned when someone asks the bot for help for
a given module (instead of help for a certain command). We'll change
this one to "Lots of stuff relating to random numbers."
Then there are the imports. The callbacks module is used (the class
you're given subclasses callbacks.Privmsg) but the privmsgs module
@ -176,8 +176,8 @@ And we save two lines of code and make our code a little more clear :)
Now that we have an RNG, we need some way to get random numbers. So
first, we'll add a command that simply gets the next random number and
gives it back to the user. It takes no arguments, of course (what
would you give it?). Here's the command, and I'll follow that with the
explanation of what each part means.
would you give it?). Here's the command, and I'll follow that with
the explanation of what each part means.
def random(self, irc, msg, args):
"""takes no arguments
@ -342,9 +342,9 @@ checking for missing arguments and whatnot so we don't have to.
The Random object we're using offers us a "sample" method that takes a
sequence and a number (we'll call it N) and returns a list of N items
taken randomly from the sequence. So I'll show you an example that
takes advantage of multiple arguments but doesn't use
privmsgs.getArgs (and thus has to handle its own errors if the number
of arguments isn't right). Here's the code:
takes advantage of multiple arguments but doesn't use privmsgs.getArgs
(and thus has to handle its own errors if the number of arguments
isn't right). Here's the code:
def sample(self, irc, msg, args):
"""<number of items> [<text> ...]
@ -373,12 +373,11 @@ than through getArgs. Since we already have the arguments in a list,
it doesn't make any sense to have privmsgs.getArgs smush them all
together into a big long string that we'll just have to re-split. But
we still want the nice error handling of privmsgs.getArgs. So what do
we do? We raise callbacks.ArgumentError! That's the secret juju
that privmsgs.getArgs is doing; now we're just doing it ourself.
Someone up our callchain knows how to handle it so a neat error
message is returned. So in this function, if .pop(0) fails, we
weren't given enough arguments and thus need to tell the user how to
call us.
we do? We raise callbacks.ArgumentError! That's the secret juju that
privmsgs.getArgs is doing; now we're just doing it ourself. Someone
up our callchain knows how to handle it so a neat error message is
returned. So in this function, if .pop(0) fails, we weren't given
enough arguments and thus need to tell the user how to call us.
So we have the args, we have the number, we do a simple call to
random.sample and then we do this funky utils.commaAndify to it.
@ -417,8 +416,8 @@ important, though, is the first thing you'll notice that's different:
the privmsg.getArgs call. Here we're offering a default argument in
case the user is too lazy to supply one (or just wants a nice,
standard six-sided die :)) privmsgs.getArgs supports that; we'll just
tell it that we don't *need* any arguments (via required=0) and that we
*might like* one argument (optional=1). If the user provides an
tell it that we don't *need* any arguments (via required=0) and that
we *might like* one argument (optional=1). If the user provides an
argument, we'll get it -- if they don't, we'll just get an empty
string. Hence the "if not n: n = 6", where we provide the default.

View File

@ -4,13 +4,12 @@ Q: Why does my bot not recognize me or tell me that I don't have the
A: Because you're not given it anything to recognize you from!
You'll need to identify with the bot ("help identify" to see how
that works) or add your hostmask to your user record ("help
addhostmask" to see how that works) for it to know that you're
you. You may wish to note that addhostmask can accept a password;
rather than identify, you can send the command "addhostmask
myOwnerUser [hostmask] myOwnerUserPassword" and the bot will add
your current hostmask to your owner user (of course, you should
change myOwnerUser and myOwnerUserPassword appropriately for your
bot).
addhostmask" to see how that works) for it to know that you're you.
You may wish to note that addhostmask can accept a password; rather
than identify, you can send the command "addhostmask myOwnerUser
[hostmask] myOwnerUserPassword" and the bot will add your current
hostmask to your owner user (of course, you should change
myOwnerUser and myOwnerUserPassword appropriately for your bot).
Q: How do I make my Supybot op my users?
@ -21,10 +20,10 @@ A: First, you'll have to make sure that your users register with the
Use the "channel addcapability" command to do this. After that,
your users should be able to use the "op" command to get ops.
If you want your users to be auto-opped when they join the
channel, you'll need to load the Enforcer plugin and turn its
autoOp configuration variable on. Use the "config" command to do
so. Here's an example of how to do these steps:
If you want your users to be auto-opped when they join the channel,
you'll need to load the Enforcer plugin and turn its autoOp
configuration variable on. Use the "config" command to do so.
Here's an example of how to do these steps:
<jemfinch|lambda> I'm going to make an example session for giving
you auto-ops, for our FAQ.
@ -60,12 +59,11 @@ Q: Can users with the "admin" capability change configuration
A: Currently, no. Since this is the first release of Supybot that
uses the registry, we wanted to stay on the conservative side and
require the "owner" capability for changing all
non-channel-related configuration variables. Feel free to make
your case to us as to why a certain configuration variable should
only require the "admin" capability instead of the "owner"
capability, and if we agree with you, we'll change it for the next
release.
require the "owner" capability for changing all non-channel-related
configuration variables. Feel free to make your case to us as to
why a certain configuration variable should only require the
"admin" capability instead of the "owner" capability, and if we
agree with you, we'll change it for the next release.
Q: How do I make my Supybot connect to multiple servers?
@ -75,10 +73,10 @@ A: You'll need to use the Relay plugin. As long as you don't call
channels (even if the bot is on the same channel on different
networks). In order to use the Relay plugin, you'll want to first
call the "relay start" command, followed by the "relay connect"
command. These commands are (unfortunately) not persistent at
this time, so you'll need to give them to the bot anytime you
start it up. We'll probably have this lack of persistence
rectified before the next release.
command. These commands are (unfortunately) not persistent at this
time, so you'll need to give them to the bot anytime you start it
up. We'll probably have this lack of persistence rectified before
the next release.
Q: Can Supybot do factoids?
@ -89,10 +87,10 @@ A: Supybot most certainly can! In fact, we offer two full-fledged
Factoids (written by jemfinch) is Supybot's original
factoids-related plugin. It offers full integration with Supybot's
nested commands as well as a complete 1:n key to factoid ratio,
with lookup by individual number. Factoids also uses
a channel-specific database instead of a global database, although
in the future it will likely be a configuration option whether to
use channel-specific or global databases for such plugins.
with lookup by individual number. Factoids also uses a
channel-specific database instead of a global database, although in
the future it will likely be a configuration option whether to use
channel-specific or global databases for such plugins.
MoobotFactoids (written by Strike) is much more full-featured,
offering users the ability to define factoids in a slightly more
@ -103,11 +101,10 @@ A: Supybot most certainly can! In fact, we offer two full-fledged
beginning)). If you're accustomed to Moobot's factoids or
Blootbot's factoids, then this is the Factoids plugin for you.
Unfortunately, due to the more natural definition syntax (required
to be compatible with Moobot) you can't define Factoids with
nested commands; you'll have to evaluate the command first and
then copy the result into your factoid definition. MoobotFactoids
uses a global database, so the factoids are the same for all
channels.
to be compatible with Moobot) you can't define Factoids with nested
commands; you'll have to evaluate the command first and then copy
the result into your factoid definition. MoobotFactoids uses a
global database, so the factoids are the same for all channels.
In the future, we plan to have a compatibility plugin for Infobot,
but as of present we've not yet written one.
@ -119,9 +116,9 @@ A: As of present, we have no automated way to do so. Strike has
written a few scripts for importing a Moobot database into
MoobotFactoids, however, so you'll want to talk to him about
helping you with that. We're certainly happy to help you convert
such databases; if you can provide us with such a database
exported to a flat file, we can probably do the rest of the work
to write a script that imports it into a database for one of our
such databases; if you can provide us with such a database exported
to a flat file, we can probably do the rest of the work to write a
script that imports it into a database for one of our
factoids-related plugins.
@ -142,8 +139,8 @@ A: Submit it on Sourceforge through our Sourceforge project page:
log entry). We'd also like to see the commands that caused the
bug, or happened around the time you saw the bug. If the bug
involved a database, we'd love to see the database. Remember, it's
always worse to send us too much information in a bug report than
too little.
always worse to send us too little information in a bug report than
too much.
Q: Karma doesn't seem to work for me.

View File

@ -28,15 +28,15 @@ like being asked many questions, just run supybot with no arguments
and it'll ask you only the questions necessary to run a bot.
So after running either of those two programs, you've got a nice
registry file handy. If you're not satisfied with your answers to
any of the questions you were asked, feel free to run the program
again until you're satisfied with all your answers. Once you're
satisfied, though, run the "supybot" program with the registry file
you created as an argument. This will start the bot; unless you
turned off logging to stdout, you'll see some nice log messages
describing what the bot is doing at any particular moment; it may
pause for a significant amount of time after saying "Connecting
to ..." while the server tries to check its ident.
registry file handy. If you're not satisfied with your answers to any
of the questions you were asked, feel free to run the program again
until you're satisfied with all your answers. Once you're satisfied,
though, run the "supybot" program with the registry file you created
as an argument. This will start the bot; unless you turned off
logging to stdout, you'll see some nice log messages describing what
the bot is doing at any particular moment; it may pause for a
significant amount of time after saying "Connecting to ..." while the
server tries to check its ident.
Ok, so let's assume your bot connected to the server fine and joined
the channels you told it to join. For now we'll assume you named your
@ -60,16 +60,14 @@ supybot: list Misc
Will list all the commands in the Misc plugin. If you want to see the
help for any command, just use the help command:
supybot: help help
supybot: help list
supybot: help load
supybot: help help supybot: help list supybot: help load
Sometimes more than one plugin will have a given command; for
instance, the "list" command exists in both the Misc and Config
plugins (both loaded by default). List, in this case, defaults to
the Misc plugin, but you may want to get the help for the list
command in the Config plugin. In that case, you'll want to give your
command like this:
plugins (both loaded by default). List, in this case, defaults to the
Misc plugin, but you may want to get the help for the list command in
the Config plugin. In that case, you'll want to give your command
like this:
supybot: help config list
@ -149,12 +147,12 @@ try is to look at the listing of configuration groups for the bot
chunk. When you invoke this command, you should see output like:
<supybot> nick, ident, user, server, password, channels, prefixChars,
defaultCapabilities, defaultAllow, defaultIgnore,
humanTimestampFormat, externalIP, bracketSyntax, pipeSyntax,
followIdentificationThroughNickChanges, alwaysJoinOnInvite,
showSimpleSyntax, maxHistoryLength, nickmods, throttleTime,
snarfThrottle, threadAllCommands, pingServer, pingInterval,
upkeepInterval, flush, (1 more message)
defaultCapabilities, defaultAllow, defaultIgnore,
humanTimestampFormat, externalIP, bracketSyntax, pipeSyntax,
followIdentificationThroughNickChanges, alwaysJoinOnInvite,
showSimpleSyntax, maxHistoryLength, nickmods, throttleTime,
snarfThrottle, threadAllCommands, pingServer, pingInterval,
upkeepInterval, flush, (1 more message)
Now, to see the rest of the output, simply give the command "more",
and it will show you the rest:

View File

@ -1,26 +1,26 @@
So here's a general *programming* introduction to what the different modules do
and what services they provide. It is, however, only an introduction. Read
the modules themselves for a much more detailed explanation :)
So here's a general *programming* introduction to what the different
modules do and what services they provide. It is, however, only an
introduction. Read the modules themselves for a much more detailed
explanation :)
fix.py: Stuff that Python should (but doesn't) include by default.
cdb.py: A constant database library, translated from C (and my O'Caml version)
More information available at http://cr.yp.to/cdb.html. Not
currently used since we switched to PySQLite.
cdb.py: A constant database library, translated from C (and my O'Caml
version) More information available at
http://cr.yp.to/cdb.html. Not currently used since we
switched to PySQLite.
ansi.py: Contains different ANSI color sequences.
Mostly used by the debug module.
debug.py: Functions for handling bugs and errors in a consistent manner
throughout the bot.
conf.py: The configuration file for the bot -- it sets a lot of
variables that other modules check for when they have
questions about what they need to do.
conf.py: The configuration file for the bot -- it sets a lot of variables that
other modules check for when they have questions about what they need
to do.
world.py: Just a dropping off place for some globals that need to be shared
among all the modules. It's obviously not used *a lot*, but some
things seem to fit better here than anywhere else.
world.py: Just a dropping off place for some globals that need to be
shared among all the modules. It's obviously not used *a
lot*, but some things seem to fit better here than anywhere
else.
template.py: A template used by setup.py to create customized runnable
Python scripts for individual bots.
@ -28,21 +28,22 @@ template.py: A template used by setup.py to create customized runnable
privmsgs.py: Basic stuff relating to callbacks.Privmsg, the base class
for most plugins.
callbacks.py: A few basic callbacks providing significant functionality.
You'll likely be inheriting from Privmsg quite a bit.
callbacks.py: A few basic callbacks providing significant
functionality. You'll likely be inheriting from Privmsg
quite a bit.
ircdb.py: The users and channels databases are here, as well as the
IrcUser and IrcChannel classes. Look here when you want to
restrict a command to only certain users.
irclib.py: Provides the most important class in the irclib, Irc. It represents
a connection to an IRC server, but it's entirely separate from the
network implementation. It's connected to the network (or whatever
else drives it) by a "driver" module which uses its feedMsg/takeMsg
functions.
irclib.py: Provides the most important class in the irclib, Irc. It
represents a connection to an IRC server, but it's entirely
separate from the network implementation. It's connected
to the network (or whatever else drives it) by a "driver"
module which uses its feedMsg/takeMsg functions.
drivers.py: The baseclass (IrcDriver) for various drivers to drive irclib.Irc
classes. Also, the driving mechanism.
drivers.py: The baseclass (IrcDriver) for various drivers to drive
irclib.Irc classes. Also, the driving mechanism.
asyncoreDrivers.py: The asyncore-based drivers for use with the bot.
@ -52,12 +53,12 @@ socketDrivers.py: The plain old socket-based drivers for use with the
twistedDrivers.py: The Twisted <http://www.twistedmatrix.com/> drivers
for use with the bot.
ircmsgs.py: The IrcMsg class (get to know it :)) and various functions for
making the creation of IrcMsgs easier.
ircmsgs.py: The IrcMsg class (get to know it :)) and various functions
for making the creation of IrcMsgs easier.
ircutils.py: Various utility functions for Irc -- read the module to see what
goodies are there :)
ircutils.py: Various utility functions for Irc -- read the module to
see what goodies are there :)
schedule.py: A schedule driver (which is automatically registered with the
drivers module) to run things at a particular time, or at
specified periods of time.
schedule.py: A schedule driver (which is automatically registered with
the drivers module) to run things at a particular time,
or at specified periods of time.

View File

@ -1,5 +1,5 @@
Read PEP 8 (Guido's Style Guide) and know that we use almost all the same style
guidelines.
Read PEP 8 (Guido's Style Guide) and know that we use almost all the
same style guidelines.
Maximum line length is 79 characters. 78 is a safer bet, though.
@ -10,29 +10,31 @@ They're just easier to type.
Triple double quotes (""") are always used for docstrings.
Spaces go around all operators (except around '=' in default arguments to
functions) and after all commas (unless doing so keeps a line within the 79
character limit).
Spaces go around all operators (except around '=' in default arguments
to functions) and after all commas (unless doing so keeps a line
within the 79 character limit).
Class names are StudlyCaps. Method and function names are camelCaps
(StudlyCaps with an initial lowercase letter). If variable and attribute
names can maintain readability without being camelCaps, then they should be
entirely in lowercase, otherwise they should also use camelCaps. Plugin names
are StudlyCaps.
(StudlyCaps with an initial lowercase letter). If variable and
attribute names can maintain readability without being camelCaps, then
they should be entirely in lowercase, otherwise they should also use
camelCaps. Plugin names are StudlyCaps.
Imports should always happen at the top of the module, one import per line
(so if imports need to be added or removed later, it can be done easily).
Imports should always happen at the top of the module, one import per
line (so if imports need to be added or removed later, it can be done
easily).
A blank line should be between all consecutive method declarations in a
class definition. Two blank lines should be between all consecutive class
definitions in a file. Comments are even better than blank lines for
separating classes.
A blank line should be between all consecutive method declarations in
a class definition. Two blank lines should be between all consecutive
class definitions in a file. Comments are even better than blank
lines for separating classes.
Database filenames should generally begin with the name of the plugin and the
extension should be 'db'. baseplugin.DBHandler does this already.
Database filenames should generally begin with the name of the plugin
and the extension should be 'db'. baseplugin.DBHandler does this
already.
Whenever creating a file descriptor or socket, keep a reference around and be
sure to close it. There should be no code like this:
Whenever creating a file descriptor or socket, keep a reference around
and be sure to close it. There should be no code like this:
s = urllib2.urlopen('url').read()
Instead, do this:
fd = urllib2.urlopen('url')
@ -44,31 +46,33 @@ All plugins should include a docstring decsribing what the plugin
does. This docstring will be returned when the user wants help on a
plugin.
Method docstrings in classes deriving from callbacks.Privmsg should include an
argument list as their first line, and after that a blank line followed by
a longer description of what the command does. The argument list is used by
the 'syntax' command, and the longer description is used by the 'help' command.
Method docstrings in classes deriving from callbacks.Privmsg should
include an argument list as their first line, and after that a blank
line followed by a longer description of what the command does. The
argument list is used by the 'syntax' command, and the longer
description is used by the 'help' command.
Whenever joining more than two strings, use string interpolation, not addition:
Whenever joining more than two strings, use string interpolation, not
addition:
s = x + y + z # Bad.
s = '%s%s%s' % (x, y, z) # Good.
s = ''.join([x, y, z]) # Best, but not as general.
This has to do with efficiency; the intermediate string x+y is made (and thus
copied) before x+y+z is made, so it's less efficient.
This has to do with efficiency; the intermediate string x+y is made
(and thus copied) before x+y+z is made, so it's less efficient.
When writing strings that have formatting characters in them, don't
use anything but %s unless you absolutely must. In particular, %d
should never be used, it's less general than %s and serves no useful
purpose.
Use the debug module to its fullest; when you need to print some values to
debug, use debug.printf to do so, and leave those print statements in the code
(commented out) so they can later be re-enabled. Remember that once
code is buggy, it tends to have more bugs, and you'll probably need those print
statements again.
Use the log module to its fullest; when you need to print some values
to debug, use self.log.debug to do so, and leave those print
statements in the code (commented out) so they can later be
re-enabled. Remember that once code is buggy, it tends to have more
bugs, and you'll probably need those print statements again.
SQL table names should be all-lowercase and include underscores to separate
words. This is because SQL itself is case-insensitive.
SQL table names should be all-lowercase and include underscores to
separate words. This is because SQL itself is case-insensitive.
SQL statements in code should put SQL words in ALL CAPS:
SELECT quote FROM quotes ORDER BY random() LIMIT 1