{"id":19917193,"url":"https://github.com/athos/pogonos","last_synced_at":"2025-04-07T15:05:23.814Z","repository":{"id":40417767,"uuid":"237243302","full_name":"athos/pogonos","owner":"athos","description":"Yet another Clojure(Script) implementation of the Mustache templating language","archived":false,"fork":false,"pushed_at":"2025-03-18T01:37:52.000Z","size":393,"stargazers_count":78,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-31T14:11:12.463Z","etag":null,"topics":["babashka","clojure","clojurescript","mustache","template"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/athos.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["athos"]}},"created_at":"2020-01-30T15:30:21.000Z","updated_at":"2025-03-18T01:37:56.000Z","dependencies_parsed_at":"2024-04-02T14:35:25.288Z","dependency_job_id":null,"html_url":"https://github.com/athos/pogonos","commit_stats":{"total_commits":283,"total_committers":3,"mean_commits":94.33333333333333,"dds":"0.017667844522968212","last_synced_commit":"c8b19c9f747d150a2cc154dd187bb17dd2547edf"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/athos%2Fpogonos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/athos%2Fpogonos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/athos%2Fpogonos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/athos%2Fpogonos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/athos","download_url":"https://codeload.github.com/athos/pogonos/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247675597,"owners_count":20977376,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["babashka","clojure","clojurescript","mustache","template"],"created_at":"2024-11-12T21:49:06.461Z","updated_at":"2025-04-07T15:05:23.788Z","avatar_url":"https://github.com/athos.png","language":"Clojure","funding_links":["https://github.com/sponsors/athos"],"categories":[],"sub_categories":[],"readme":"# Pogonos\n[![Clojars Project](https://img.shields.io/clojars/v/pogonos.svg)](https://clojars.org/pogonos)\n![build](https://github.com/athos/pogonos/workflows/build/badge.svg)\n[![codecov](https://codecov.io/gh/athos/pogonos/branch/master/graph/badge.svg)](https://codecov.io/gh/athos/pogonos)\n[![bb compatible](https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg)](https://book.babashka.org#badges)\n\nPogonos is yet another Clojure(Script) implementation of the [Mustache](http://mustache.github.io/) templating language.\n\n## Features\n\n- Compliant to the [Mustache spec](https://github.com/mustache/spec) v1.3.0 including lambdas and dynamic partials\n- Fast but clean implementation\n- User-friendly error messages for parsing errors\n- Handy API for use from the CLI\n- Supports Clojure, ClojureScript, self-hosted ClojureScript and Babashka\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Basics](#basics)\n  - [Outputs](#outputs)\n  - [Partials](#partials)\n  - [Error messages](#error-messages)\n  - [CLI usage](#cli-usage)\n  - [Babashka support](#babashka-support)\n\n## Installation\n\nAdd the following to your project's dependencies:\n\n[![Clojars Project](https://clojars.org/pogonos/latest-version.svg)](https://clojars.org/pogonos)\n\n## Usage\n\nIn this section, you'll see how to use Pogonos, but if you're not so familiar with the Mustache language itself, you might want to read its [documentation](http://mustache.github.io/) first.\n\n### Basics\n\n#### `render-string`\n\nThe easiest way to use the library is to just call `render-string`:\n\n```clojure\n(require '[pogonos.core :as pg])\n\n(pg/render-string \"Hello, {{name}}!\" {:name \"Rich\"})\n;=\u003e \"Hello, Rich!\"\n```\n\n`render-string` takes two arguments; a string that represents a Mustache template,\nand a map of the values passed to the template.\nThe keys of the map must be keywords.\n\nThen, the function will render the template and return the resulting string.\nIf you'd rather write out the rendering result to somewhere, instead of\ngenerating a string, you can use *outputs* to specify where to output the result.\nSee [Outputs](#outputs) for details.\n\n#### `render-file` / `render-resource`\n\n`render-string` has two look-alike cousins named `render-file` and `render-resource`.\nThe only difference between `render-string` and those functions is that `render-string`\ndirectly takes a template string as an argument whereas `render-file` and\n`render-resource` load a template stored in a text file on the file system\nor a resource file placed somewhere on the classpath.\n\nLet's say you have a template file located at `resources/sample.mustache`\nwhose content looks like the following:\n\n```console\n$ cat resources/sample.mustache\nHello, {{name}}!\n```\n\nThen, you can render the template using `render-file`:\n\n```clojure\n;; loads a template from a text file on the file system\n(pg/render-file \"resources/sample.mustache\" {:name \"Rich\"})\n```\n\nOr if you have the template file on your classpath, you can also render it\nwith `render-resource` (Here we assume the `resources` directory is\nincluded in the classpath):\n\n```clojure\n;; loads a template from a resource file on the classpath\n(pg/render-resource \"sample.mustache\" {:name \"Rich\"})\n```\n\n#### `parse-string` / `parse-file` / `parse-resource` / `render`\n\nAll the render functions mentioned above are more suitable for one-shot\nrendering. But if you want to render the same template with different contexts\nover and over again, it would be more efficient to prepare a *parsed template*\nprior to rendering.\n\nTo prepare a parsed template, use `parse-string` (or `parse-file` / `parse-resource`\naccordingly):\n\n```clojure\n(def template (pg/parse-string \"Hello, {{name}}!\"))\n\ntemplate\n;=\u003e #pogonos.nodes.Root{:body [\"Hello, \" #pogonos.nodes.Variable{:keys (:name), :unescaped? false} \"!\"]}\n```\n\nAnd then, you can render the parsed template using the `render` function:\n\n```clojure\n(pg/render template {:name \"Rich\"})\n;=\u003e \"Hello, Rich!\"\n\n(pg/render template {:name \"Alex\"})\n;=\u003e \"Hello, Alex!\"\n```\n\nAt the time, Pogonos does NOT have an internal mechanism to implicitly cache\nparsed results of previously rendered templates for better rendering performance.\nSo, if you want to use Pogonos in situations where the rendering performance matters,\nyou may have to cache parsed templates yourself.\n\n#### `check-string` / `check-file` / `check-resource` \\[`0.2.0+`\\]\n\nSince `0.2.0`, Pogonos also provides another set of functions: `check-string`, `check-file` and `check-resource`.\n\nThese functions try to parse the input template and check if the template\ncontains any Mustache syntax error. If any, they will report it as an exception.\nOtherwise, they will return `nil` silently:\n\n```clojure\n(pg/check-string \"Hello, {{name\")\n;; Execution error (ExceptionInfo) at pogonos.error/error (error.cljc:52).\n;; Missing closing delimiter \"}}\" (1:14):\n;;\n;;   1| Hello, {{name\n;;                   ^^\n\n(pg/check-string \"Hello, {{name}}!\")\n;=\u003e nil\n```\n\nThe verbosity of error messages can be controlled by an option.\nSee [Error messages](#error-messages) for details.\n\nWhat the `check-*` functions do is semantically equivalent to \"parsing a template\nand discarding the parsed result\". However, the `check-*` functions are generally\nmore efficient than `parse-*` in this regard because the former functions do not\nactually build a syntax tree.\n\n### Outputs\n\nAn output is the way to specify where to output the rendering result.\nBy default, Pogonos's render functions output the result as a string.\nYou can emulate this behavior by specifying `(pogonos.output/to-string)`\nas the output like the following:\n\n```clojure\n(require '[pogonos.output :as output])\n\n(pg/render-string \"Hello, {{name}}!\" {:name \"Clojure\"}\n                  {:output (output/to-string)})\n;=\u003e \"Hello, Clojure!\"\n```\n\nYou can also write out the rendering result to a file or to stdout via output:\n\n```clojure\n;; writes the rendering result to a file\n(pg/render-string \"Hello, {{name}}!\" {:name \"Clojure\"}\n                  {:output (output/to-file \"hello.txt\")})\n\n;; writes the rendering result to the stdout\n(pg/render-string \"Hello, {{name}}!\" {:name \"Clojure\"}\n                  {:output (output/to-stdout)})\n```\n\nIn general, it's more efficient to write out the rendering result\ndirectly to a file than to generate a resulting string and then write it\nout to the file.\n\n### Partials\n\nThe Mustache spec provides a feature named [partials](http://mustache.github.io/mustache.5.html#Partials). Partials can be used to include contents from other templates.\n\nLet's say you have a partial `resources/user.mustache` that looks like:\n\n```console\n$ cat resources/user.mustache\n\u003cstrong\u003e{{name}}\u003c/strong\u003e\n```\n\nYou can render a template that has a partial in it using the render\nfunctions out of the box:\n\n```clojure\n(pg/render-string \"\u003ch2\u003eUsers\u003c/h2\u003e{{#users}}{{\u003euser}}{{/users}}\"\n                  {:users [{:name \"Rich\"} {:name \"Alex\"}]})\n;=\u003e \"\u003ch2\u003eUsers\u003c/h2\u003e\u003cstrong\u003eRich\u003c/strong\u003e\u003cstrong\u003eAlex\u003c/strong\u003e\"\n```\n\nBy default, `render-string` and `render-resource` try to find\npartials on the classpath, and `render-file` on the file system.\n\nTo specify where to find partials explicitly, use the `:partials` option:\n\n```clojure\n(require '[pogonos.partials :as partials])\n\n(pg/render-string \"\u003ch2\u003eUsers\u003c/h2\u003e{{#users}}{{\u003euser}}{{/users}}\"\n                  {:users [{:name \"Rich\"} {:name \"Alex\"}]}\n                  {:partials (partials/file-partials \"resources\")})\n\n(pg/render-string \"\u003ch2\u003eUsers\u003c/h2\u003e{{#users}}{{\u003euser}}{{/users}}\"\n                  {:users [{:name \"Rich\"} {:name \"Alex\"}]}\n                  {:partials (partials/resource-partials)})\n```\n\nYou can even specify a map to utilize *inline* partials:\n\n```clojure\n(pg/render-string \"\u003ch2\u003eUsers\u003c/h2\u003e{{#users}}{{\u003euser}}{{/users}}\"\n                  {:users [{:name \"Rich\"} {:name \"Alex\"}]}\n                  {:partials {:user \"\u003cstrong\u003e{{name}}\u003c/strong\u003e\"}}\n```\n\nTo disable partials, specify `nil` for `:partials`:\n\n```clojure\n(pg/render-string \"\u003ch2\u003eUsers\u003c/h2\u003e{{\u003epartial}}\" {} {:partials nil})\n;=\u003e \"\u003ch2\u003eUsers\u003c/h2\u003e\"\n```\n\n### Error messages\n\nPogonos aims to provide user-friendly error messages for parse errors\nas one of its features, so that users can easily find where and why\nthe error occurred.\n\nFor example, if you miss the closing delimiter of a Mustache tag, you'll\nsee a detailed error message, like the following:\n\n```clojure\n(pg/render-string \"Hello, {{name\" {:name \"Clojure\"})\n\n;; Execution error (ExceptionInfo) at pogonos.error/error (error.cljc:52).\n;; Missing closing delimiter \"}}\" (1:14):\n;;\n;;   1| Hello, {{name\n;;                   ^^\n```\n\nYou can suppress these somewhat \"verbose\" error messages if you want,\nby specifying the option `{:suppress-verbose-errors true}`:\n\n```clojure\n(pg/render-string \"Hello, {{name\" {:name \"Clojure\"}\n                  {:suppress-verbose-errors true})\n\n;; Execution error (ExceptionInfo) at pogonos.error/error (error.cljc:52).\n;; Missing closing delimiter \"}}\" (1:14)\n```\n\nEven while disabling verbose error messages, you can get them back by calling\n`perr` explicitly:\n\n```clojure\n(pg/perr *e)\n;; Missing closing delimiter \"}}\" (1:14):\n;;\n;;   1| Hello, {{name\n;;                   ^^\n```\n\n### CLI usage\n\nPogonos 0.2.0+ provides a new API for calling functions via the `-X`/`-T` option of the Clojure CLI.\n\nTo use it as a `-X` program, add settings like the following to your `deps.edn`:\n\n```clojure\n{:aliases\n {...\n  template {:extra-deps {pogonos/pogonos {:mvn/version \"\u003cversion\u003e\"}}\n            :ns-default pogonos.api}\n  ...}}\n```\n\nTo use it as a `-T` tool, install Pogonos with the following command:\n\n```console\nclojure -Ttools install io.github.athos/pogonos '{:git/tag \u003cversion\u003e}' :as template\n```\n\nThen, you can call the API from the CLI like:\n\n```console\n# as -X program\n$ clojure -X:template \u003cfunction name\u003e ...\n\n# as -T tool\n$ clojure -Ttemplate \u003cfunction name\u003e ...\n```\n\nThe functions available from the CLI are as follows:\n\n- [`render`](#render)\n- [`check`](#check)\n\nYou will see the usage of each function in the next sections.\n\n#### `render`\n\nThe `render` function renders the specified Mustache template.\n\nThe example below renders a template file named `hello.mustache` with the data `{:name \"Clojurian\"}`:\n\n```console\n$ cat hello.mustache\nHello, {{name}}!\n$ clojure -X:template render :file '\"hello.mustache\"' :data '{:name \"Clojurian\"}'\nHello, Clojurian!\n$\n```\n\nThe `:file` option specifies the path to the template file to be rendered. The `:data` option specifies a map of values passed to the template.\n\nIf no template is specified, Pogonos will try to read the template from stdin:\n\n```console\n$ echo 'Hello, {{name}}!' | clojure -X:template render :data '{:name \"Clojurian\"}'\nHello, Clojurian!\n$\n```\n\nThe following table shows the available options for `render`:\n\n| Option | Description |\n| :----- | :---------- |\n| `:string` | Renders the given template string |\n| `:file` | Renders the specified template file |\n| `:resource` | Renders the specified template resource on the classpath |\n| `:output` | The path to the output file. If not specified, the rendering result will be emitted to stdout by default. |\n| `:data` | A map of values passed to the template |\n| `:data-file` | If specified, reads an EDN map from the file specified by that path and pass it to the template |\n\n#### `check`\n\nThe `check` function performs a syntax check on a given Mustache template, reporting any syntax errors that the Mustache template contains.\n\nThe example below checks a template file named `broken.mustache` that contains a syntax error:\n\n```console\n$ cat broken.mustache\nThis is a broken {{template\n$ clojure -X:template check :file '\"broken.mustache\"'\nChecking template broken.mustache\n[ERROR] Missing closing delimiter \"}}\" (broken.mustache:1:28):\n\n  1| This is a broken {{template\n                                ^^\n$\n```\n\nIf no template is specified, Pogonos will try to read the template to be checked from stdin:\n\n```console\n$ echo '{{#foo}}' | clojure -X:template check\n[ERROR] Missing section-end tag {{/foo}} (1:9):\n\n  1| {{#foo}}\n             ^^\n$\n```\n\nThe following table shows the available options for `check`:\n\n| Option | Description |\n| :----- | :---------- |\n| `:string` | Checks the given template string |\n| `:file` | Checks the specified template file |\n| `:dir` | Checks the template files in the specified directory |\n| `:resource` | Checks the specified template resource on the classpath |\n| `:include-regex` | Includes only the templates that match the given pattern |\n| `:exclude-regex` | Excludes the templates that match the given pattern |\n| `:only-show-errors` | Hides progress messages |\n| `:suppress-verbose-errors` | Suppresses verbose error messages |\n\nNote that the `:file`, `:dir` and `:resource` options allow multiple items to be specified separated by the file path separator (`:` (colon) on Linux/macOS and `;` (semicolon) on Windows).\n\nFor example, the following command will check three template files named `foo.mustache`, `bar.mustache` and `baz.mustache` (Here, we assume that the file path separator is `:`):\n\n```console\n$ clojure -X:template check :file '\"foo.mustache:bar.mustache:baz.mustache\"'\n```\n\n### Babashka support\n\nPogonos 0.2.1+ supports Babashka. It's supported in the following three ways:\n\n1. All the public function provided in `pogonos.core` can be used on Babashka, just like on the JVM\n2. The API for the CLI usage can also be used on Babashka\n3. Pogonos provides a standalone command that can be installed with [`bbin`](https://github.com/babashka/bbin) and works just like the [CLI tool](#cli-usage)\n\nThe following sections will focus on 3.\n\n#### Installation\n\nPogonos provides a standalone command named `pgns`. To install the `pgns` command, run the following:\n\n```console\nbbin install io.github.athos/pogonos\n```\n\n#### Usage\n\nThe `pgns` command can be used exactly like the CLI tool:\n\n```console\n$ echo 'Hello, {{name}}!' | pgns render :data '{:name \"Clojurian\"}'\nHello, Clojurian!\n$\n```\n\nBacked by [babashka.cli](https://github.com/babashka/cli), the `pgns` command also provides more UNIXy options:\n\n```console\n$ echo 'Hello, {{name}}!' | pgns render --data '{:name \"Clojurian\"}'\nHello, Clojurian!\n$\n```\n\nRun `pgns help` for more detailed usage.\n\n## License\n\nCopyright © 2020 Shogo Ohta\n\nThis program and the accompanying materials are made available under the\nterms of the Eclipse Public License 2.0 which is available at\nhttp://www.eclipse.org/legal/epl-2.0.\n\nThis Source Code may also be made available under the following Secondary\nLicenses when the conditions for such availability set forth in the Eclipse\nPublic License, v. 2.0 are satisfied: GNU General Public License as published by\nthe Free Software Foundation, either version 2 of the License, or (at your\noption) any later version, with the GNU Classpath Exception which is available\nat https://www.gnu.org/software/classpath/license.html.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fathos%2Fpogonos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fathos%2Fpogonos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fathos%2Fpogonos/lists"}