:param extractor:
        a function that takes one argument (the message) and returns a portion
        of message to be interpreted. To extract the text of a chat message,
        use ``lambda msg: msg['text']``.

    :param prefix:
        a list of special characters expected to indicate the head of a command.

    :param separator:
        a command may be followed by arguments separated by ``separator``.

    :type pass_args: bool
    :param pass_args:
        If ``True``, arguments following a command will be passed to the handler
        function.

    :return:
        a key function that interprets a specific part of a message and returns
        the embedded command, optionally followed by arguments. If the text is
        not preceded by any of the specified ``prefix``, it returns a 1-tuple
        ``(None,)`` as the key. This is to distinguish with the special
        ``None`` key in routing table.

def by_command(extractor, prefix=('/',), separator=' ', pass_args=False):
    """
    :param extractor:
        a function that takes one argument (the message) and returns a portion
        of message to be interpreted. To extract the text of a chat message,
        use ``lambda msg: msg['text']``.

    :param prefix:
        a list of special characters expected to indicate the head of a command.

    :param separator:
        a command may be followed by arguments separated by ``separator``.

    :type pass_args: bool
    :param pass_args:
        If ``True``, arguments following a command will be passed to the handler
        function.

    :return:
        a key function that interprets a specific part of a message and returns
        the embedded command, optionally followed by arguments. If the text is
        not preceded by any of the specified ``prefix``, it returns a 1-tuple
        ``(None,)`` as the key. This is to distinguish with the special
        ``None`` key in routing table.
    """
    if not isinstance(prefix, (tuple, list)):
        prefix = (prefix,)

    def f(msg):
        text = extractor(msg)
        for px in prefix:
            if text.startswith(px):
                chunks = text[len(px):].split(separator)
                return chunks[0], (chunks[1:],) if pass_args else ()
        return (None,),  # to distinguish with `None`
    return f