Table of Contents generated with DocToc
Suppose you've written a fabulously popular library, used the world
over by adoring fans. For the purposes of this document, let's say
this library is called "liquid-cool". If using liquid-cool takes a bit
of setup, or if you'd just like to give your users a little guidance
on how one might best create a new project which uses liquid-cool, you
might want to provide a template for it (just like how lein
already
provides built-in templates for "app", "plugin", and so on).
Let's assume your library's project dir is ~/dev/liquid-cool
. Create
a template for it like so:
cd ~/dev
lein new template liquid-cool --to-dir liquid-cool-template
Your new template would look like:
liquid-cool-template
├── LICENSE
├── project.clj
├── README.md
├── resources
| └── leiningen
| └── new
| └── liquid_cool
| └── foo.clj
└── src
└── leiningen
└── new
└── liquid_cool.clj
Note that you'll now have a new and separate project named "liquid-cool-template". It will have a group-id of "liquid-cool", and an artifact-id of "lein-template".
All lein templates have an artifact-id of "lein-template", and are differentiated by their group-id, which always should match the project for which they provide a template.
The files that your template will provide to users are in
resources/leiningen/new/liquid_cool
. The template generator starts you off
with just one, named "foo.clj". You can see it referenced in
src/leiningen/new/liquid_cool.clj
, right underneath the
->files data
line.
You can delete foo.clj
if you like (and its corresponding line in
liquid_cool.clj
), and start populating that
resources/leiningen/new/liquid_cool
directory with the files you wish to be
part of your template. For everything you add, make sure the
liquid_cool.clj
file receives corresponding entries in that ->files
call. For examples to follow, have a look inside the *.clj files for
the built-in
templates.
While developing a template, if you're in the template project directory,
leiningen will pick it up and you'll be able to test it. e.g. from the
liquid-cool-template
dir:
$ lein new liquid-cool myproject
will create a directory called myproject
, built from your template.
Alternately, if you want to test your template from another directory on
your system (without publishing your template to clojars yet), just run:
$ lein install
You should then be able to run lein new liquid-cool myproject
from any
directory on your system.
The default generated template uses stencil for templating, which implements the language-agnostic templating system Mustache. All the available tag types can be found in the Mustache manual; we will only go through the most common tag type here.
Suppose we want to add in a standard markdown readme file where the input name
is the main header of the file. To be able to do so, we must do two things:
Ensure that the input name is contained within the data
mapped to the key X,
and that we have a template file which looks up the key X by wrapping it in
double mustaches like so: {{X}}
. As for our input name, data
already
contains the line :name name
, which means we can lookup the input name by
writing {{name}}
in the template file. To try it out, save the following
contents in the file resources/leiningen/new/liquid_cool/README.md
:
# {{name}}
This is our readme!
And add the following line right underneath the ->files data
line:
["README.md" (render "README.md" data)]
Now, if we for instance say lein new liquid-cool liquid-cool-app
, the newly
generated project will contain a file named README.md
where the header is
liquid-cool-app
.
Clojure syntax can conflict with the default mustache tag delimiter. For example, when destructuring a nested map:
(let [{{:keys [a b]} :ab} some-map]
(do-something a b))
Stencil will interpret the {{
as the start of a mustache tag, but since the
contents are not valid mustache, the render fails. To get around this, we can
change the mustache delimiter temporarily, like so:
{{! Change mustache delimiter to <% and %> }}
{{=<% %>=}}
(let [{{:keys [a b]} :ab} some-map]
(do-something a b))
<%! Reset mustache delimiter %>
<%={{ }}=%>
Templates are just maven artifacts. Particularly, they need only be on
the classpath when lein new
is called. So, as a side-effect, you
can just put your templates in a jar and toss them on clojars and have
people install them like normal Leiningen plugins.
In Leiningen 2.x, templates get dynamically fetched if they're not
found. So for instance lein new heroku myproject
will find the
latest version of the heroku/lein-template
project from Clojars and
use that.
Users of Leiningen 1.x (1.6.2 or later) can also use the template if
they install the lein-newnew
plugin:
$ lein plugin install lein-newnew 0.3.6
$ lein new foo
$ lein new plugin lein-foo