mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-12-23 19:22:45 +01:00
textwidth=70 reformatting along with some documentation fixes that I noticed
This commit is contained in:
parent
940a934f6e
commit
5deb99192e
@ -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.
|
||||
|
@ -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!
|
||||
|
33
docs/EXAMPLE
33
docs/EXAMPLE
@ -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.
|
||||
|
||||
|
67
docs/FAQ
67
docs/FAQ
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
70
docs/STYLE
70
docs/STYLE
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user