Word-level n-grams in a string

        By default, whitespace is assumed to be a word boundary.

        >>> ng.word_ngrams('This is not a test!')
        [('This', 'is', 'not'), ('is', 'not', 'a'), ('not', 'a', 'test!')]

        If the sequence's length is less than or equal to n, the n-grams are
        simply the sequence itself.

        >>> ng.word_ngrams('Test!')
        [('Test!')]

        Args:
            s: a string

        Returns:
            list: tuples of word-level n-grams

def word_ngrams(s, n=3, token_fn=tokens.on_whitespace):
    """
        Word-level n-grams in a string

        By default, whitespace is assumed to be a word boundary.

        >>> ng.word_ngrams('This is not a test!')
        [('This', 'is', 'not'), ('is', 'not', 'a'), ('not', 'a', 'test!')]

        If the sequence's length is less than or equal to n, the n-grams are
        simply the sequence itself.

        >>> ng.word_ngrams('Test!')
        [('Test!')]

        Args:
            s: a string

        Returns:
            list: tuples of word-level n-grams
    """
    tokens = token_fn(s)
    return __ngrams(tokens, n=min(len(tokens), n))