# Using cpl g & cpl n templating

## Contents

- Prerequisites

- Generate schematics

- Project types

## Prerequisites

Create a folder called `.cpl`

## cpl generate schematics

Create a file which begins with `schematic_your_schematic.py`. A schematic template is detected by starting with `schematic_` and endswith `.py`.

You should replace `your_schematic` with an appropriate name of your schematic. For example, we will choose `Enum`. Attention: It is important that you do not overwrite templates by creating a file or class with the same name.

In the template create a class with the name of your schematic. For example:

    from cpl_cli.abc.generate_schematic_abc import GenerateSchematicABC

    class Enum(GenerateSchematicABC):

        def __init__(self, *args: str):
            GenerateSchematicABC.__init__(self, *args)

        def get_code(self) -> str:
            import textwrap
            code = textwrap.dedent("""\
            from enum import Enum

            class $Name(Enum):

                atr = 0
            """)
            return self.build_code_str(code, Name=self._class_name)

        @classmethod
        def register(cls):
            GenerateSchematicABC.register(
                cls,
                'enum',
                ['e', 'E']
            )

You can test it by calling `cpl g --help` your schematic should be listed as available.

## cpl new project types

The project templating is a little more complex and is therefore divided into several files. First of all, for information, it is very important not to overwrite any existing files or classes!

Template structure explained by the example of the internal type `console`:

    - project_console.py
    - project_file_license.py
    - project_file_appsettings.py
    - project_file.py
    - project_file_readme.py
    - project_file_code_main.py
    - project_file_code_startup.py
    - project_file_code_application.py

Here the template `project_console.py` defines how a console project has to look like when it is generated. Here is the code to illustrate this:

    from cpl_cli.abc.project_type_abc import ProjectTypeABC
    from cpl_cli.configuration import WorkspaceSettings
    from cpl_core.utils import String

    class Console(ProjectTypeABC):

        def __init__(
                self,
                base_path: str,
                project_name: str,
                workspace: WorkspaceSettings,
                use_application_api: bool,
                use_startup: bool,
                use_service_providing: bool,
                use_async: bool,
                project_file_data: dict,
        ):
            from project_file import ProjectFile
            from project_file_appsettings import ProjectFileAppsettings
            from project_file_code_application import ProjectFileApplication
            from project_file_code_main import ProjectFileMain
            from project_file_code_startup import ProjectFileStartup
            from project_file_readme import ProjectFileReadme
            from project_file_license import ProjectFileLicense
            from schematic_init import Init

            ProjectTypeABC.__init__(self, base_path, project_name, workspace, use_application_api, use_startup, use_service_providing, use_async, project_file_data)

            project_path = f'{base_path}{String.convert_to_snake_case(project_name.split("/")[-1])}/'

            self.add_template(ProjectFile(project_name.split('/')[-1], project_path, project_file_data))
            if workspace is None:
                self.add_template(ProjectFileLicense(''))
                self.add_template(ProjectFileReadme(''))
                self.add_template(Init('', 'init', f'{base_path}tests/'))

            self.add_template(Init('', 'init', project_path))
            self.add_template(ProjectFileAppsettings(project_path))

            if use_application_api:
                self.add_template(ProjectFileApplication(project_path, use_application_api, use_startup, use_service_providing, use_async))

            if use_startup:
                self.add_template(ProjectFileStartup(project_path, use_application_api, use_startup, use_service_providing, use_async))

            self.add_template(ProjectFileMain(project_name.split('/')[-1], project_path, use_application_api, use_startup, use_service_providing, use_async))

The class must be named exactly as the project type should be named. It is also checked on the initial letter of the class as alias. Now create a class for normal files which inherits from `FileTemplateABC` and a class for code files which inherits from `CodeFileTemplateABC`.

For example:

project_file_code_startup.py:

    from cpl_cli.abc.code_file_template_abc import CodeFileTemplateABC

    class ProjectFileStartup(CodeFileTemplateABC):

        def __init__(self, path: str, use_application_api: bool, use_startup: bool, use_service_providing: bool, use_async: bool):
            CodeFileTemplateABC.__init__(self, 'startup', path, '', use_application_api, use_startup, use_service_providing, use_async)

        def get_code(self) -> str:
            import textwrap

            return textwrap.dedent("""\
            from cpl_core.application import StartupABC
            from cpl_core.configuration import ConfigurationABC
            from cpl_core.dependency_injection import ServiceProviderABC, ServiceCollectionABC
            from cpl_core.environment import ApplicationEnvironment

            class Startup(StartupABC):

                def __init__(self):
                    StartupABC.__init__(self)

                def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironment) -> ConfigurationABC:
                    return configuration

                def configure_services(self, services: ServiceCollectionABC, environment: ApplicationEnvironment) -> ServiceProviderABC:
                    return services.build_service_provider()
            """)

project_file.py:

    import json

    from cpl_cli.abc.file_template_abc import FileTemplateABC

    class ProjectFile(FileTemplateABC):

        def __init__(self, name: str, path: str, code: dict):
            FileTemplateABC.__init__(self, '', path, '{}')
            self._name = f'{name}.json'
            self._code = code

        def get_code(self) -> str:
            return json.dumps(self._code, indent=2)