texlive[53637] Master/texmf-dist: texplate (2feb20)

commits+karl at tug.org commits+karl at tug.org
Sun Feb 2 23:30:34 CET 2020


Revision: 53637
          http://tug.org/svn/texlive?view=revision&revision=53637
Author:   karl
Date:     2020-02-02 23:30:34 +0100 (Sun, 02 Feb 2020)
Log Message:
-----------
texplate (2feb20)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/support/texplate/README.md
    trunk/Master/texmf-dist/doc/support/texplate/texplate-manual.pdf
    trunk/Master/texmf-dist/doc/support/texplate/texplate-manual.tex
    trunk/Master/texmf-dist/scripts/texplate/texplate.jar

Added Paths:
-----------
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/Main.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/TemplateProcessing.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/InvalidKeySetException.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/InvalidTemplateException.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/TemplateMergingException.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/Configuration.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/Template.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/BooleanHandler.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/CSVListHandler.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/Handler.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/HandlerUtils.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/MergingUtils.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/MessageUtils.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/PathUtils.kt
    trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/ValidatorUtils.kt
    trunk/Master/texmf-dist/source/support/texplate/main/resources/
    trunk/Master/texmf-dist/source/support/texplate/main/resources/org/
    trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/
    trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/
    trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/templates/
    trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/templates/texplate-article.toml
    trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/templates/texplate-standalone.toml

Removed Paths:
-------------
    trunk/Master/texmf-dist/scripts/texplate/templates/
    trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/Main.java
    trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/exceptions/
    trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Configuration.java
    trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Template.java
    trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/TemplateProcessing.java
    trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/handlers/
    trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/util/

Modified: trunk/Master/texmf-dist/doc/support/texplate/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/support/texplate/README.md	2020-02-02 00:57:43 UTC (rev 53636)
+++ trunk/Master/texmf-dist/doc/support/texplate/README.md	2020-02-02 22:30:34 UTC (rev 53637)
@@ -1,6 +1,8 @@
 # TeXplate
 
-![Language: Kotlin](https://img.shields.io/badge/Language-Kotlin-blue.svg?style=flat-square) ![Minimum JRE: 8.0](https://img.shields.io/badge/Minimum_JRE-8.0-blue.svg?style=flat-square) ![Current version: 1.0.1](https://img.shields.io/badge/Current_version-1.0.1-blue.svg?style=flat-square)
+![Language: Kotlin](https://img.shields.io/badge/Language-Kotlin-blue.svg?style=flat-square)
+![Minimum JRE: 8.0](https://img.shields.io/badge/Minimum_JRE-8.0-blue.svg?style=flat-square)
+![Current version](https://img.shields.io/badge/dynamic/json.svg?color=blue&label=Latest%20release&query=%24.0.name&url=https%3A%2F%2Fgitlab.com%2Fapi%2Fv4%2Fprojects%2F13793875%2Frepository%2Ftags&style=flat-square)
 
 TeXplate is a tool for creating document structures based on templates. The application name is a word play on _TeX_ and _template_, so the purpose seems quite obvious: we want to provide an easy and straightforward framework for reducing the typical code boilerplate when writing TeX documents. Also note that one can easily extrapolate the use beyond articles and theses: the application is powerful enough to generate _any_ text-based structure, given that a corresponding template exists.
 
@@ -20,7 +22,7 @@
                              \ \_\                              
                               \/_/                              
 
-TeXplate 1.0.1, a document structure creation tool
+TeXplate 1.0.2, a document structure creation tool
 Copyright (c) 2020, Island of TeX
 All rights reserved.
 
@@ -83,7 +85,7 @@
                              \ \_\                              
                               \/_/                              
 
-TeXplate 1.0.1, a document structure creation tool
+TeXplate 1.0.2, a document structure creation tool
 Copyright (c) 2020, Island of TeX
 All rights reserved.
 

Modified: trunk/Master/texmf-dist/doc/support/texplate/texplate-manual.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/support/texplate/texplate-manual.tex
===================================================================
--- trunk/Master/texmf-dist/doc/support/texplate/texplate-manual.tex	2020-02-02 00:57:43 UTC (rev 53636)
+++ trunk/Master/texmf-dist/doc/support/texplate/texplate-manual.tex	2020-02-02 22:30:34 UTC (rev 53637)
@@ -17,7 +17,7 @@
 \newcommand{\shortopt}[1]{{\ttfamily-#1}}
 \newcommand{\longopt}[1]{{\ttfamily{-}{-}#1}}
 \newcommand{\macro}[1]{{\ttfamily\textbackslash#1}}
-\newcommand{\texplateversion}{1.0.1}
+\newcommand{\texplateversion}{1.0.2}
 
 \title{A gentle introduction to \texplate:\\ a document structure creation tool}
 \author{Island of \TeX}
@@ -242,7 +242,7 @@
 Observe that \texplate's lookup system is case-sensitive, so make sure to always reference the correct name.
 \end{disclaimer}
 
-Although there are no hard limitations on a template name, it is advisable to keep it short and concise, with no spaces whatsoever\footnote{Another Carlislean statement would remind us that people that put spaces in their file names deserve no sympathy. At all.}. As a consequence, potential issues with extended characters in the Unicode range and command line escaping are avoided, and thus our beloved tool might just work as expected.
+Although there are no hard limitations on a template name, it is advisable to keep it short and concise, with no spaces whatsoever\footnote{Another Carlislean statement would remind us that people who put spaces in their file names deserve no sympathy. At all.}. As a consequence, potential issues with extended characters in the Unicode range and command line escaping are avoided, and thus our beloved tool might just work as expected.
 
 \section{Directory lookup}
 \label{sec:directorylookup}
@@ -252,7 +252,7 @@
 \begin{enumerate}
 \item\inline{\textasciitilde/.texplate/templates} which refers to a path structure from the user home directory.
 
-\item\inline{<APP>/templates} which refers to a path structure from the application directory (with \inline{<APP>} denoting the location where \texplate\ is installed).
+\item The application's resources which refers to a files within the JAR file. You can use a ZIP viewer to look at the templates there.
 \end{enumerate}
 
 For instance, as a means to illustrate the concept of directory lookup, consider the following command line command:
@@ -396,7 +396,7 @@
 \item When running \texplate, this is the expected output to be displayed in the command line (note that the layout is slightly modified due to space constraints in this user manual):
 
 \begin{code}
-TeXplate 1.0.1, a document structure creation tool
+TeXplate 1.0.2, a document structure creation tool
 Copyright (c) 2020, Island of TeX
 All rights reserved.
 
@@ -597,8 +597,42 @@
 
 Happy \TeX ing with \texplate!
 
-\section*{License}
+\chapter*{License}
 
 \texplate\ is licensed under the New BSD License. Please note that the New BSD License has been verified as a GPL-compatible free software license by the Free Software Foundation, and has been vetted as an open source license by the Open Source Initiative.
 
+\chapter*{Changelog}
+
+\section*{1.0.2 (current)}
+
+\subsection*{Fixed}
+
+\begin{itemize}
+\item \texplate\ now finds its templates even on Windows.
+\end{itemize}
+
+\subsection*{Changed}
+
+\begin{itemize}
+\item \texplate\ now finishes its transition to Kotlin. We did not change any  functionality in the course of this change.
+\item Templates are now provided as resources from the JAR instead of a separate  folder on the hard drive.
+\end{itemize}
+
+\section*{1.0.1 (2020-01-17)}
+
+\subsection*{Changed}
+
+\begin{itemize}
+\item \texplate\ will now distribute only non-generic template file names. In the  system's template directory, we search for \inline{texplate-<name>.toml} as well.
+\end{itemize}
+
+\section*{1.0.0 (2020-01-15)}
+
+\subsection*{Added}
+
+\begin{itemize}
+\item Base functionality and default templates.
+\item User manual.
+\end{itemize}
+
 \end{document}

Modified: trunk/Master/texmf-dist/scripts/texplate/texplate.jar
===================================================================
(Binary files differ)

Deleted: trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/Main.java
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/Main.java	2020-02-02 00:57:43 UTC (rev 53636)
+++ trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/Main.java	2020-02-02 22:30:34 UTC (rev 53637)
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.texplate;
-
-import org.islandoftex.texplate.model.TemplateProcessing;
-import org.islandoftex.texplate.util.MessageUtils;
-import picocli.CommandLine;
-
-/**
- * The main class. The application logic is enclosed in the template processing
- * class.
- *
- * @version 1.0
- * @since 1.0
- */
-public class Main {
-
-    /**
-     * Main method. Note that it simply passes the control to the template
-     * processing class.
-     *
-     * @param args The command line arguments.
-     */
-    public static void main(String[] args) {
-
-        // draw the application logo in the
-        // terminal (please have fixed fonts
-        // in your terminal for a nice display)
-        MessageUtils.drawLogo();
-
-        // calls the command line processing method
-        // and performs the actual application logic
-        int exitCode = new CommandLine(new TemplateProcessing()).execute(args);
-        System.exit(exitCode);
-    }
-
-}

Deleted: trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Configuration.java
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Configuration.java	2020-02-02 00:57:43 UTC (rev 53636)
+++ trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Configuration.java	2020-02-02 22:30:34 UTC (rev 53637)
@@ -1,150 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.texplate.model;
-
-import com.moandjiezana.toml.Toml;
-import io.vavr.control.Try;
-import org.islandoftex.texplate.exceptions.InvalidTemplateException;
-
-import java.nio.file.Path;
-import java.util.Map;
-
-/**
- * The configuration model.
- *
- * @version 1.0
- * @since 1.0
- */
-public class Configuration {
-
-    // template of the template
-    private String template;
-
-    // map of variables for the configuration
-    private Map<String, Object> map;
-
-    /**
-     * Constructor.
-     */
-    public Configuration() {
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param template The template.
-     * @param map      The map.
-     */
-    public Configuration(String template, Map<String, Object> map) {
-        this.template = template;
-        this.map = map;
-    }
-
-    /**
-     * Gets the template.
-     *
-     * @return The template.
-     */
-    public String getTemplate() {
-        return template;
-    }
-
-    /**
-     * Sets the template.
-     *
-     * @param template The template.
-     */
-    public void setTemplate(String template) {
-        this.template = template;
-    }
-
-    /**
-     * Gets the map.
-     *
-     * @return The map.
-     */
-    public Map<String, Object> getMap() {
-        return map;
-    }
-
-    /**
-     * Sets the map.
-     *
-     * @param map The map.
-     */
-    public void setMap(Map<String, Object> map) {
-        this.map = map;
-    }
-
-    /**
-     * Checks whether the configuration is valid.
-     *
-     * @return A boolean value indicating whether the configuration is valid.
-     */
-    private boolean isValid() {
-        return !(template == null || map == null);
-    }
-
-    /**
-     * Reads the configuration from path.
-     *
-     * @param path The path.
-     * @return Configuration.
-     * @throws InvalidTemplateException The configuration is invalid.
-     */
-    private static Configuration readFromPath(Path path)
-            throws InvalidTemplateException {
-
-        // the actual configuration
-        Configuration configuration;
-
-        // the default message
-        String message = "The provided configuration file looks invalid. "
-                + "Please make sure the configuration has a valid syntax and "
-                + "try again. ";
-
-        try {
-
-            // gets the configuration
-            configuration = new Toml().read(path.toFile()).
-                    to(Configuration.class);
-
-        } catch (Exception exception) {
-
-            // the configuration
-            // seems invalid
-            throw new InvalidTemplateException(message + "In this particular "
-                    + "scenario, there is a possibility that the configuration "
-                    + "file does not follow the TOML specification. Please "
-                    + "refer to the user manual for further details and a "
-                    + "possible fix. Also, the raised exception message can "
-                    + "give us some hints on what happened.", exception);
-        }
-
-        // checks whether the
-        // configuration is valid
-        if (configuration.isValid()) {
-
-            // returns the configuration
-            return configuration;
-        } else {
-
-            // the configuration
-            // is invalid
-            throw new InvalidTemplateException(message + "Specifically, some "
-                    + "mandatory fields are either absent or empty in the "
-                    + "configuration file. It is quite important to strictly "
-                    + "follow the configuration specification, as detailed in "
-                    + "the user manual, or the tool will not work at all.");
-        }
-    }
-
-    /**
-     * Gets the configuration from a path.
-     *
-     * @param path The path.
-     * @return The configuration.
-     */
-    public static Try<Configuration> of(Path path) {
-        return Try.of(() -> readFromPath(path));
-    }
-}

Deleted: trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Template.java
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Template.java	2020-02-02 00:57:43 UTC (rev 53636)
+++ trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/Template.java	2020-02-02 22:30:34 UTC (rev 53637)
@@ -1,252 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.texplate.model;
-
-import com.moandjiezana.toml.Toml;
-import io.vavr.control.Try;
-import org.islandoftex.texplate.exceptions.InvalidTemplateException;
-
-import java.nio.file.Path;
-import java.util.List;
-import java.util.Map;
-
-/**
- * The template model.
- *
- * @version 1.0
- * @since 1.0
- */
-public class Template {
-
-    // name of the template
-    private String name;
-
-    // description of the template
-    private String description;
-
-    // list of authors who wrote the template
-    private List<String> authors;
-
-    // list of requirements for the template
-    private List<String> requirements;
-
-    // the document to be configured
-    private String document;
-
-    // the map handlers
-    private Map<String, String> handlers;
-
-    /**
-     * Constructor.
-     */
-    public Template() {
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param name         Name of the template.
-     * @param description  Description of the template.
-     * @param authors      List of authors of the template.
-     * @param requirements List of requirements for the template.
-     * @param document     The document to be configured.
-     * @param handlers     The optional map handlers.
-     */
-    public Template(String name, String description, List<String> authors,
-                    List<String> requirements, String document,
-                    Map<String, String> handlers) {
-        this.name = name;
-        this.description = description;
-        this.authors = authors;
-        this.requirements = requirements;
-        this.document = document;
-        this.handlers = handlers;
-    }
-
-    /**
-     * Gets the template name.
-     *
-     * @return The template name.
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the template name.
-     *
-     * @param name The template name.
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * Gets the template description.
-     *
-     * @return The template description.
-     */
-    public String getDescription() {
-        return description;
-    }
-
-    /**
-     * Sets the template description.
-     *
-     * @param description The template description.
-     */
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    /**
-     * Gets the template authors.
-     *
-     * @return The template authors.
-     */
-    public List<String> getAuthors() {
-        return authors;
-    }
-
-    /**
-     * Sets the template authors.
-     *
-     * @param authors The template authors.
-     */
-    public void setAuthors(List<String> authors) {
-        this.authors = authors;
-    }
-
-    /**
-     * Gets the template requirements.
-     *
-     * @return The template requirements.
-     */
-    public List<String> getRequirements() {
-        return requirements;
-    }
-
-    /**
-     * Sets the template requirements.
-     *
-     * @param requirements The template requirements.
-     */
-    public void setRequirements(List<String> requirements) {
-        this.requirements = requirements;
-    }
-
-    /**
-     * Gets the template document.
-     *
-     * @return The template document.
-     */
-    public String getDocument() {
-        return document;
-    }
-
-    /**
-     * Sets the template document.
-     *
-     * @param document The template document.
-     */
-    public void setDocument(String document) {
-        this.document = document;
-    }
-
-    /**
-     * Gets the map handlers.
-     *
-     * @return The map handlers.
-     */
-    public Map<String, String> getHandlers() {
-        return handlers;
-    }
-
-    /**
-     * Sets the map handlers.
-     *
-     * @param handlers The map handlers.
-     */
-    public void setHandlers(Map<String, String> handlers) {
-        this.handlers = handlers;
-    }
-
-    /**
-     * Checks whether the template is valid.
-     *
-     * @return A boolean value indicating whether the template is valid.
-     */
-    private boolean isValid() {
-        return !((name == null) || (description == null)
-                || (authors == null) || (requirements == null)
-                || (document == null) || name.trim().isEmpty()
-                || description.trim().isEmpty() || authors.isEmpty()
-                || document.trim().isEmpty());
-    }
-
-    /**
-     * Reads the template from the provided path.
-     *
-     * @param path The path to the template file.
-     * @return The template object from the provided path.
-     * @throws InvalidTemplateException The template is invalid.
-     */
-    private static Template readFromPath(Path path)
-            throws InvalidTemplateException {
-
-        // the actual template
-        Template template;
-
-        // the exception message, in case the
-        // conversion fails or if there are
-        // missing elements from the template
-        String message = "The provided template file looks invalid. Please "
-                + "make sure the template has a valid syntax and try again. ";
-
-        try {
-
-            // reads the file and converts
-            // the TOML format into the object
-            template = new Toml().read(path.toFile()).to(Template.class);
-
-        } catch (Exception exception) {
-
-            // throws the new exception and
-            // attaches the original cause
-            throw new InvalidTemplateException(message + "In this particular "
-                    + "scenario, there is a possibility that the template "
-                    + "file does not follow the TOML specification. Please "
-                    + "refer to the user manual for further details and a "
-                    + "possible fix. Also, the raised exception message can "
-                    + "give us some hints on what happened.", exception);
-        }
-
-        // the conversion hasn't failed, but we need
-        // to check whether the template is valid
-        if (template.isValid()) {
-
-            // everything went fine, so
-            // simply return the template
-            return template;
-        } else {
-
-            // the template is invalid, so we
-            // need to throw an exception
-            throw new InvalidTemplateException(message + "Specifically, some "
-                    + "mandatory fields are either absent or empty in the "
-                    + "template file. It is quite important to strictly "
-                    + "follow the template specification, as detailed in the "
-                    + "user manual, or the tool will not work at all.");
-        }
-    }
-
-    /**
-     * Returns the template from the provided path.
-     *
-     * @param path The path in which the template is retrieved.
-     * @return The corresponding template, enclosed in a Try object.
-     */
-    public static Try<Template> of(Path path) {
-        return Try.of(() -> readFromPath(path));
-    }
-
-}

Deleted: trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/TemplateProcessing.java
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/TemplateProcessing.java	2020-02-02 00:57:43 UTC (rev 53636)
+++ trunk/Master/texmf-dist/source/support/texplate/main/java/org/islandoftex/texplate/model/TemplateProcessing.java	2020-02-02 22:30:34 UTC (rev 53637)
@@ -1,391 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause
-package org.islandoftex.texplate.model;
-
-import io.vavr.control.Either;
-import org.islandoftex.texplate.util.MergingUtils;
-import org.islandoftex.texplate.util.MessageUtils;
-import org.islandoftex.texplate.util.PathUtils;
-import org.islandoftex.texplate.util.ValidatorUtils;
-import picocli.CommandLine;
-import picocli.CommandLine.Option;
-
-import java.nio.file.Path;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Callable;
-
-/**
- * The template processing class.
- *
- * @version 1.0
- * @since 1.0
- */
- at CommandLine.Command(
-        usageHelpWidth = 70,
-        name = "texplate"
-)
-public class TemplateProcessing implements Callable<Integer> {
-
-    // the file output, which will hold the
-    // result of the merging of both template
-    // and context data map from command line
-    @Option(
-            names = {"-o", "--output"},
-            description = "The output file in which the chosen "
-                    + "template will be effectively written. Make sure "
-                    + "the directory has the correct permissions for "
-                    + "writing the output file.",
-            required = true,
-            type = Path.class
-    )
-    private Path output;
-
-    // the template name
-    @Option(
-            names = {"-t", "--template"},
-            description = "The template and. The tool will "
-                    + "search both user and system locations and set the "
-                    + "template model accordingly, based on your specs."
-    )
-    private String template;
-
-    // the context data map that holds
-    // a set of key/value pairs to be
-    // merged with the template
-    @Option(
-            names = {"-m", "--map"},
-            description = "The contextual map that provides the "
-                    + "data to be merged in the template. This parameter "
-                    + "can be used multiple times. You can specify a map "
-                    + "entry with the key=value syntax (mind the entry "
-                    + "separator).",
-            arity = "1..*"
-    )
-    private Map<String, String> map;
-
-    @Option(
-            names = {"-c", "--config"},
-            description = "The configuration file in which the tool "
-                    + "can read template data, for automation purposes. Make "
-                    + "sure to follow the correct specification when writing "
-                    + "a configuration file.",
-            type = Path.class
-    )
-    private Path configuration;
-
-    /**
-     * The application logic, enclosed as a call method.
-     *
-     * @return An integer value denoting the exit status.
-     * @throws Exception An exception was raised in the application logic.
-     */
-    @Override
-    public Integer call() throws Exception {
-
-        // the exit status, originally
-        // set as a valid value
-        int exit = 0;
-
-        // configuration halt flag, indicating
-        // whether the tool has to end earlier
-        boolean halt = false;
-
-        Map<String, Object> cmap = new HashMap<>();
-
-        // ensure the context data map
-        // is at least instantiated
-        ensureMap();
-
-        // there is a configuration file
-        // found in the command line
-        if (has(configuration)) {
-
-            // print the configuration
-            // check line for status
-            MessageUtils.line("Checking configuration");
-
-            // try to read the configuration
-            // file into a proper object
-            Either<Throwable, Configuration> configChecking = Configuration.
-                    of(configuration).toEither();
-
-            // the configuration file
-            // seems to be valid, proceed
-            if (configChecking.isRight()) {
-
-                // print status line
-                MessageUtils.status(true);
-
-                // get the configuration file
-                Configuration config = configChecking.get();
-
-                // check if the configuration
-                // has a proper template
-                if (has(config.getTemplate())) {
-
-                    // if so, build the template if, and
-                    // only if, there's no one already
-                    // set through command line
-                    template = ensure(template, config.getTemplate());
-                }
-
-                // check if the configuration
-                // has a proper string/string map
-                if (has(config.getMap())) {
-
-                    // set the main configuration
-                    // map to be dealt later on
-                    cmap = config.getMap();
-                }
-
-                // print header about tidying
-                // up configuration variables
-                MessageUtils.line("Adjusting variables from file");
-                MessageUtils.status(true);
-                System.out.println();
-
-            } else {
-
-                // an error occurred, print it
-                // set exit code and halt
-                MessageUtils.status(false);
-                MessageUtils.error(configChecking.getLeft());
-                exit = -1;
-                halt = true;
-            }
-        } else {
-
-            // print header regarding
-            // no config file found
-            MessageUtils.line("Configuration file mode disabled");
-            MessageUtils.status(true);
-
-            // print a header regarding
-            // full command line mode
-            MessageUtils.line("Entering full command line mode");
-
-            // there's no configuration file, so we
-            // need to check whether there is not a
-            // pattern set in the command line
-            if (!has(template)) {
-
-                // print status
-                MessageUtils.status(false);
-
-                // print message
-                MessageUtils.error(new Exception("The template was not set "
-                        + "in the command line through the -t/--template "
-                        + "option. If not explicitly specified in a "
-                        + "configuration file, this option becomes mandatory, "
-                        + "so make sure to define it  either in the command "
-                        + "line or in a proper configuration file."));
-
-                exit = -1;
-                halt = true;
-
-            } else {
-
-                // print status
-                MessageUtils.status(true);
-                System.out.println();
-            }
-
-        }
-
-        // check whether we should
-        // halt prematurely
-        if (!halt) {
-
-            // initial message, preparing our
-            // hearts to the actual merging :)
-            System.out.println("Please, wait...");
-            System.out.println();
-
-            // now we need to obtain the actual
-            // template from a file stored either
-            // in the user home or in the system
-            MessageUtils.line("Obtaining reference");
-
-            // let us try to get the corresponding
-            // file from the template pattern
-            Either<Throwable, Path> fileChecking = PathUtils.
-                    getTemplatePath(template).toEither();
-
-            // the actual template file was
-            // found, so we can proceed to
-            // the next phase
-            if (fileChecking.isRight()) {
-
-                // updates the current
-                // status accordingly
-                MessageUtils.status(true);
-
-                // now it's time to compose the template
-                // object from its corresponding file
-                MessageUtils.line("Composing template");
-
-                // attempts to retrieve the template
-                // attributes from the referenced file
-                // to the actual template object
-                Either<Throwable, Template> templateComposition
-                        = Template.of(fileChecking.get()).toEither();
-
-                // the template composition was successful,
-                // so we can move on to the next phase
-                if (templateComposition.isRight()) {
-
-                    // updates the current
-                    // status accordingly
-                    MessageUtils.status(true);
-
-                    // once the template object is populated,
-                    // we need to verify if both template and
-                    // data map are not somehow conflicting
-                    MessageUtils.line("Validating data");
-                    Either<Throwable, Map<String, String>> dataValidation
-                            = ValidatorUtils.validate(templateComposition.get(),
-                            map).toEither();
-
-                    // the data validation was consistent,
-                    // so now the merging can be applied
-                    if (dataValidation.isRight()) {
-
-                        // updates the current
-                        // status accordingly
-                        MessageUtils.status(true);
-
-                        // now it's the final phase, in which
-                        // both template and data are merged
-                        MessageUtils.line("Merging template and data");
-
-                        // merge both template and context data
-                        // map
-                        Either<Throwable, Long> merging = MergingUtils.
-                                merge(templateComposition.get(),
-                                        dataValidation.get(),
-                                        output, cmap).toEither();
-
-                        // the merging was successful,
-                        // so now there's nothing else
-                        // to do, yay!
-                        if (merging.isRight()) {
-
-                            // updates the current
-                            // status accordingly
-                            MessageUtils.status(true);
-
-                            // print the final messge and
-                            // tell the user everything
-                            // went smooth!
-                            System.out.println();
-                            System.out.println("Done! Enjoy your template!");
-                            System.out.println("Written: "
-                                    + getSize(merging.get()));
-                        } else {
-
-                            // updates the current
-                            // status accordingly
-                            MessageUtils.status(false);
-
-                            // the merging failed, so the
-                            // exception is displayed and
-                            // the exit status is updated
-                            MessageUtils.error(merging.getLeft());
-                            exit = -1;
-                        }
-                    } else {
-
-                        // updates the current
-                        // status accordingly
-                        MessageUtils.status(false);
-
-                        // the data validation failed, so
-                        // the exception is displayed and
-                        // the exit status is updated
-                        MessageUtils.error(dataValidation.getLeft());
-                        exit = -1;
-                    }
-                } else {
-
-                    // updates the current
-                    // status accordingly
-                    MessageUtils.status(false);
-
-                    // the template composition failed,
-                    // so the exception is displayed and
-                    // the exit status is updated
-                    MessageUtils.error(templateComposition.getLeft());
-                    exit = -1;
-                }
-            } else {
-
-                // updates the current
-                // status accordingly
-                MessageUtils.status(false);
-
-                // the file checking failed, so
-                // the exception is displayed and
-                // the exit status is updated
-                MessageUtils.error(fileChecking.getLeft());
-                exit = -1;
-            }
-        }
-
-        // the exit status is returned,
-        // denoting whether the application
-        // was able to merge both template
-        // and data accordingly
-        return exit;
-    }
-
-    /**
-     * Ensures the data map is never pointed to a null reference.
-     */
-    private void ensureMap() {
-
-        // if the map is null, simply
-        // create a new instance
-        if (!has(map)) {
-            map = new HashMap<>();
-        }
-    }
-
-    /**
-     * Gets the file size in a human readable format.
-     *
-     * @param bytes The file size, in bytes.
-     * @return The file size in a human readable format.
-     */
-    private String getSize(long bytes) {
-        if (bytes < 1024) {
-            return bytes + " B";
-        } else {
-            int exponent = (int) (Math.log(bytes) / Math.log(1024));
-            return String.format("%.1f %cB", bytes / Math.pow(1024, exponent),
-                    "KMGTPE".charAt(exponent - 1));
-        }
-    }
-
-    /**
-     * Ensures the first parameter is not null, or sets it to the second one.
-     *
-     * @param <T>    The type.
-     * @param first  First parameter.
-     * @param second Second parameter.
-     * @return Either the first or the second one.
-     */
-    private <T> T ensure(T first, T second) {
-        return !has(first) ? second : first;
-    }
-
-    /**
-     * Checks whether the object exists.
-     *
-     * @param object The objects.
-     * @return Boolean value indicating whether the object exists.
-     */
-    private boolean has(Object object) {
-        return object != null;
-    }
-
-}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/Main.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/Main.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/Main.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate
+
+import kotlin.system.exitProcess
+import org.islandoftex.texplate.util.MessageUtils
+import picocli.CommandLine
+
+/**
+ * Main method. Note that it simply passes the control to the template
+ * processing class.
+ *
+ * @param args The command line arguments.
+ */
+fun main(args: Array<String>) {
+    // draw the application logo in the terminal (please have fixed fonts
+    // in your terminal for a nice display)
+    MessageUtils.drawLogo()
+    // calls the command line processing method and performs the actual
+    // application logic
+    @Suppress("SpreadOperator")
+    val exitCode = CommandLine(TemplateProcessing()).execute(*args)
+    exitProcess(exitCode)
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/TemplateProcessing.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/TemplateProcessing.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/TemplateProcessing.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate
+
+import java.nio.file.Path
+import java.util.concurrent.Callable
+import kotlin.math.ln
+import kotlin.math.pow
+import org.islandoftex.texplate.exceptions.InvalidTemplateException
+import org.islandoftex.texplate.model.Configuration
+import org.islandoftex.texplate.model.Template
+import org.islandoftex.texplate.util.MergingUtils.mergeTemplate
+import org.islandoftex.texplate.util.MessageUtils.error
+import org.islandoftex.texplate.util.MessageUtils.line
+import org.islandoftex.texplate.util.MessageUtils.status
+import org.islandoftex.texplate.util.PathUtils.getTemplatePath
+import org.islandoftex.texplate.util.ValidatorUtils.validate
+import picocli.CommandLine
+
+/**
+ * The template processing class.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+ at CommandLine.Command(usageHelpWidth = 70, name = "texplate")
+class TemplateProcessing : Callable<Int> {
+    // the file output, which will hold the result of the merging of both template
+    // and context data map from command line
+    @CommandLine.Option(
+            names = ["-o", "--output"],
+            description = ["The output file in which the chosen " +
+                    "template will be effectively written. Make sure " +
+                    "the directory has the correct permissions for " +
+                    "writing the output file."],
+            required = true,
+            type = [Path::class]
+    )
+    private val output: Path? = null
+
+    // the template name
+    @CommandLine.Option(
+            names = ["-t", "--template"],
+            description = ["The name of the template. The tool will " +
+                    "search both user and system locations and set the " +
+                    "template model accordingly, based on your specs."]
+    )
+    private var template: String? = null
+
+    // the context data map that holds a set of key/value pairs to be merged
+    // with the template
+    @CommandLine.Option(
+            names = ["-m", "--map"],
+            description = ["The contextual map that provides the " +
+                    "data to be merged in the template. This parameter " +
+                    "can be used multiple times. You can specify a map " +
+                    "entry with the key=value syntax (mind the entry " +
+                    "separator)."],
+            arity = "1..*"
+    )
+    private var map: Map<String, String>? = null
+
+    @CommandLine.Option(
+            names = ["-c", "--config"],
+            description = ["The configuration file in which the tool " +
+                    "can read template data, for automation purposes. Make " +
+                    "sure to follow the correct specification when writing " +
+                    "a configuration file."],
+            type = [Path::class]
+    )
+    private val configuration: Path? = null
+
+    /**
+     * The application logic, enclosed as a call method.
+     *
+     * @return An integer value denoting the exit status.
+     * @throws Exception An exception was raised in the application logic.
+     */
+    @Throws(Exception::class)
+    override fun call(): Int {
+        // the exit status, originally set as a valid value
+        var exit = 0
+        // configuration halt flag, indicating whether the tool has to end earlier
+        var halt = false
+        var cmap: Map<String, Any> = mutableMapOf()
+        // ensure the context data map is at least instantiated
+        ensureMap()
+        // there is a configuration file found in the command line
+        if (has(configuration)) {
+            line("Checking configuration")
+            try {
+                val config = Configuration.fromPath(configuration!!)
+                // the configuration file seems to be valid, proceed
+                status(true)
+                // check if the configuration has a proper template
+                if (has(config.template)) {
+                    // if so, build the template if, and only if, there's no one already
+                    // set through command line
+                    template = ensure(template, config.template)
+                }
+                // check if the configuration has a proper string/string map
+                if (has(config.map)) {
+                    // set the main configuration map to be dealt later on
+                    cmap = config.map
+                }
+                line("Adjusting variables from file")
+                status(true)
+                println()
+            } catch (e: InvalidTemplateException) {
+                // an error occurred, print it, set exit code and halt
+                status(false)
+                error(e)
+                exit = -1
+                halt = true
+            }
+        } else {
+            line("Configuration file mode disabled")
+            status(true)
+            line("Entering full command line mode")
+            // there's no configuration file, so we need to check whether there is
+            // not a pattern set in the command line
+            if (!has(template)) {
+                status(false)
+                error(Exception("The template was not set " +
+                        "in the command line through the -t/--template " +
+                        "option. If not explicitly specified in a " +
+                        "configuration file, this option becomes mandatory, " +
+                        "so make sure to define it  either in the command " +
+                        "line or in a proper configuration file."))
+                exit = -1
+                halt = true
+            } else {
+                status(true)
+                println()
+            }
+        }
+        // check whether we should halt prematurely
+        if (!halt) {
+            println("Please, wait...")
+            println()
+            // now we need to obtain the actual template from a file stored either
+            // in the user home or in the system
+            line("Obtaining reference")
+            try {
+                // let us try to get the corresponding file from the template pattern
+                val file = getTemplatePath(template!!)
+                // the actual template file was found, so we can proceed to
+                // the next phase
+                status(true)
+                line("Composing template")
+                // attempts to retrieve the template attributes from the referenced file
+                // to the actual template object
+                val template = Template.fromPath(file)
+                // the template composition was successful, so we can move on to the
+                // next phase
+                status(true)
+                // once the template object is populated, we need to verify if both
+                // template and data map are not somehow conflicting
+                line("Validating data")
+                val validatedData = validate(template, map!!)
+                // the data validation was consistent, so now the merging can be
+                // applied
+                status(true)
+                line("Merging template and data")
+                val merged = mergeTemplate(template, validatedData, output!!,
+                        cmap)
+                status(true)
+                println()
+                println("Done! Enjoy your template!")
+                println("Written: " + getSize(merged))
+            } catch (e: InvalidTemplateException) {
+                status(false)
+                error(e)
+                exit = -1
+            }
+        }
+        // the exit status is returned, denoting whether the application was able
+        // to merge both template and data accordingly
+        return exit
+    }
+
+    /**
+     * Ensures the data map is never pointed to a null reference.
+     */
+    private fun ensureMap() {
+        if (!has(map)) {
+            map = mutableMapOf()
+        }
+    }
+
+    /**
+     * Gets the file size in a human readable format.
+     *
+     * @param bytes The file size, in bytes.
+     * @return The file size in a human readable format.
+     */
+    @Suppress("MagicNumber")
+    private fun getSize(bytes: Long): String {
+        return if (bytes < 1024) {
+            "$bytes B"
+        } else {
+            val exponent = (ln(bytes.toDouble()) / ln(1024.0)).toInt()
+            "%.1f %cB".format(bytes / 1024.0.pow(exponent.toDouble()),
+                    "KMGTPE"[exponent - 1])
+        }
+    }
+
+    /**
+     * Ensures the first parameter is not null, or sets it to the second one.
+     *
+     * @param <T>    The type.
+     * @param first First parameter.
+     * @param second Second parameter.
+     * @return Either the first or the second one.
+    </T> */
+    private fun <T> ensure(first: T, second: T): T {
+        return if (!has(first)) second else first
+    }
+
+    /**
+     * Checks whether the object exists.
+     *
+     * @param obj The object.
+     * @return Boolean value indicating whether the object exists.
+     */
+    private fun has(obj: Any?): Boolean {
+        return obj != null
+    }
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/InvalidKeySetException.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/InvalidKeySetException.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/InvalidKeySetException.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.exceptions
+
+/**
+ * Handles exceptions when the context map contains invalid keys.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+class InvalidKeySetException : Exception {
+    /**
+     * Constructor.
+     */
+    constructor()
+
+    /**
+     * Constructor.
+     *
+     * @param message Message to be attached to the exception.
+     */
+    constructor(message: String?) : super(message)
+
+    /**
+     * Constructor.
+     *
+     * @param message Message to be attached to the exception.
+     * @param cause The throwable cause to be forwarded.
+     */
+    constructor(message: String?, cause: Throwable?) : super(message, cause)
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/InvalidTemplateException.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/InvalidTemplateException.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/InvalidTemplateException.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.exceptions
+
+/**
+ * Handles exceptions when the template is somehow invalid.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+class InvalidTemplateException : Exception {
+    constructor()
+
+    /**
+     * Constructor.
+     *
+     * @param message Message to be attached to the exception.
+     */
+    constructor(message: String?) : super(message)
+
+    /**
+     * Constructor.
+     *
+     * @param message Message to be attached to the exception.
+     * @param cause The throwable cause to be forwarded.
+     */
+    constructor(message: String?, cause: Throwable?) : super(message, cause)
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/TemplateMergingException.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/TemplateMergingException.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/exceptions/TemplateMergingException.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.exceptions
+
+/**
+ * Handles exceptions when the template merging failed.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+class TemplateMergingException : Exception {
+    /**
+     * Constructor.
+     */
+    constructor()
+
+    /**
+     * Constructor.
+     *
+     * @param message Message to be attached to the exception.
+     */
+    constructor(message: String?) : super(message)
+
+    /**
+     * Constructor.
+     *
+     * @param message Message to be attached to the exception.
+     * @param cause The throwable cause to be forwarded.
+     */
+    constructor(message: String?, cause: Throwable?) : super(message, cause)
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/Configuration.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/Configuration.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/Configuration.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model
+
+import com.moandjiezana.toml.Toml
+import java.nio.file.Path
+import org.islandoftex.texplate.exceptions.InvalidTemplateException
+
+/**
+ * The configuration model.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+data class Configuration(
+    /**
+     * The template of the template.
+     */
+    val template: String? = null,
+    /**
+     * Map of variables for the configuration.
+     */
+    val map: Map<String, Any> = mapOf()
+) {
+    /**
+     * Whether the configuration is valid.
+     */
+    private val isValid: Boolean
+        get() = template != null
+
+    companion object {
+        /**
+         * Reads the configuration from path.
+         *
+         * @param path The path.
+         * @return Configuration.
+         * @throws InvalidTemplateException The configuration is invalid.
+         */
+        @Throws(InvalidTemplateException::class)
+        fun fromPath(path: Path): Configuration {
+            val configuration: Configuration
+            val message = ("The provided configuration file looks invalid. " +
+                    "Please make sure the configuration has a valid syntax and " +
+                    "try again. ")
+            configuration = try {
+                // gets the configuration
+                Toml().read(path.toFile()).to(Configuration::class.java)
+            } catch (exception: IllegalStateException) {
+                // the configuration seems invalid
+                throw InvalidTemplateException(message + "In this particular " +
+                        "scenario, there is a possibility that the configuration " +
+                        "file does not follow the TOML specification. Please " +
+                        "refer to the user manual for further details and a " +
+                        "possible fix. Also, the raised exception message can " +
+                        "give us some hints on what happened.", exception)
+            }
+            return if (configuration.isValid) {
+                configuration
+            } else {
+                throw InvalidTemplateException(message + "Specifically, some " +
+                        "mandatory fields are either absent or empty in the " +
+                        "configuration file. It is quite important to strictly " +
+                        "follow the configuration specification, as detailed in " +
+                        "the user manual, or the tool will not work at all.")
+            }
+        }
+    }
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/Template.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/Template.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/Template.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model
+
+import com.moandjiezana.toml.Toml
+import java.nio.file.Path
+import org.islandoftex.texplate.exceptions.InvalidTemplateException
+
+/**
+ * The template model.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+data class Template(
+    /**
+     * Name of the template
+     */
+    val name: String? = null,
+    /**
+     * Description of the template
+     */
+    val description: String? = null,
+    /**
+     * List of authors who wrote the template
+     */
+    val authors: List<String> = listOf(),
+    /**
+     * List of requirements for the template
+     */
+    val requirements: List<String> = listOf(),
+    /**
+     * The document to be configured
+     */
+    val document: String? = null,
+    /**
+     * The map handlers
+     */
+    val handlers: Map<String, String> = mapOf()
+) {
+    /**
+     * Checks whether the template is valid.
+     *
+     * @return A boolean value indicating whether the template is valid.
+     */
+    private val isValid: Boolean
+        get() = !(name == null || description == null ||
+                document == null || name.isBlank() ||
+                description.isBlank() || authors.isEmpty() ||
+                document.isBlank())
+
+    companion object {
+        /**
+         * Reads the template from the provided path.
+         *
+         * @param path The path to the template file.
+         * @return The template object from the provided path.
+         * @throws InvalidTemplateException The template is invalid.
+         */
+        @JvmStatic
+        @Throws(InvalidTemplateException::class)
+        fun fromPath(path: Path): Template {
+            val template: Template
+            // the exception message, in case the conversion fails or if there are
+            // missing elements from the template
+            val message = ("The provided template file looks invalid. Please " +
+                    "make sure the template has a valid syntax and try again. ")
+            template = try {
+                Toml().read(path.toFile()).to(Template::class.java)
+            } catch (exception: IllegalStateException) {
+                throw InvalidTemplateException(message + "In this particular " +
+                        "scenario, there is a possibility that the template " +
+                        "file does not follow the TOML specification. Please " +
+                        "refer to the user manual for further details and a " +
+                        "possible fix. Also, the raised exception message can " +
+                        "give us some hints on what happened.", exception)
+            }
+            // the conversion hasn't failed, but we need to check whether the
+            // template is valid
+            return if (template.isValid) {
+                template
+            } else {
+                throw InvalidTemplateException(message + "Specifically, some " +
+                        "mandatory fields are either absent or empty in the " +
+                        "template file. It is quite important to strictly " +
+                        "follow the template specification, as detailed in the " +
+                        "user manual, or the tool will not work at all.")
+            }
+        }
+    }
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/BooleanHandler.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/BooleanHandler.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/BooleanHandler.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model.handlers
+
+/**
+ * Implements a boolean handler.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+class BooleanHandler : Handler {
+    /**
+     * Applies the conversion to the string.
+     *
+     * @param string The string.
+     * @return A list.
+     */
+    override fun apply(string: String?): Any? {
+        return listOf("true", "1", "yes").contains(string!!.toLowerCase())
+    }
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/CSVListHandler.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/CSVListHandler.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/CSVListHandler.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model.handlers
+
+/**
+ * Implements a CSV list handler.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+class CSVListHandler : Handler {
+    /**
+     * Applies the conversion to the string.
+     *
+     * @param string The string.
+     * @return A list.
+     */
+    override fun apply(string: String?): Any? {
+        return string?.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)".toRegex())
+                ?.map { it.trim() }
+                ?.filter { it.isNotEmpty() }
+    }
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/Handler.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/Handler.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/model/handlers/Handler.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.model.handlers
+
+/**
+ * Interface for handlers.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+interface Handler {
+    /**
+     * Apply the handler in the string.
+     *
+     * @param string The string.
+     * @return The resulting object.
+     */
+    fun apply(string: String?): Any?
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/HandlerUtils.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/HandlerUtils.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/HandlerUtils.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util
+
+import org.islandoftex.texplate.model.handlers.BooleanHandler
+import org.islandoftex.texplate.model.handlers.CSVListHandler
+import org.islandoftex.texplate.model.handlers.Handler
+
+/**
+ * Provides the map of handlers.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+object HandlerUtils {
+    /**
+     * Gets the map of handlers.
+     *
+     * @return Map of handlers.
+     */
+    @JvmStatic
+    val handlers: Map<String, Handler> = mapOf(
+            "to-csv-list" to CSVListHandler(),
+            "to-boolean" to BooleanHandler()
+    )
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/MergingUtils.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/MergingUtils.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/MergingUtils.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util
+
+import java.io.IOException
+import java.nio.file.Path
+import org.apache.velocity.VelocityContext
+import org.apache.velocity.exception.MethodInvocationException
+import org.apache.velocity.exception.ParseErrorException
+import org.apache.velocity.exception.ResourceNotFoundException
+import org.apache.velocity.exception.TemplateInitException
+import org.apache.velocity.runtime.RuntimeConstants
+import org.apache.velocity.runtime.RuntimeSingleton
+import org.apache.velocity.runtime.parser.ParseException
+import org.islandoftex.texplate.exceptions.TemplateMergingException
+import org.islandoftex.texplate.model.Template
+import org.islandoftex.texplate.util.HandlerUtils.handlers
+import org.slf4j.helpers.NOPLoggerFactory
+
+/**
+ * Merging utilities.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+object MergingUtils {
+    /**
+     * Merges both template and data.
+     *
+     * @param template The template object.
+     * @param map The data map.
+     * @param output The output path.
+     * @param cmap The configuration map.
+     * @return The length of the generated output.
+     * @throws TemplateMergingException The merging failed.
+     */
+    @JvmStatic
+    @Throws(TemplateMergingException::class)
+    @Suppress("TooGenericExceptionCaught")
+    fun mergeTemplate(
+        template: Template,
+        map: Map<String, String?>,
+        output: Path,
+        cmap: Map<String, Any>
+    ): Long {
+        // create the context map
+        val context = handle(template, map, cmap)
+        // create a file writer for the output reference
+        try {
+            output.toFile().writer().use { writer ->
+                // the document is actually read into a string reader
+                val reader = template.document!!.reader()
+                // load both runtime services and the template model from Velocity
+                val services = RuntimeSingleton.getRuntimeServices()
+                services.addProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE,
+                        NOPLoggerFactory().getLogger(""))
+                val reference = org.apache.velocity.Template()
+                // set both runtime services and document data into the template document
+                reference.setRuntimeServices(services)
+                reference.data = services.parse(reader, reference)
+                reference.initDocument()
+                // create the context based on the data map previously set
+                val entries = VelocityContext(context)
+                // merge both template and data into the file writer
+                reference.merge(entries, writer)
+            }
+        } catch (exception: Exception) {
+            // TODO: simplify
+            when (exception) {
+                is IOException, is MethodInvocationException, is ParseErrorException,
+                is ParseException, is ResourceNotFoundException, is TemplateInitException ->
+                    throw TemplateMergingException("An error occurred while " +
+                            "trying to merge the template reference with the " +
+                            "provided data. Make sure the template is correct " +
+                            "and try again. The raised exception might give us " +
+                            "some hints on what exactly happened. Typically, " +
+                            "make sure the template strictly follows the " +
+                            "Velocity 2.0 language syntax.", exception)
+                else -> throw TemplateMergingException("Fatal error occured. " +
+                        "This error should never happen. Please make a detailed " +
+                        "report to the developers.")
+            }
+        }
+        // simply return the length of the generated output file
+        return output.toFile().length()
+    }
+
+    /**
+     * Handles the context map.
+     *
+     * @param template The template model.
+     * @param map The context map.
+     * @param configmap The map from a configuration file.
+     * @return The new context map.
+     */
+    private fun handle(
+        template: Template,
+        map: Map<String, String?>,
+        configmap: Map<String, Any>
+    ): Map<String, Any?> {
+        // no handlers found
+        return if (template.handlers.isEmpty()) {
+            // create a new map from the command line map and put the values from
+            // the configuration file cmap, if absent
+            configmap.mapValues { it.value.toString() }.plus(map)
+        } else {
+            // get default handlers and set the resulting map
+            val result: MutableMap<String, Any?> = mutableMapOf()
+            // check each key from the map
+            map.forEach { (key: String, value: String?) ->
+                // there is a handler for the current key
+                if (template.handlers.containsKey(key) &&
+                        handlers.containsKey(template.handlers[key])) {
+                    // apply the handler and store the value in the map
+                    result[key] = handlers[template.handlers[key]]!!.apply(value)
+                } else {
+                    // simply store the value
+                    result[key] = value
+                    // TODO: should we warn about an invalid handler?
+                }
+            }
+
+            // put remaining values from the configuration file, if absent
+            configmap.plus(result)
+        }
+    }
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/MessageUtils.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/MessageUtils.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/MessageUtils.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util
+
+import java.time.LocalDate
+
+/**
+ * Message helper methods.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+object MessageUtils {
+    // the message width
+    private const val WIDTH = 60
+    // the application version
+    private val VERSION = MessageUtils::class.java.`package`.implementationVersion
+            ?: "DEVELOPMENT BUILD"
+
+    /**
+     * Prints a line in the terminal, without a line break.
+     *
+     * @param message The message to be printed.
+     */
+    @JvmStatic
+    fun line(message: String) {
+        print("$message ".padEnd(WIDTH - " [FAILED]".length, '.') + " ")
+    }
+
+    /**
+     * Prints the status in the terminal.
+     *
+     * @param result The boolean value.
+     */
+    @JvmStatic
+    fun status(result: Boolean) {
+        println(if (result) "[ DONE ]" else "[FAILED]")
+    }
+
+    /**
+     * Prints the error in the terminal.
+     *
+     * @param throwable The throwable reference.
+     */
+    @JvmStatic
+    fun error(throwable: Throwable) {
+        println("\n" + "HOUSTON, WE'VE GOT A PROBLEM ".padEnd(WIDTH, '-') +
+                "\n" + throwable.message + "\n" +
+                "".padStart(WIDTH, '-') + "\n")
+    }
+
+    /**
+     * Prints the application logo in the terminal.
+     */
+    fun drawLogo() {
+        println(
+                " ______         __   __          ___             __             \n" +
+                        "/\\__  _\\       /\\ \\ /\\ \\        /\\_ \\           /\\ \\__          \n" +
+                        "\\/_/\\ \\/    __ \\ `\\`\\/'/'  _____\\//\\ \\      __  \\ \\ ,_\\    __   \n" +
+                        "   \\ \\ \\  /'__`\\`\\/ > <   /\\ '__`\\\\ \\ \\   /'__`\\ \\ \\ \\/  /'__`\\ \n" +
+                        "    \\ \\ \\/\\  __/   \\/'/\\`\\\\ \\ \\L\\ \\\\_\\ \\_/\\ \\L\\.\\_\\ \\ \\_/\\  __/ \n" +
+                        "     \\ \\_\\ \\____\\  /\\_\\\\ \\_\\ \\ ,__//\\____\\ \\__/.\\_\\\\ \\__\\ \\____\\\n" +
+                        "      \\/_/\\/____/  \\/_/ \\/_/\\ \\ \\/ \\/____/\\/__/\\/_/ \\/__/\\/____/\n" +
+                        "                             \\ \\_\\                              \n" +
+                        "                              \\/_/                              \n"
+        )
+        println(
+                "TeXplate $VERSION, a document structure creation tool\n" +
+                        "Copyright (c) ${LocalDate.now().year}, Island of TeX\n" +
+                        "All rights reserved.\n"
+        )
+    }
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/PathUtils.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/PathUtils.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/PathUtils.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util
+
+import java.io.FileNotFoundException
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.Paths
+
+/**
+ * Helper methods for path handling.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+object PathUtils {
+    // the templates folder
+    private const val TEMPLATES_FOLDER = "templates"
+    // the user application folder
+    private const val USER_APPLICATION_FOLDER = ".texplate"
+
+    /**
+     * The user's template path.
+     */
+    private val userTemplatePath: Path
+        get() = try {
+            Paths.get(System.getProperty("user.home"),
+                    USER_APPLICATION_FOLDER, TEMPLATES_FOLDER)
+        } catch (e: RuntimeException) {
+            Paths.get(".")
+        }
+
+    /**
+     * Searches all paths looking for the provided template.
+     *
+     * @param name The name to be associated to a template file.
+     * @return The corresponding template file.
+     * @throws FileNotFoundException The template file could not be found.
+     */
+    @JvmStatic
+    @Throws(FileNotFoundException::class)
+    fun getTemplatePath(name: String): Path {
+        // the file has to be a TOML format, so we add the extension
+        val fullName = "$name.toml"
+        // the first reference is based on the user template path resolved with the
+        // file name
+        val reference = userTemplatePath.resolve(fullName)
+        // if the file actually exists, the search is done!
+        return if (Files.exists(reference)) {
+            reference
+        } else {
+            // the reference was not found in the user location, so let us try the
+            // system counterpart
+            try {
+                val tempFile = Files.createTempFile(null, null)
+                tempFile.toFile().writeText(PathUtils::class.java
+                        .getResource("/org/islandoftex/texplate/templates/texplate-$fullName")
+                        .readText())
+                tempFile
+            } catch (e: RuntimeException) {
+                throw FileNotFoundException("I am sorry, but the template " +
+                        "file '" + fullName + "' could not be found in the " +
+                        "default template locations (system and user). Make " +
+                        "sure the reference is correct and try again. For " +
+                        "reference, these are the paths I searched: '" +
+                        userTemplatePath + "'.")
+            }
+        }
+    }
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/ValidatorUtils.kt
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/ValidatorUtils.kt	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/kotlin/org/islandoftex/texplate/util/ValidatorUtils.kt	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package org.islandoftex.texplate.util
+
+import org.islandoftex.texplate.exceptions.InvalidKeySetException
+import org.islandoftex.texplate.model.Template
+
+/**
+ * Helper methods for validation.
+ *
+ * @version 1.0
+ * @since 1.0
+ */
+object ValidatorUtils {
+    /**
+     * Validates the data map based on the template requirements.
+     *
+     * @param template The template.
+     * @param map The data map.
+     * @return A boolean value indicating whether the data map is valid.
+     */
+    private fun validateRequirements(
+        template: Template,
+        map: Map<String, String>
+    ): Boolean {
+        return template.requirements.isNullOrEmpty() ||
+                template.requirements.containsAll(map.keys)
+    }
+
+    /**
+     * Validates the template pattern and the data map and throws an exception
+     * in case of failure.
+     *
+     * @param template The template.
+     * @param map The data map.
+     * @return The data map.
+     * @throws InvalidKeySetException There are invalid keys in the map.
+     */
+    @JvmStatic
+    @Throws(InvalidKeySetException::class)
+    fun validate(
+        template: Template,
+        map: Map<String, String>
+    ): Map<String, String> {
+        // for starters, we try to validate the template requirements
+        return if (validateRequirements(template, map)) {
+            map
+        } else {
+            throw InvalidKeySetException("The provided map does not " +
+                    "contain all the keys required by the chosen " +
+                    "template. Make sure to define such keys and try " +
+                    "again. Check the user manual for further details.")
+        }
+    }
+}

Added: trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/templates/texplate-article.toml
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/templates/texplate-article.toml	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/templates/texplate-article.toml	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,54 @@
+name = "article"
+description = """
+A simple template for the default article class, with support for new
+engines (with fontspec fallback), babel languages, geometry options,
+generic packages, and TikZ and corresponding libraries.
+"""
+authors = [ "Island of TeX" ]
+requirements = []
+document = '''
+\documentclass#if($options)[$options]#{end}{article}
+
+#if ($xetex || $luatex)
+\usepackage{fontspec}
+#else
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+#end
+#if ($geometry)
+
+\usepackage[$geometry]{geometry}
+#end
+#if ($babel)
+#if (!$geometry)
+
+#end
+\usepackage[$babel]{babel}
+#end
+#if ($packages)
+
+#foreach ($package in $packages)
+\usepackage{$package}
+#end
+#end
+#if ($tikz)
+
+\usepackage{tikz}
+#if ($libraries)
+#foreach ($library in $libraries)
+\usetikzlibrary{$library}
+#end
+#end
+#end
+
+\begin{document}
+
+\end{document}
+'''
+
+[handlers]
+xetex = "to-boolean"
+luatex = "to-boolean"
+tikz = "to-boolean"
+libraries = "to-csv-list"
+packages = "to-csv-list"

Added: trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/templates/texplate-standalone.toml
===================================================================
--- trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/templates/texplate-standalone.toml	                        (rev 0)
+++ trunk/Master/texmf-dist/source/support/texplate/main/resources/org/islandoftex/texplate/templates/texplate-standalone.toml	2020-02-02 22:30:34 UTC (rev 53637)
@@ -0,0 +1,45 @@
+name = "standalone"
+description = """
+A simple template for the standalone class, with support for
+class options, new engines (with fontspec fallback), list of
+packages, and TikZ and corresponding libraries.
+"""
+authors = [ "Island of TeX" ]
+requirements = []
+document = '''
+\documentclass#if($options)[$options]#{end}{standalone}
+
+#if ($xetex || $luatex)
+\usepackage{fontspec}
+#else
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+#end
+#if ($packages)
+
+#foreach ($package in $packages)
+\usepackage{$package}
+#end
+#end
+#if ($tikz)
+
+\usepackage{tikz}
+#if ($libraries)
+#foreach ($library in $libraries)
+\usetikzlibrary{$library}
+#end
+#end
+#end
+
+\begin{document}
+
+\end{document}
+'''
+
+[handlers]
+xetex = "to-boolean"
+luatex = "to-boolean"
+tikz = "to-boolean"
+libraries = "to-csv-list"
+packages = "to-csv-list"
+



More information about the tex-live-commits mailing list.