diff options
Diffstat (limited to 'tools/cru-py/cru/template.py')
| -rw-r--r-- | tools/cru-py/cru/template.py | 207 | 
1 files changed, 0 insertions, 207 deletions
diff --git a/tools/cru-py/cru/template.py b/tools/cru-py/cru/template.py deleted file mode 100644 index 35d68ac..0000000 --- a/tools/cru-py/cru/template.py +++ /dev/null @@ -1,207 +0,0 @@ -from abc import ABCMeta, abstractmethod -from collections.abc import Callable, Mapping -from pathlib import Path -from string import Template -from typing import Generic, TypeVar - -from ._iter import CruIterator -from ._error import CruException - -from .parsing import StrWrapperVarParser - - -class CruTemplateError(CruException): -    pass - - -class CruTemplateBase(metaclass=ABCMeta): -    def __init__(self, text: str): -        self._text = text -        self._variables: set[str] | None = None - -    @abstractmethod -    def _get_variables(self) -> set[str]: -        raise NotImplementedError() - -    @property -    def text(self) -> str: -        return self._text - -    @property -    def variables(self) -> set[str]: -        if self._variables is None: -            self._variables = self._get_variables() -        return self._variables - -    @property -    def variable_count(self) -> int: -        return len(self.variables) - -    @property -    def has_variables(self) -> bool: -        return self.variable_count > 0 - -    @abstractmethod -    def _do_generate(self, mapping: dict[str, str]) -> str: -        raise NotImplementedError() - -    def generate(self, mapping: Mapping[str, str], allow_extra: bool = True) -> str: -        values = dict(mapping) -        if not self.variables <= set(values.keys()): -            raise CruTemplateError("Missing variables.") -        if not allow_extra and not set(values.keys()) <= self.variables: -            raise CruTemplateError("Extra variables.") -        return self._do_generate(values) - - -class CruTemplate(CruTemplateBase): -    def __init__(self, prefix: str, text: str): -        super().__init__(text) -        self._prefix = prefix -        self._template = Template(text) - -    def _get_variables(self) -> set[str]: -        return ( -            CruIterator(self._template.get_identifiers()) -            .filter(lambda i: i.startswith(self.prefix)) -            .to_set() -        ) - -    @property -    def prefix(self) -> str: -        return self._prefix - -    @property -    def py_template(self) -> Template: -        return self._template - -    @property -    def all_variables(self) -> set[str]: -        return set(self._template.get_identifiers()) - -    def _do_generate(self, mapping: dict[str, str]) -> str: -        return self._template.safe_substitute(mapping) - - -class CruStrWrapperTemplate(CruTemplateBase): -    def __init__(self, text: str, wrapper: str = "@@"): -        super().__init__(text) -        self._wrapper = wrapper -        self._tokens: StrWrapperVarParser.Result - -    @property -    def wrapper(self) -> str: -        return self._wrapper - -    def _get_variables(self): -        self._tokens = StrWrapperVarParser(self.wrapper).parse(self.text) -        return ( -            self._tokens.cru_iter() -            .filter(lambda t: t.is_var) -            .map(lambda t: t.value) -            .to_set() -        ) - -    def _do_generate(self, mapping): -        return ( -            self._tokens.cru_iter() -            .map(lambda t: mapping[t.value] if t.is_var else t.value) -            .join_str("") -        ) - - -_Template = TypeVar("_Template", bound=CruTemplateBase) - - -class TemplateTree(Generic[_Template]): -    def __init__( -        self, -        template_generator: Callable[[str], _Template], -        source: str, -        *, -        template_file_suffix: str | None = ".template", -    ): -        """ -        If template_file_suffix is not None, the files will be checked according to the -        suffix of the file name. If the suffix matches, the file will be regarded as a -        template file. Otherwise, it will be regarded as a non-template file. -        Content of template file must contain variables that need to be replaced, while -        content of non-template file may not contain any variables. -        If either case is false, it generally means whether the file is a template is -        wrongly handled. -        """ -        self._template_generator = template_generator -        self._files: list[tuple[Path, _Template]] = [] -        self._source = source -        self._template_file_suffix = template_file_suffix -        self._load() - -    @property -    def templates(self) -> list[tuple[Path, _Template]]: -        return self._files - -    @property -    def source(self) -> str: -        return self._source - -    @property -    def template_file_suffix(self) -> str | None: -        return self._template_file_suffix - -    @staticmethod -    def _scan_files(root: str) -> list[Path]: -        root_path = Path(root) -        result: list[Path] = [] -        for path in root_path.glob("**/*"): -            if not path.is_file(): -                continue -            path = path.relative_to(root_path) -            result.append(Path(path)) -        return result - -    def _load(self) -> None: -        files = self._scan_files(self.source) -        for file_path in files: -            template_file = Path(self.source) / file_path -            with open(template_file, "r") as f: -                content = f.read() -            template = self._template_generator(content) -            if self.template_file_suffix is not None: -                should_be_template = file_path.name.endswith(self.template_file_suffix) -                if should_be_template and not template.has_variables: -                    raise CruTemplateError( -                        f"Template file {file_path} has no variables." -                    ) -                elif not should_be_template and template.has_variables: -                    raise CruTemplateError(f"Non-template {file_path} has variables.") -            self._files.append((file_path, template)) - -    @property -    def variables(self) -> set[str]: -        s = set() -        for _, template in self.templates: -            s.update(template.variables) -        return s - -    def generate(self, variables: Mapping[str, str]) -> list[tuple[Path, str]]: -        result: list[tuple[Path, str]] = [] -        for path, template in self.templates: -            if self.template_file_suffix is not None and path.name.endswith( -                self.template_file_suffix -            ): -                path = path.parent / (path.name[: -len(self.template_file_suffix)]) - -            text = template.generate(variables) -            result.append((path, text)) -        return result - -    def generate_to( -        self, destination: str, variables: Mapping[str, str], dry_run: bool -    ) -> None: -        generated = self.generate(variables) -        if not dry_run: -            for path, text in generated: -                des = Path(destination) / path -                des.parent.mkdir(parents=True, exist_ok=True) -                with open(des, "w") as f: -                    f.write(text)  | 
