diff options
author | kotfu <kotfu@kotfu.net> | 2018-07-21 12:56:25 -0600 |
---|---|---|
committer | kotfu <kotfu@kotfu.net> | 2018-07-21 12:56:25 -0600 |
commit | cb0c58db58920122a66cafedc764e59d5087c841 (patch) | |
tree | 74144c7d0b498705f3f6c23fed512843f6c8fd03 /examples/hooks.py | |
parent | 3f737b4b25810cbdc8386777ade0c9b819bb25c1 (diff) | |
download | cmd2-git-cb0c58db58920122a66cafedc764e59d5087c841.tar.gz |
Add hook example
Diffstat (limited to 'examples/hooks.py')
-rw-r--r-- | examples/hooks.py | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/examples/hooks.py b/examples/hooks.py new file mode 100644 index 00000000..66922b79 --- /dev/null +++ b/examples/hooks.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# coding=utf-8 +""" +A sample application for cmd2 demonstrating how to use hooks. + +This application shows how to use postparsing hooks to allow case insensitive +command names, abbreviated commands, as well as allowing numeric arguments to +follow a command without any intervening whitespace. + +""" + +import re + +from typing import List + +import cmd2 + + +class CmdLineApp(cmd2.Cmd): + """Example cmd2 application demonstrating the use of hooks. + + This simple application has one command, `list` which generates a list + of 10 numbers. This command takes one optional argument, which is the + number to start on. + + We have three postparsing hooks, which allow the user to enter: + + (Cmd) list 5 + (Cmd) L 5 + (Cmd) l 5 + (Cmd) L5 + (Cmd) LI5 + + and have them all treated as valid input which prints a list of 10 numbers + starting with the number 5. + """ + + # Setting this true makes it run a shell command if a cmd2/cmd command doesn't exist + # default_to_shell = True + def __init__(self, *args, **kwargs): + # sneakily remove the cmd2.Cmd command called load + # this lets a user enter a command like "l5" and allows it to + # be unambiguous + delattr(cmd2.Cmd, "do_load") + + super().__init__(*args, **kwargs) + + # register three hooks + self.register_postparsing_hook(self.add_whitespace_hook) + self.register_postparsing_hook(self.downcase_hook) + self.register_postparsing_hook(self.abbrev_hook) + + def add_whitespace_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData: + """A hook to split alphabetic command names immediately followed by a number. + + l24 -> l 24 + list24 -> list 24 + list 24 -> list 24 + + """ + command = data.statement.command + # regular expression with looks for: + # ^ - the beginning of the string + # ([^\s\d]+) - one or more non-whitespace non-digit characters, set as capture group 1 + # (\d+) - one or more digit characters, set as capture group 2 + command_pattern = re.compile(r'^([^\s\d]+)(\d+)') + match = command_pattern.search(command) + if match: + data.statement = self.statement_parser.parse("{} {} {}".format( + match.group(1), + match.group(2), + '' if data.statement.args is None else data.statement.args + )) + return data + + def downcase_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData: + """A hook to make uppercase commands lowercase.""" + command = data.statement.command.lower() + data.statement = self.statement_parser.parse("{} {}".format( + command, + '' if data.statement.args is None else data.statement.args + )) + return data + + def abbrev_hook(self, data: cmd2.plugin.PostparsingData) -> cmd2.plugin.PostparsingData: + """Accept unique abbreviated commands""" + target = 'do_' + data.statement.command + if not target in dir(self): + # check if the entered command might be an abbreviation + funcs = [func for func in self.keywords if func.startswith(data.statement.command)] + if len(funcs) == 1: + raw = data.statement.raw.replace(data.statement.command, funcs[0], 1) + data.statement = self.statement_parser.parse(raw) + return data + + @cmd2.with_argument_list + def do_list(self, arglist: List[str]) -> None: + """Generate a list of 10 numbers.""" + if arglist: + first = arglist[0] + try: + first = int(first) + except ValueError: + first = 1 + else: + first = 1 + last = first + 10 + + for x in range(first, last): + self.poutput(x) + + +if __name__ == '__main__': + c = CmdLineApp() + c.cmdloop() |