Giter Club home page Giter Club logo

clostache's Introduction

Clostache

{{ mustache }} for Clojure.

Compliant with the Mustache spec since version 1.0. Supporting lambdas since version 1.1.

Works with Clojure 1.5 since version 1.5. If you want to use Clostache in Clojure 1.3 or 1.4 projects, use version 1.4. In Clojure 1.2 projects, use version 1.1.

Build Status

Usage

The easiest way to use Clostache in your project is via Clojars.

Leiningen:

[de.ubercode.clostache/clostache "1.4.0"]

Maven:

<dependency>
  <groupId>de.ubercode.clostache</groupId>
  <artifactId>clostache</artifactId>
  <version>1.4.0</version>
</dependency>

To install it via cljr, run:

cljr install de.ubercode.clostache/clostache

This is how you use Clostache:

(use 'clostache.parser)
(render "Hello, {{name}}!" {:name "Felix"})

You can render a resource from the classpath like this:

(use 'clostache.parser)
(render-resource "templates/hello.mustache" {:name "Michael"})

Each function supports an optional third argument, containing partials (see below).

Examples

Variable replacement

Variables are tags enclosed by two curly brackets (mustaches) and will be replaced with the respective data.

Template:

Hello, {{person}}!

Data:

{:person "World"}

Output:

Hello, World!

Escaped output

The following characters will be replaced with HTML entities: &"<>. Tags that use three curly brackets or start with {{& will not be escaped.

Template:

Escaped: {{html}}
Unescaped: {{{html}}}
Unescaped: {{&html}}

Data:

{:html "<h1>Hello, World!</h1>"}

Output:

Escaped: &lt;h1&gt;Hello, World!&lt;/h1&gt;
Unescaped: <h1>Hello, World!</h1>
Unescaped: <h1>Hello, World!</h1>

Sections

Sections start with a tag beginning with {{# and end with one beginning with {{/. Their content is only rendered if the data is either the boolean value true, a value or a non-empty list.

Template:

{{#greet}}Hello, World!{{/greet}}

Data:

{:greet true}

Output:

Hello, World!

In case of a list, the section's content is rendered for each element, and it can contain tags refering to the elements.

Template:

<ul>
{{#people}}
    <li>{{name}}</li>
{{/people}}
</ul>

Data:

{:people [{:name "Felix"} {:name "Jenny"}]}

Output:

<ul>
    <li>Felix</li>
    <li>Jenny</li>
</ul>

For single values, the section is rendered exactly once.

Template:

{{#greeting}}{{text}}!{{/greeting}}

Data:

{:greeting {:text "Hello, World"}}

Output:

Hello, World!

Inverted sections

Inverted sections start with a tag beginning with {{^ and end with one beginning with {{/. Their content is only rendered if the data is either the boolean value false or an empty list.

Template:

{{^ignore}}Hello, World!{{/ignore}}

Data:

{:ignore false}

Output:

Hello, World!

Comments

Comments are tags that begin with {{!. They will not be rendered.

Template:

<h2>Felix' section<h2>
{{! Look ma, I've written a section }}

Output:

<h2>Felix' section</h2>

Dotted names

Dotted names are a shorter and more convenient way of accessing nested variables or sections.

Template:

{{greeting.text}}

Data:

{:greeting {:text "Hello, World"}}

Output:

Hello, World

Implicit iterators

Implicit iterators allow you to iterate over a one dimensional list of elements.

Template:

<ul>
{{#names}}
    <li>{{.}}</li>
{{/names}}
</ul>

Data:

{:names ["Felix" "Jenny"]}

Output:

<ul>
    <li>Felix</li>
    <li>Jenny</li>
</ul>

Partials

Partials allow you to include other templates (e.g. from separate files).

Template:

Hello{{>names}}!

Data:

{:people [{:name "Felix"} {:name "Jenny"}]}

Partials:

{:names "{{#people}}, {{name}}{{/people}}"}

Output:

Hello, Felix, Jenny!

Set delimiters

You don't have to use mustaches, you can change the delimiters to anything you like.

Template:

{{=<% %>=}}
Hello, <%name%>!

Data:

{:name "Felix"}

Output:

Hello, Felix!

Lambdas

You can also call functions from templates.

Template:

{{hello}}
{{#greet}}Felix{{/greet}}

Data:

{:hello "Hello, World!"}
{:greet #(str "Hello, " %)}

Output:

Hello, World!
Hello, Felix!

Functions can also render the text given to them if they need to do something more complicated.

Template:

"{{#people}}Hi {{#upper}}{{name}}{{/upper}}{{/people}}"

Data:

{:people [{:name "Felix"}] 
 :upper (fn [text] 
          (fn [render-fn] 
            (clojure.string/upper-case (render-fn text))))}

Output:

Hello FELIX

Development

Make sure you have Leiningen 2 installed.

To run the spec tests, fetch them like this:

git submodule update --init

And run them against all supported Clojure versions:

lein all test

License

Copyright (C) 2014 Felix H. Dahlke

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Contributors

clostache's People

Contributors

annapawlicka avatar fhd avatar julianbirch avatar liquidz avatar michaelklishin avatar pastjean avatar rgeoghegan avatar ryancole avatar santervo avatar simonl2002 avatar stanistan avatar stuarth avatar trevor avatar zeroem avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clostache's Issues

Dollar sign fails.

The test named test-render-with-dollar-sign is currently failing on version 1.4.0

(= "Hello, $Felix!" (render "Hello, {{! This is a comment.}}{{name}}!"
                            {:name "$Felix"}))
; => false

(render "Hello, {{! This is a comment.}}{{name}}!"
        {:name "$Felix"})
; => "Hello, \\$Felix!"

Test fail with Clojure 1.6 (escaping backslashes)

The unit test fail with current Clojure 1.6. It looks like a change between 1.4 and 1.5 broke the escaping of backslashes in the code. Maybe something related to the handling of regular expressions?

% perl -i -pe 's/1\.3\.0/1.6.0/g;' project.clj && lein test
WARNING: :warn-on-reflection is deprecated in project.clj; use :global-vars.
Reflection warning, clojure/core/incubator.clj:84:7 - reference to field getClass can't be resolved.
Reflection warning, clojure/core/incubator.clj:84:7 - reference to field isArray can't be resolved.

lein test clostache.test-parser

lein test :only clostache.test-parser/test-render-html-unescaped

FAIL in (test-render-html-unescaped) (test_parser.clj:22)
expected: (= "&\\\"<>" (render "{{{string}}}" {:string "&\\\"<>"}))
  actual: (not (= "&\\\"<>" "&\\\\\"<>"))

lein test :only clostache.test-parser/test-render-with-dollar-sign

FAIL in (test-render-with-dollar-sign) (test_parser.clj:9)
expected: (= "Hello, $Felix!" (render "Hello, {{! This is a comment.}}{{name}}!" {:name "$Felix"}))
  actual: (not (= "Hello, $Felix!" "Hello, \\$Felix!"))

lein test clostache.test-specs

Ran 42 tests containing 163 assertions.
2 failures, 0 errors.
Tests failed.

set delimeters inside squiggly braces not handled properly

I'm trying to use clostache to insert values into a latex template. I've changed the set delimeters to <% %> because {{ occurs in latex. However, I ran into a case where I have a template like the following:

\name{<% name %>}

The resulting template (when name is "Foo") is:

\nameFoo

I looked at the code, and this seems to be a result of process-set-delimiters replacing instances of the chosen delimiters with {{ and }}, so in my example, after process-set-delimiters, template becomes:

\name{{{ name }}}

And because mustache uses {{{ as a delimiter for unescaped insertion, this is a problem. I've tested this using mustache from the command-line, and there it works as expected.

Here's a failing test case:

(deftest test-set-delimiters-with-curly-braces
  (is (= (render "{{=<% %>=}}\n{<% foo %>}" {:foo "bar"}) "{bar}")))

I looked at the code, but sadly, I'm very new to clojure and so I'm a little lost as to how to proceed to resolve this situation. If you could give me any pointers as to how this might be solved, I'll be glad to make an attempt at it.

Thanks!

LGPL Licensing

We're running into a bit of a licensing issue which I'm hoping could be solved. Most clojure dependencies are distributed under EPL rather LGPL. One of the finer points of EPL is you can create closed-source applications that use your library. The LGPL requires you distribute your library SxS for dynamic relinking should someone want to swap versions.

On some level this doesn't really matter for clostache itself - clostache is Clojure only. Jars let you do the above pretty easily. If you just use clostache server-side without giving users software binaries, there aren't any disclosure requirements to your end users.

The rough part is cljstache - the clojurescript fork of clostache. Given the way clojurescript compiles code (under advanced compilation), making a library dynamically linkable is extremely difficult. It's not really a design goal for most javascript.

I know this might be a long shot, but would this project consider re-licensing it's code under the EPL? There's only about 15 contributors so it might be doable. The license is extremely similar but allows for unmodified closed-source use.

UTF8 support

My template is rendered without some special language symbols. Does it support UTF-8?

Silly documentation detail

The doc section about implicit iterators lists the opening tag as {#names}} when it should be {{#names}}.

It's a nit, but it seemed worth mentioning.

Nesting function calls

Hello there,

Given this data:
{:format #(format-date %)}
{:user {:created-at (now)}}

And this template:
{{#format}}{{user.created-at}}{{/format}}

The "format-date" function receives {{#user}}{{created-at}}{{/user}}.

Is this expected behavior? Shouldn't the parser parse the expressions inside out?

Allow lambda sections to render text

From the mustache manual:

When the value is a callable object, such as a function or lambda, the object will be invoked and passed the block of text. The text passed is the literal block, unrendered. {{tags}} will not have been expanded - the lambda should do that on its own. In this way you can implement filters or caching.

After looking at the code appears that if a section is a function we apply it to the body

(if (fn? section-data) 
  (section-data (:body section))
   ...)

Which means there is no way for the lambda to render that text. Perhaps like the javascript mustache implementation a additional parameter should be passed into the lambda (https://github.com/janl/mustache.js#functions) for use in rendering the section contents if necessary.

An example:

(def template "{{#people}}Hi {{#upper}}{{name}}{{/upper}} {{/people}}")

(def data 
  {:people [{:name "Tom"}, {:name "Bob"}] 
   :upper (fn [text render-fn] (clojure.string/upper-case (render-fn text)))})

(render template data)
=> "Hi TOM Hi BOB"

Infinite loop when rendering a template with a template inside

Hi there ๐Ÿ‘‹

I've hit an issue where a call to render never returns: (Using [cljstache "2.0.1"])

user=> (require 'cljstache.core)
nil
user=> (cljstache.core/render "{{ foo }}" {:foo "{{ foo }}"})
"{{ foo }}" ;; This works OK
user=> (cljstache.core/render "{{ foo.a }}" {:foo {:a "{{ foo.a }}"}})
;; This never returns

Inconsistency with mustache for {{.}}

You can (ab)use sections and {{.}} to conditionally include passages like this in mustache:

Template: {{#foo}}quox: {{.}}{{/foo}}
Data (JSON): {"foo": "bar"}
Output: quox: bar

This does not work in clostache:

(render "{{#foo}}quox: {{.}}{{/foo}}" {:foo "bar"})
;=> "quox: bquox: aquox: r"

If this is not going to be addressed anytime soon, is there another way to achieve conditionals without nesting data? I want to fill a template with data from a CSV file, which is necessarily flat, so I can't just use the more reasonable {:foo {:value "bar"}} and {{#foo}} {{value}} {{/foo}}.

Allow functions in addition to maps for partials

I would like to be able to pass a function that takes a partial name and returns the template, instead of a map of names to partial templates. Using a memoized function would enable lazy loading of partial resources rather than having to load every partial that a template may use ahead of time.

Please replace :use with :refer

Hi,

having Clostache in the dependecy chain causes the following warning to be printed:

WARNING: seqable? already refers to: #'clojure.core/seqable? in namespace: clostache.parser, being replaced by: #'clojure.core.incubator/seqable?

It can be fixed by simply replacing :use with :require - particularly when :use was already using its most conservative variant (:only).

As a further hint, there's https://github.com/bbatsov/clojure-style-guide/tree/e3be6b321447939371f2318e620a281ef4367a58#prefer-require-over-use

Thanks!

-V

Strings now repeat according to length

Imagine you're working on

(render "{{#x}}0{{/x}}" { :x "hello" })

This prints "XXXXX". I'm inclined to think that it should print "X", and I imagine the equivalent code does in ruby (don't have it to hand). I'll send through a pull if we agree it's a bug.

Check for Seqable in render-section

In particular, at the moment it's not possible to render sorted-maps, which is actually pretty useful.

(def l [{:x 1} {:x 5} {:x 3}])
(def l2 (apply sorted-set-by #(compare (:x %1) (:x %2)) l))

(clostache.parser/render "{{#y}}{{x}}{{/y}}" {:y l})
; "153"
(clostache.parser/render "{{#y}}{{x}}{{/y}}" {:y l2})
; "", should have been "135"

Hope you agree this needs fixing. Will try to put together a patch for it myself.

Dot notation breaks inside repeated sections

(render "{{hotels.tripadvisor.popularity-rank}}"
        {:hotels {:tripadvisor {:popularity-rank 12}}})
=>"12"

But

(render "{{#hotels}}{{tripadvisor.popularity-rank}}{{/hotels}}"
        {:hotels [{:tripadvisor {:popularity-rank 12}}]})
=> ""

join-standalone-tags doesn't follow mustache spec

Hi Felix,

Thanks for making clostache, I've really enjoyed using it!

While tracking down a bug in my code, I realized that partials on their own lines don't save the newline at the end of partial, instead replacing it with whatever the partial contains, and looking through the clostache source, I found join-standalone-tags, which seemed the likely source of this behavior.

The commit messages for that function didn't give a lot of context for why this change was made, but it looks like this no longer follows the mustache spec for partials, which I found here. The overview of the partials spec doesn't define how to handle newlines at the EOL in the case of standalone partials, however, the test for the spec -- line 54 -- shows it as keeping the newlines at the end of standalone partials.

Is this the desired behavior for partials in clostache?

Thank you,
Evan

render and render-resource require a data map?

It looks like both render and render-resource require a data map. Would it be possible to add an additional function overload to allow one to exclude the data map, if it's not used?

Support non-clostache partials

I'll happily write this and send a pull request. At the moment, my plan is to

  1. allow you to specify a string as a partial, in which case it is interpreted as a clostache template
  2. allow you to specify a function, in which case it is invoked and assumed to return HTML.

My principal reason for wanting to do this is to handle small nasty pieces of code where hiccup is a better fit, but you could use it to mix and match template engines as well.

Include another file

I render e-mails content and i have signature on the end of e-mails. I can use partials as {{>siganture}}but i feel it is not the right way. I can also use my own function {{#include}}signature{{/include}} to load another file. But i guess it is something common and should be something to include file as standard. What do you think about that?

Support iteration over sets

If you try to iterate over a collection:
{{#things}} {{id}} {{/things}}
But things happens to be a set, nothing gets rendered.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.