Swapped the argument order for utils.{pluralize,nItems}

This commit is contained in:
Jeremy Fincher 2003-12-12 15:41:33 +00:00
parent f4f91bcdb0
commit 42ce8c33a6
23 changed files with 149 additions and 133 deletions

View File

@ -1,14 +1,17 @@
* Added Lookup.search * Added Lookup.search
* Updated Todo.remove to allow removing multiple taskids * Updated Todo.remove to allow removing multiple taskids
* Added Topic.reorder, a new command for reordering the topics in a * Added Topic.reorder, a new command for reordering the topics in a
specific manner. specific manner.
* Added Http.extension, a new command to retrieve file extension in * Added Topic.list, a new command for listing the topics in a
channel (mostly in order to help out with Topic.reorder :))
* Added Http.extension, a new command to retrieve file extension in
formation from filext.com. formation from filext.com.
* Updated Relay.whois to include a user's away status and identified * Updated Relay.whois to include a user's away status and identified
state, if the server supports it. state, if the server supports it.
2003-12-6 Jeremy Fincher <jemfinch@supybot.org> 2003-12-6 Jeremy Fincher <jemfinch@supybot.org>

View File

@ -151,7 +151,7 @@ def makeNewAlias(name, alias):
f = types.FunctionType(f.func_code, f.func_globals, f = types.FunctionType(f.func_code, f.func_globals,
name, closure=f.func_closure) name, closure=f.func_closure)
f.__doc__ ='<an alias, %s>\n\nAlias for %r' % \ f.__doc__ ='<an alias, %s>\n\nAlias for %r' % \
(utils.nItems(biggestDollar, 'argument'), alias) (utils.nItems('argument', biggestDollar), alias)
return f return f

View File

@ -432,21 +432,21 @@ class ChannelDB(plugins.ChannelDBHandler,
'%s has joined %s, parted %s, quit %s, kicked someone %s, '\ '%s has joined %s, parted %s, quit %s, kicked someone %s, '\
'been kicked %s, changed the topic %s, ' \ 'been kicked %s, changed the topic %s, ' \
'and changed the mode %s.' % \ 'and changed the mode %s.' % \
(name, utils.nItems(values.msgs, 'message'), (name, utils.nItems('message', values.msgs),
utils.nItems(values.chars, 'character'), utils.nItems('character', values.chars),
utils.nItems(values.words, 'word'), utils.nItems('word', values.words),
utils.nItems(values.smileys, 'smiley'), utils.nItems('smiley', values.smileys),
utils.nItems(values.frowns, 'frown'), utils.nItems('frown', values.frowns),
values.actions, values.actions == 1 and 'was an ACTION. ' values.actions, values.actions == 1 and 'was an ACTION. '
or 'were ACTIONs. ', or 'were ACTIONs. ',
name, name,
utils.nItems(values.joins, 'time'), utils.nItems('time', values.joins),
utils.nItems(values.parts, 'time'), utils.nItems('time', values.parts),
utils.nItems(values.quits, 'time'), utils.nItems('time', values.quits),
utils.nItems(values.kicks, 'time'), utils.nItems('time', values.kicks),
utils.nItems(values.kicked, 'time'), utils.nItems('time', values.kicked),
utils.nItems(values.topics, 'time'), utils.nItems('time', values.topics),
utils.nItems(values.modes, 'time')) utils.nItems('time', values.modes))
irc.reply(msg, s) irc.reply(msg, s)
def channelstats(self, irc, msg, args): def channelstats(self, irc, msg, args):
@ -538,7 +538,7 @@ class ChannelDB(plugins.ChannelDBHandler,
irc.error(msg, '%s has never said %r.' % (user, word)) irc.error(msg, '%s has never said %r.' % (user, word))
return return
count = int(cursor.fetchone()[0]) count = int(cursor.fetchone()[0])
s = '%s has said %r %s.' % (user,word,utils.nItems(count, 'time')) s = '%s has said %r %s.' % (user,word,utils.nItems('time', count))
irc.reply(msg, s) irc.reply(msg, s)
else: else:
# Figure out if we got a user or a word # Figure out if we got a user or a word
@ -594,9 +594,9 @@ class ChannelDB(plugins.ChannelDBHandler,
word) word)
total = int(cursor.fetchone()[0]) total = int(cursor.fetchone()[0])
ers = '%rer' % word ers = '%rer' % word
ret = 'Top %s ' % utils.nItems(numResultsShown, ers) ret = 'Top %s ' % utils.nItems(ers, numResultsShown)
ret += '(out of a total of %s seen):' % \ ret += '(out of a total of %s seen):' % \
utils.nItems(total, repr(word)) utils.nItems(repr(word), total)
L = [] L = []
for (count, id) in results[:numResultsShown]: for (count, id) in results[:numResultsShown]:
username = ircdb.users.getUser(id).name username = ircdb.users.getUser(id).name
@ -607,7 +607,7 @@ class ChannelDB(plugins.ChannelDBHandler,
for (_, userId) in results: for (_, userId) in results:
if userId == id: if userId == id:
s = 'You are ranked %s out of %s.' % \ s = 'You are ranked %s out of %s.' % \
(rank, utils.nItems(len(results), ers)) (rank, utils.nItems(ers, len(results)))
break break
else: else:
rank += 1 rank += 1

View File

@ -318,7 +318,7 @@ class Factoids(plugins.ChannelDBHandler, callbacks.Privmsg):
factoids = '; '.join(L) factoids = '; '.join(L)
s = 'Key %r is %s and has %s associated with it: %s' % \ s = 'Key %r is %s and has %s associated with it: %s' % \
(key, locked and 'locked' or 'not locked', (key, locked and 'locked' or 'not locked',
utils.nItems(counter, 'factoid'), factoids) utils.nItems('factoid', counter), factoids)
irc.reply(msg, s) irc.reply(msg, s)
def change(self, irc, msg, args): def change(self, irc, msg, args):

View File

@ -259,7 +259,7 @@ class FunDB(callbacks.Privmsg, configurable.Mixin, plugins.ChannelDBHandler):
cursor.execute(sql) cursor.execute(sql)
total = int(cursor.fetchone()[0]) total = int(cursor.fetchone()[0])
irc.reply(msg, 'There %s currently %s in my database.' % irc.reply(msg, 'There %s currently %s in my database.' %
(utils.be(total), utils.nItems(total, table))) (utils.be(total), utils.nItems(table, total)))
def get(self, irc, msg, args): def get(self, irc, msg, args):
"""[<channel>] <lart|excuse|insult|praise> <id> """[<channel>] <lart|excuse|insult|praise> <id>

View File

@ -140,18 +140,18 @@ class Gameknot(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
'and a record of %s, %s, and %s ' \ 'and a record of %s, %s, and %s ' \
'(win/loss/draw percentage: %.2f%%/%.2f%%/%.2f%%). %s' % \ '(win/loss/draw percentage: %.2f%%/%.2f%%/%.2f%%). %s' % \
(name, team, rating, games, (name, team, rating, games,
utils.nItems(w, 'win'), utils.nItems('win', w),
utils.nItems(l, 'loss'), utils.nItems('loss', l),
utils.nItems(d, 'draw'), utils.nItems('draw', d),
wp, lp, dp, seen) wp, lp, dp, seen)
else: else:
s = '%s is rated %s and has %s ' \ s = '%s is rated %s and has %s ' \
'and a record of %s, %s, and %s ' \ 'and a record of %s, %s, and %s ' \
'(win/loss/draw percentage: %.2f%%/%.2f%%/%.2f%%). %s' % \ '(win/loss/draw percentage: %.2f%%/%.2f%%/%.2f%%). %s' % \
(name, rating, games, (name, rating, games,
utils.nItems(w, 'win'), utils.nItems('win', w),
utils.nItems(l, 'loss'), utils.nItems('loss', l),
utils.nItems(d, 'draw'), utils.nItems('draw', d),
wp, lp, dp, seen) wp, lp, dp, seen)
return s return s
except AttributeError: except AttributeError:

View File

@ -153,7 +153,7 @@ class Google(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
def formatData(self, data): def formatData(self, data):
if isinstance(data, basestring): if isinstance(data, basestring):
return data return data
time = 'Search took %s seconds: ' % data.meta.searchTime time = 'Search took %s seconds' % data.meta.searchTime
results = [] results = []
for result in data.results: for result in data.results:
title = utils.htmlToText(result.title.encode('utf-8')) title = utils.htmlToText(result.title.encode('utf-8'))
@ -163,9 +163,9 @@ class Google(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
else: else:
results.append(url) results.append(url)
if not results: if not results:
return 'No matches found %s' % time return 'No matches found (%s)' % time
else: else:
return '%s %s' % (time, '; '.join(results)) return '%s: %s' % (time, '; '.join(results))
def licensekey(self, irc, msg, args): def licensekey(self, irc, msg, args):
"""<key> """<key>

View File

@ -124,11 +124,10 @@ class Karma(callbacks.PrivmsgCommandAndRegexp,
if self.configurables.get('simple-output', channel): if self.configurables.get('simple-output', channel):
s = '%s: %s' % (name, total) s = '%s: %s' % (name, total)
else: else:
s = 'Karma for %r has been increased %s %s ' \ s = 'Karma for %r has been increased %s ' \
'and decreased %s %s for a total karma of %s.' % \ 'and decreased %s for a total karma of %s.' % \
(name, added, utils.pluralize(added, 'time'), (name, utils.nItems('time', added),
subtracted, utils.pluralize(subtracted, 'time'), utils.nItems('time', subtracted), total)
total)
irc.reply(msg, s) irc.reply(msg, s)
elif len(args) > 1: elif len(args) > 1:
normalizedArgs = sets.Set(imap(str.lower, args)) normalizedArgs = sets.Set(imap(str.lower, args))

View File

@ -435,7 +435,7 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
last_at = time.strftime(conf.humanTimestampFormat, last_at = time.strftime(conf.humanTimestampFormat,
time.localtime(int(last_requested_at))) time.localtime(int(last_requested_at)))
req_count = requested_count req_count = requested_count
times_str = utils.nItems(requested_count, 'time') times_str = utils.nItems('time', requested_count)
s += " Last requested by %s on %s, requested %s." % \ s += " Last requested by %s on %s, requested %s." % \
(last_by, last_at, times_str) (last_by, last_at, times_str)
# Last, locked info # Last, locked info
@ -538,14 +538,14 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
L = ['%s (%s)' % (ircdb.users.getUser(t[0]).name, int(t[1])) L = ['%s (%s)' % (ircdb.users.getUser(t[0]).name, int(t[1]))
for t in cursor.fetchall()] for t in cursor.fetchall()]
return 'Most prolific %s: %s' % \ return 'Most prolific %s: %s' % \
(utils.pluralize(len(L), 'author'), utils.commaAndify(L)) (utils.pluralize('author', len(L)), utils.commaAndify(L))
def _mostRecent(self, cursor, limit): def _mostRecent(self, cursor, limit):
cursor.execute("""SELECT key FROM factoids cursor.execute("""SELECT key FROM factoids
ORDER by created_at DESC LIMIT %s""", limit) ORDER by created_at DESC LIMIT %s""", limit)
L = [repr(t[0]) for t in cursor.fetchall()] L = [repr(t[0]) for t in cursor.fetchall()]
return '%s: %s' % \ return '%s: %s' % \
(utils.nItems(len(L), 'factoid', between='latest'), (utils.nItems('factoid', len(L), between='latest'),
utils.commaAndify(L)) utils.commaAndify(L))
def _mostPopular(self, cursor, limit): def _mostPopular(self, cursor, limit):
@ -556,7 +556,7 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
raise self.MostException, 'No factoids have been requested.' raise self.MostException, 'No factoids have been requested.'
L = ['%r (%s)' % (t[0], t[1]) for t in cursor.fetchall()] L = ['%r (%s)' % (t[0], t[1]) for t in cursor.fetchall()]
return 'Top %s: %s' % \ return 'Top %s: %s' % \
(utils.nItems(len(L), 'factoid', between='requested'), (utils.nItems('factoid', len(L), between='requested'),
utils.commaAndify(L)) utils.commaAndify(L))
def listauth(self, irc, msg, args): def listauth(self, irc, msg, args):

View File

@ -64,7 +64,7 @@ class Movies(callbacks.Privmsg):
'It\'s been rated %s out of 10. ' \ 'It\'s been rated %s out of 10. ' \
'More information is available at <%s>' % \ 'More information is available at <%s>' % \
(title, movie.year(), genres, (title, movie.year(), genres,
utils.pluralize(len(movie.genres()), 'genre'), utils.pluralize('genre', len(movie.genres())),
movie.rating(), movie.url) movie.rating(), movie.url)
return s return s

View File

@ -114,7 +114,7 @@ class Note(callbacks.Privmsg):
unread = int(cursor.fetchone()[0]) unread = int(cursor.fetchone()[0])
s = 'You have %s; ' \ s = 'You have %s; ' \
'%s that I haven\'t told you about before now..' % \ '%s that I haven\'t told you about before now..' % \
(utils.nItems(unread, 'note', 'unread'), unnotified) (utils.nItems('note', unread, 'unread'), unnotified)
irc.queueMsg(ircmsgs.privmsg(msg.nick, s)) irc.queueMsg(ircmsgs.privmsg(msg.nick, s))
cursor.execute("""UPDATE notes SET notified=1 cursor.execute("""UPDATE notes SET notified=1
WHERE notes.to_id=%s""", id) WHERE notes.to_id=%s""", id)

View File

@ -110,8 +110,8 @@ class Quotes(plugins.ChannelDBHandler, callbacks.Privmsg):
maxid = int(cursor.fetchone()[0]) maxid = int(cursor.fetchone()[0])
if maxid is None: if maxid is None:
maxid = 0 maxid = 0
QUOTE = utils.pluralize(maxid, 'quote') s = 'There %s %s in my database.' % \
s = 'There %s %s %s in my database.' % (utils.be(maxid), maxid, QUOTE) (utils.be(maxid), utils.nItems('quote', maxid))
irc.reply(msg, s) irc.reply(msg, s)
def get(self, irc, msg, args): def get(self, irc, msg, args):

View File

@ -176,7 +176,7 @@ class Status(callbacks.Privmsg):
'seconds of CPU time. Out of %s I have %s active.' % 'seconds of CPU time. Out of %s I have %s active.' %
(user, system, user + system, (user, system, user + system,
childUser, childSystem, childUser + childSystem, childUser, childSystem, childUser + childSystem,
utils.nItems(world.threadsSpawned, 'thread', 'spawned'), utils.nItems('thread', world.threadsSpawned, 'spawned'),
activeThreads)) activeThreads))
mem = None mem = None
pid = os.getpid() pid = os.getpid()
@ -211,9 +211,9 @@ class Status(callbacks.Privmsg):
attr == callbacks.canonicalName(attr): attr == callbacks.canonicalName(attr):
commands += 1 commands += 1
s = 'I offer a total of %s in %s. I have processed %s.' % \ s = 'I offer a total of %s in %s. I have processed %s.' % \
(utils.nItems(commands, 'command'), (utils.nItems('command', commands),
utils.nItems(callbacksPrivmsg, 'plugin', 'command-based'), utils.nItems('plugin', callbacksPrivmsg, 'command-based'),
utils.nItems(world.commandsProcessed, 'command')) utils.nItems('command', world.commandsProcessed))
irc.reply(msg, s) irc.reply(msg, s)
def commands(self, irc, msg, args): def commands(self, irc, msg, args):

View File

@ -247,20 +247,18 @@ class Todo(callbacks.Privmsg):
_sqlTrans = string.maketrans('*?', '%_') _sqlTrans = string.maketrans('*?', '%_')
def search(self, irc, msg, args): def search(self, irc, msg, args):
"""[--{regexp,exact}=<value>] [<glob>] """[--{regexp}=<value>] [<glob>]
Searches the keyspace for tasks matching <glob>. If --regexp is given, Searches the todos for tasks matching <glob>. If --regexp is given,
its associated value is taken as a regexp and matched against the its associated value is taken as a regexp and matched against the
tasks; if --exact is given, its associated value is taken as an exact tasks.
string to match against the tasks.
""" """
try: try:
id = ircdb.users.getUserId(msg.prefix) id = ircdb.users.getUserId(msg.prefix)
except KeyError: except KeyError:
irc.error(msg, conf.replyNotRegistered) irc.error(msg, conf.replyNotRegistered)
return return
(optlist, rest) = getopt.getopt(args, '', ['regexp='])
(optlist, rest) = getopt.getopt(args, '', ['regexp=', 'exact='])
if not optlist and not rest: if not optlist and not rest:
raise callbacks.ArgumentError raise callbacks.ArgumentError
db = self.dbHandler.getDb() db = self.dbHandler.getDb()
@ -268,10 +266,7 @@ class Todo(callbacks.Privmsg):
formats = [] formats = []
predicateName = 'p' predicateName = 'p'
for (option, arg) in optlist: for (option, arg) in optlist:
if option == '--exact': if option == '--regexp':
criteria.append('task LIKE %s')
formats.append('%' + arg + '%')
elif option == '--regexp':
criteria.append('%s(task)' % predicateName) criteria.append('%s(task)' % predicateName)
try: try:
r = utils.perlReToPythonRe(arg) r = utils.perlReToPythonRe(arg)

View File

@ -76,6 +76,13 @@ class Topic(callbacks.Privmsg, configurable.Mixin):
separator = self.configurables.get('separator', channel) separator = self.configurables.get('separator', channel)
return separator.join(topics) return separator.join(topics)
def _unformatTopic(self, topic, channel):
m = self.topicUnformatter.match(topic)
if m:
return (m.group(1), m.group(2))
else:
return (topic, '')
def add(self, irc, msg, args, channel): def add(self, irc, msg, args, channel):
"""[<channel>] <topic> """[<channel>] <topic>
@ -168,6 +175,22 @@ class Topic(callbacks.Privmsg, configurable.Mixin):
irc.error(msg, 'There are no topics to reorder.') irc.error(msg, 'There are no topics to reorder.')
reorder = privmsgs.checkChannelCapability(reorder, 'topic') reorder = privmsgs.checkChannelCapability(reorder, 'topic')
def list(self, irc, msg, args, channel):
"""[<channel>] <number>
Returns a list of the topics in <channel>, prefixed by their indexes.
Mostly useful for topic reordering. <channel> is only necessary if the
message isn't sent in the channel itself.
"""
topics = self._splitTopic(irc.state.getTopic(channel), channel)
L = []
for (i, t) in enumerate(topics):
(t, _) = self._unformatTopic(t, channel)
L.append('%s: %s' % (i+1, utils.ellipsisify(t, 30)))
s = utils.commaAndify(L)
irc.reply(msg, s)
list = privmsgs.channel(list)
def get(self, irc, msg, args, channel): def get(self, irc, msg, args, channel):
"""[<channel>] <number> """[<channel>] <number>
@ -189,11 +212,7 @@ class Topic(callbacks.Privmsg, configurable.Mixin):
topics = self._splitTopic(irc.state.getTopic(channel), channel) topics = self._splitTopic(irc.state.getTopic(channel), channel)
if topics: if topics:
try: try:
match = self.topicUnformatter.match(topics[number]) irc.reply(msg, self._unformatTopic(topics[number], channel)[0])
if match:
irc.reply(msg, match.group(1))
else:
irc.reply(msg, topics[number])
except IndexError: except IndexError:
irc.error(msg, 'That\'s not a valid topic.') irc.error(msg, 'That\'s not a valid topic.')
else: else:
@ -233,11 +252,7 @@ class Topic(callbacks.Privmsg, configurable.Mixin):
irc.error(msg, 'There are no topics to change.') irc.error(msg, 'There are no topics to change.')
return return
topic = topics.pop(number) topic = topics.pop(number)
match = self.topicUnformatter.match(topic) (topic, name) = self._unformatTopic(topic, channel)
if match is None:
name = ''
else:
(topic, name) = match.groups()
try: try:
senderName = ircdb.users.getUser(msg.prefix).name senderName = ircdb.users.getUser(msg.prefix).name
except KeyError: except KeyError:
@ -279,11 +294,7 @@ class Topic(callbacks.Privmsg, configurable.Mixin):
except IndexError: except IndexError:
irc.error(msg, 'That\'s not a valid topic number.') irc.error(msg, 'That\'s not a valid topic number.')
return return
match = self.topicUnformatter.match(topic) (topic, name) = self._unformatTopic(topic, channel)
if match is None:
name = ''
else:
(topic, name) = match.groups()
try: try:
username = ircdb.users.getUser(msg.prefix).name username = ircdb.users.getUser(msg.prefix).name
except KeyError: except KeyError:

View File

@ -318,7 +318,7 @@ class Misc(callbacks.Privmsg):
chunk = L.pop() chunk = L.pop()
if L: if L:
chunk += ' \x02(%s)\x0F' % \ chunk += ' \x02(%s)\x0F' % \
utils.nItems(len(L), 'message', 'more') utils.nItems('message', len(L), 'more')
irc.reply(msg, chunk, True) irc.reply(msg, chunk, True)
except KeyError: except KeyError:
irc.error(msg, 'You haven\'t asked me a command!') irc.error(msg, 'You haven\'t asked me a command!')

View File

@ -337,7 +337,7 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
if gc.garbage: if gc.garbage:
irc.reply(msg, 'Garbage! %r' % gc.garbage) irc.reply(msg, 'Garbage! %r' % gc.garbage)
else: else:
irc.reply(msg, '%s collected.' % utils.nItems(collected, 'object')) irc.reply(msg, '%s collected.' % utils.nItems('object', collected))
def set(self, irc, msg, args): def set(self, irc, msg, args):
"""<name> <value> """<name> <value>

View File

@ -445,8 +445,9 @@ class IrcObjectProxy:
msgs.reverse() msgs.reverse()
response = msgs.pop() response = msgs.pop()
if msgs: if msgs:
response = ircutils.bold('(%s)') n = ircutils.bold('(%s)')
response %= utils.nItems(len(msgs), 'message', 'more') n %= utils.nItems('message', len(msgs), 'more')
response = '%s %s' % (response, n)
mask = msg.prefix.split('!', 1)[1] mask = msg.prefix.split('!', 1)[1]
Privmsg._mores[mask] = msgs Privmsg._mores[mask] = msgs
private = self.private or not ircutils.isChannel(msg.args[0]) private = self.private or not ircutils.isChannel(msg.args[0])

View File

@ -124,31 +124,31 @@ def timeElapsed(elapsed, leadingZeroes=False, years=True, weeks=True,
if leadingZeroes or yrs: if leadingZeroes or yrs:
if yrs: if yrs:
leadingZeroes = True leadingZeroes = True
ret.append(nItems(yrs, 'year')) ret.append(nItems('year', yrs))
if weeks: if weeks:
wks, elapsed = elapsed // 604800, elapsed % 604800 wks, elapsed = elapsed // 604800, elapsed % 604800
if leadingZeroes or wks: if leadingZeroes or wks:
if wks: if wks:
leadingZeroes = True leadingZeroes = True
ret.append(nItems(wks, 'week')) ret.append(nItems('week', wks))
if days: if days:
ds, elapsed = elapsed // 86400, elapsed % 86400 ds, elapsed = elapsed // 86400, elapsed % 86400
if leadingZeroes or ds: if leadingZeroes or ds:
if ds: if ds:
leadingZeroes = True leadingZeroes = True
ret.append(nItems(ds, 'day')) ret.append(nItems('day', ds))
if hours: if hours:
hrs, elapsed = elapsed // 3600, elapsed % 3600 hrs, elapsed = elapsed // 3600, elapsed % 3600
if leadingZeroes or hrs: if leadingZeroes or hrs:
if hrs: if hrs:
leadingZeroes = True leadingZeroes = True
ret.append(nItems(hrs, 'hour')) ret.append(nItems('hour', hrs))
if minutes or seconds: if minutes or seconds:
mins, secs = elapsed // 60, elapsed % 60 mins, secs = elapsed // 60, elapsed % 60
if leadingZeroes or mins: if leadingZeroes or mins:
ret.append(nItems(mins, 'minute')) ret.append(nItems('minute', mins))
if seconds: if seconds:
ret.append(nItems(secs, 'second')) ret.append(nItems('second', secs))
if len(ret) == 0: if len(ret) == 0:
raise ValueError, 'Time difference not great enough to be noted.' raise ValueError, 'Time difference not great enough to be noted.'
if len(ret) == 1: if len(ret) == 1:
@ -317,7 +317,7 @@ def _matchCase(s1, s2):
L[i] = char.upper() L[i] = char.upper()
return ''.join(L) return ''.join(L)
def pluralize(i, s): def pluralize(s, i=2):
"""Returns the plural of s based on its number i. Put any exceptions to """Returns the plural of s based on its number i. Put any exceptions to
the general English rule of appending 's' in the plurals dictionary. the general English rule of appending 's' in the plurals dictionary.
""" """
@ -345,22 +345,22 @@ def depluralize(s):
else: else:
return s # Don't know what to do. return s # Don't know what to do.
def nItems(n, item, between=None): def nItems(item, n, between=None):
"""Works like this: """Works like this:
>>> nItems(1, 'clock') >>> nItems('clock', 1)
'1 clock' '1 clock'
>>> nItems(10, 'clock') >>> nItems('clock', 10)
'10 clocks' '10 clocks'
>>> nItems(10, 'clock', between='grandfather') >>> nItems('clock', 10, between='grandfather')
'10 grandfather clocks' '10 grandfather clocks'
""" """
if between is None: if between is None:
return '%s %s' % (n, pluralize(n, item)) return '%s %s' % (n, pluralize(item, n))
else: else:
return '%s %s %s' % (n, between, pluralize(n, item)) return '%s %s %s' % (n, between, pluralize(item, n))
def be(i): def be(i):
"""Returns the form of the verb 'to be' based on the number i.""" """Returns the form of the verb 'to be' based on the number i."""

View File

@ -113,8 +113,6 @@ if sqlite is not None:
self.assertRegexp('todo search task*', self.assertRegexp('todo search task*',
'#1: task number one and #2: task number two is ' '#1: task number one and #2: task number two is '
'much longer than task number...') 'much longer than task number...')
self.assertRegexp('todo search --exact "task number one"',
'#1: task number one')
self.assertError('todo search --regexp s/bustedregex') self.assertError('todo search --regexp s/bustedregex')
self.assertRegexp('todo search --regexp m/task/', self.assertRegexp('todo search --regexp m/task/',
'#1: task number one and #2: task number two is ' '#1: task number one and #2: task number two is '

View File

@ -104,5 +104,14 @@ class TopicTestCase(ChannelPluginTestCase, PluginDocumentation):
_ = self.getMsg('topic remove 1') _ = self.getMsg('topic remove 1')
self.assertError('topic reorder 0') self.assertError('topic reorder 0')
def testList(self):
_ = self.getMsg('topic add foo')
self.assertResponse('topic list', '1: foo')
_ = self.getMsg('topic add bar')
self.assertResponse('topic list', '1: foo and 2: bar')
_ = self.getMsg('topic add baz')
self.assertResponse('topic list', '1: foo, 2: bar, and 3: baz')
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

View File

@ -37,14 +37,14 @@ import utils
class UtilsTest(unittest.TestCase): class UtilsTest(unittest.TestCase):
def testPluralize(self): def testPluralize(self):
f = utils.pluralize f = utils.pluralize
self.assertEqual('bike', f(1, 'bike')) self.assertEqual('bike', f('bike', 1))
self.assertEqual('bikes', f(2, 'bike')) self.assertEqual('bikes', f('bike', 2))
self.assertEqual('BIKE', f(1, 'BIKE')) self.assertEqual('BIKE', f('BIKE', 1))
self.assertEqual('BIKES', f(2, 'BIKE')) self.assertEqual('BIKES', f('BIKE', 2))
self.assertEqual('match', f(1, 'match')) self.assertEqual('match', f('match', 1))
self.assertEqual('matches', f(2, 'match')) self.assertEqual('matches', f('match', 2))
self.assertEqual('Patch', f(1, 'Patch')) self.assertEqual('Patch', f('Patch', 1))
self.assertEqual('Patches', f(2, 'Patch')) self.assertEqual('Patches', f('Patch', 2))
def testDepluralize(self): def testDepluralize(self):
f = utils.depluralize f = utils.depluralize
@ -221,10 +221,10 @@ class UtilsTest(unittest.TestCase):
self.assertEqual(utils.sorted(L, mycmp), ['c', 'b', 'a']) self.assertEqual(utils.sorted(L, mycmp), ['c', 'b', 'a'])
def testNItems(self): def testNItems(self):
self.assertEqual(utils.nItems(1, 'tool', 'crazy'), '1 crazy tool') self.assertEqual(utils.nItems('tool', 1, 'crazy'), '1 crazy tool')
self.assertEqual(utils.nItems(1, 'tool'), '1 tool') self.assertEqual(utils.nItems('tool', 1), '1 tool')
self.assertEqual(utils.nItems(2, 'tool', 'crazy'), '2 crazy tools') self.assertEqual(utils.nItems('tool', 2, 'crazy'), '2 crazy tools')
self.assertEqual(utils.nItems(2, 'tool'), '2 tools') self.assertEqual(utils.nItems('tool', 2), '2 tools')
def testItersplit(self): def testItersplit(self):
from utils import itersplit from utils import itersplit

View File

@ -106,6 +106,9 @@ class PluginTestCase(unittest.TestCase):
cleanDataDir = True cleanDataDir = True
def setUp(self, nick='test'): def setUp(self, nick='test'):
# Set conf variables appropriately. # Set conf variables appropriately.
if self.__class__ in (PluginTestCase, ChannelPluginTestCase):
# Necessary because there's a test in here that shouldn\'t run.
return
conf.prefixChars = '@' conf.prefixChars = '@'
conf.replyWhenNotCommand = False conf.replyWhenNotCommand = False
self.myVerbose = world.myVerbose self.myVerbose = world.myVerbose
@ -137,6 +140,9 @@ class PluginTestCase(unittest.TestCase):
cb = Owner.loadPluginClass(self.irc, module) cb = Owner.loadPluginClass(self.irc, module)
def tearDown(self): def tearDown(self):
if self.__class__ in (PluginTestCase, ChannelPluginTestCase):
# Necessary because there's a test in here that shouldn\'t run.
return
self.irc.die() self.irc.die()
gc.collect() gc.collect()
@ -262,9 +268,29 @@ class PluginTestCase(unittest.TestCase):
self.failUnless(re.search(regexp, s, flags), self.failUnless(re.search(regexp, s, flags),
'%r does not match %r' % (s, regexp)) '%r does not match %r' % (s, regexp))
def testDocumentation(self):
if self.__class__ in (PluginTestCase, ChannelPluginTestCase):
return
for cb in self.irc.callbacks:
name = cb.name()
if (name in ('Admin', 'Channel', 'Misc', 'Owner', 'User') and \
not name.lower() in self.__class__.__name__.lower()) or \
isinstance(cb, callbacks.PrivmsgRegexp):
continue
self.failUnless(sys.modules[cb.__class__.__name__].__doc__,
'%s has no module documentation.' % name)
if hasattr(cb, 'isCommand'):
for attr in dir(cb):
if cb.isCommand(attr):
self.failUnless(getattr(cb, attr, None).__doc__,
'%s.%s has no help.' % (name, attr))
class ChannelPluginTestCase(PluginTestCase): class ChannelPluginTestCase(PluginTestCase):
channel = '#test' channel = '#test'
def setUp(self): def setUp(self):
if self.__class__ in (PluginTestCase, ChannelPluginTestCase):
return
PluginTestCase.setUp(self) PluginTestCase.setUp(self)
self.irc.feedMsg(ircmsgs.join(self.channel, prefix=self.prefix)) self.irc.feedMsg(ircmsgs.join(self.channel, prefix=self.prefix))
@ -307,33 +333,7 @@ class ChannelPluginTestCase(PluginTestCase):
class PluginDocumentation: class PluginDocumentation:
def testAllCommandsHaveHelp(self): pass # This is old stuff, it should be removed some day.
for cb in self.irc.callbacks:
if isinstance(cb, callbacks.PrivmsgRegexp):
continue
if hasattr(cb, 'isCommand'):
for attr in cb.__class__.__dict__:
if cb.isCommand(attr):
self.failUnless(getattr(cb, attr).__doc__,
'%s has no syntax' % attr)
def testAllCommandsHaveMorehelp(self):
for cb in self.irc.callbacks:
if isinstance(cb, callbacks.PrivmsgRegexp):
continue
if hasattr(cb, 'isCommand'):
for attr in cb.__class__.__dict__:
if cb.isCommand(attr):
command = getattr(cb, attr)
helps = command.__doc__
self.failUnless(helps and len(helps.splitlines()) >= 3,
'%s has no help' % attr)
def testPluginHasDocumentation(self):
for cb in self.irc.callbacks:
m = sys.modules[cb.__class__.__module__]
self.failIf(m.__doc__ is None,
'%s has no module documentation'%cb.__class__.__name__)