# AUTOGENERATED! DO NOT EDIT! File to edit: ../03_html.ipynb.

# %% auto 0
__all__ = ['hyphenate_soup', 'analyze_soups']

# %% ../03_html.ipynb 4
from collections.abc import Callable, Set
from collections import Counter
from typing import Type
import bs4
import re

# %% ../03_html.ipynb 5
word_or_punct_re = re.compile(r'\w+|[^\w]+')
word_re = re.compile(r'\w+')
default_exclude_classes = (
    bs4.element.PreformattedString,
    bs4.element.Stylesheet,
    bs4.element.Script,
    bs4.element.RubyTextString, # type: ignore
    bs4.element.RubyParenthesisString, # type: ignore
)

# %% ../03_html.ipynb 7
def hyphenate_soup(
    soup: bs4.BeautifulSoup,  # soup to be modified
    hyphenator: Callable[[str], str],  # hyphenator
    exclude_classes: tuple[Type[bs4.element.PageElement],...]=default_exclude_classes,  # do not modify inside these
) -> None:
    """Call hyphenator on words that appear in suitable elements of soup,
    and replace the contents of those elements. Suitable elements are those
    containing text whose class is not (a subclass of something) in
    exclude_classes."""
    for t in soup.find_all(string=True):
        if isinstance(t, exclude_classes):
            continue
        pieces = re.findall(word_or_punct_re, str(t.string))
        for i, word in enumerate(pieces):
            if not word_re.fullmatch(word):
                continue
            if (title := word.istitle()) or word.islower():
                hyphenated = hyphenator(word)
                if title:
                    pieces[i] = hyphenated.title()
                else:
                    pieces[i] = hyphenated
        new = ''.join(pieces)
        t.string.replace_with(new)


# %% ../03_html.ipynb 10
def analyze_soups(
    dinner: list[bs4.BeautifulSoup],  # soups to be read
    exclude_classes: tuple[Type[bs4.element.PageElement],...]=default_exclude_classes,  # do not look inside these
) -> Counter:
    """Count words appearing in all soups."""
    counter: Counter = Counter()
    for soup in dinner:
        for t in soup.find_all(string=True):
            if isinstance(t, exclude_classes):
                continue
            pieces = re.findall(word_or_punct_re, str(t.string))
            counter.update(word.lower() for word in pieces
                           if word_re.fullmatch(word) and word.istitle() or word.islower())
    return counter
