def c(self, irc, msg, args, a, c, b, iftrue, iffalse): """<a> (==|!=|<|>|<=|>=|==#|!=#|<#|>#|<=#|>=#) <b> [<dotrue>] [<dofalse>] Compares <a> with <b>. If true, then returns <iftrue> or else, <iffalse>. Operators ending in '#' compare <a>'s string length with <b>, which must be an integer in this case. In '==' comparisons, <b> can be a regular expression by encasing it within a delimiter. If either <a> or <b> are @last or @last[<nick>], uses the result of the last match/replace operation from yourself or <nick>, respectively. See $delims for valid delimiter characters. """ # TODO: <type> <a> <oper> <type> <b> ... [<a>, <b>] # <condition>: <command> <parms> ... a = wvm.fixexpr(ircutils.stripFormatting(a), False) a = self._getmatch(msg.nick, a)[1] b = wvm.fixexpr(ircutils.stripFormatting(b)) b = self._getmatch(msg.nick, b)[1] if c.endswith('#'): if b.isdigit(): a = len(a) b = int(b) else: irc.error('<b> must be an integer.') return elif c in ('<', '>', '<=', '>='): try: a = float(a) b = float(b) except ValueError: pass if c in ('==', "!="): nick, expr = wvm.parseexpr(b) try: if expr['isre']: r = re.search(expr['match'], a) else: r = a == expr['match'] if c.startswith('!'): r = not r except re.error: r = False elif c in ('<', '<#'): r = a < b elif c in ('>', '>#'): r = a > b elif c in ('<=', '<=#'): r = a <= b elif c in ('>=', '>=#'): r = a >= b elif c == '==#': r = a == b elif c == '!=#': r = a != b else: irc.error('Invalid operator.') return if r: if iftrue: if iftrue == '%a': r = a elif iftrue == '%b': r = expr['match'] else: r = iftrue else: r = a else: if iffalse: if iffalse == '%a': r = a elif iffalse == '%b': r = expr['match'] else: r = iffalse else: r = expr['match'] self._setmatch(msg.nick, r) irc.reply(r)
def array(self, irc, msg, args, opts, index, elements): """<index> [--i] [<key>:]<string> [[<key>:]<string> ...] [?:<string>] Returns the <string> whose <key> matches <index>. An <index> of "?" returns a random item. Keys that are not defined will be assigned the number of their position, starting at zero. If a key is not found and a "!" key exists, it will be returned instead, otherwise, an key error will be thrown. If --i is set, keys will be case-insensitive. Multiple keys can be assigned to a string by separating them with semicolons. This function is meant to be used in an alias: array $1 key1:item1 key2:item2 ... """ array = {} casei = False for o, a in opts: if o == "i": casei = True for position, element in enumerate(elements): element = element.split(":", 1) if len(element) == 1: array[str(position)] = element[0] else: if casei: element[0] = element[0].lower() for key in element[0].split(";"): array[wvm.fixexpr(key, False)] = wvm.fixexpr(element[1]).lstrip() if not index: index = "0" elif index == "#": try: irc.reply(len(array)) except KeyError: irc.reply(0) return elif index == "@": try: irc.reply(" / ".join(sorted(array.values(), reverse=True))) except KeyError: irc.reply("") return elif index == "@@": try: irc.reply(" / ".join(sorted(array.keys(), reverse=True))) except KeyError: irc.reply("") return elif index == "?": element = self.rng.choice(array.values()) else: index = wvm.fixexpr(index, False) if casei: index = index.lower() try: element = array[index] except KeyError: try: element = array["!"] except KeyError: irc.error("No such array key: %s" % index) return irc.reply(element)
def var(self, irc, msg, args, opts, name, elements): """[--i] [--d=<default>] [--u=<ifundef>] [--t=<timeout>] [--o=<owner>] <var>[:<index>] [[<key>:]<string> ...] If no <key>:<string> pair or <string> arguments are included, returns the <string> whose <key> matches <index> in variable <var>. If the <index> is left out, it will be assumed to be "0". An <index> of "?" returns a random item. Adding <key>:<string> pair or <string> arguments will set <var> to them. If an <index> is included with this, the existing <string> at that index will be set to the arguments as one merged <string>. If a <key> is left out, it will be assingned the number of that item's position, starting at zero. If a <key> is not found for an <index> and a "!" key exists, its will be returned instead; otherwise, a key error will be thrown. Multiple keys can be assigned to a string by separating them with semicolons. If --i is set, keys will be case-insensitve. Variables will live up to ~10 seconds unless the timeout is set with --t (0 == permanent). Variables can be made private (only the same user can modify) by prefixing it with an underscore. If --d is set, <default> will be returned as the value. If --u is set, <ifundef> will be returned as the error if the variable isn't defined. If --o is set, will give read-only access to variables belonging to that owner. """ name = name.split(":", 1) default = None ifundef = None index = None private = False casei = False count = False owner = msg.nick.lower() timeout = 10 for o, a in opts: if o == "i": casei = True elif o == "t": timeout = max(0, int(a)) elif o == "d": default = a elif o == "u": ifundef = a elif o == "o": owner = a if name[0].startswith("_"): private = True name[0] = "%s-%s" % (name[0], owner) if len(name) == 2: index = wvm.fixexpr(name[1]).lstrip() else: index = None name = name[0].lower() try: if not elements: if not index: index = "0" elif index == "#": try: irc.reply(len(self.variables[name][0])) except KeyError: irc.reply(0) return elif index == "@": try: irc.reply(" / ".join(sorted(self.variables[name][0].values()))) except KeyError: irc.reply("") return elif index == "@@": try: irc.reply(" / ".join(sorted(self.variables[name][0].keys()))) except KeyError: irc.reply("") return elif index == "?": element = self.variables[name][0].values() irc.reply(self.rng.choice(element)) return try: if self.variables[name][3]: index = index.lower() except KeyError: if default: irc.reply(default) elif ifundef: irc.error(ifundef) else: irc.error('Variable "%s" is undefined.' % name) return irc.reply(self.variables[name][0][index]) else: if private and not ircdb.checkCapability(msg.prefix, "owner"): if not ircutils.nickEqual(owner, msg.nick): irc.error("Only read-only allowed outside your scope.") return try: current_owner = self.variables[name][2] if not ircutils.nickEqual(current_owner, msg.nick): irc.error('Variable "%s" is locked by %s.' % (name, current_owner)) return except KeyError: pass if not index: array = {} for position, element in enumerate(elements): element = element.split(":", 1) if len(element) == 1: array[str(position)] = element[0] else: if casei: element[0] = element[0].lower() for key in element[0].split(";"): array[wvm.fixexpr(key, False)] = wvm.fixexpr(element[1]).lstrip() self.variables[name] = [array, (time.time(), timeout), owner, casei] else: if casei: index = index.lower() try: self.variables[name][0][index] = " ".join(elements) self.variables[name][1] = (time.time(), timeout) self.variables[name][2] = owner except KeyError: self.variables[name] = [{index: " ".join(elements)}, (time.time(), timeout), owner, casei] self._writevarsfile() irc.reply("") except KeyError: try: irc.reply(self.variables[name][0]["!"]) except KeyError: irc.error("No such variable key: %s[%s]" % (name, index))
def striphtml(html, tags=[True], limit=0, offset=0, joiner=''): """ Extracts the text from a list of HTML <tags> in <html>, returning up to <limit> elements per tag, starting at match <offset>. """ soup = BeautifulSoup(html) comments = soup.find_all(text=lambda text:isinstance(text, Comment)) [comment.extract() for comment in comments] text = [] for tag in tags: tag = str(tag).split(':') skip = offset matches = 0 attrs = {} getprop = None try: skip += int(float(tag[0])) tag = tag[1:] except ValueError: pass if tag[0] in ('', 'True'): tag[0] == 'body' for attr in tag[1:]: attr = attr.split('=', 2) l = len(attr) if l == 1: getprop = attr[0] elif l > 1: try: attrs[attr[0]] = re.compile(wvm.fixexpr(attr[1])) except re.error: attrs[attr[0]] = attr[1] if l == 3: getprop = attr[2] for tag in soup.find_all(tag[0], attrs=attrs): if not getprop: if skip > 0: skip -= 1 continue text.append(tagtotext(tag, joiner)) else: try: t = tag[getprop] if skip > 0: skip -= 1 continue text.append(t) except KeyError: continue matches += 1 if matches == limit: break text.append('~~') return "\n".join(text[:-1])