summaryrefslogtreecommitdiff
path: root/doc/templates.md
blob: 096cd37b691971816d238322343812883e6f2664 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# Templates #

- [Default Variables](#default-variables)
- [Global Variables](#global-variables)
- [Batteries-Included Templates](#batteries-included-templates)
- [Custom Templates](#custom-templates)

## Default Variables

- `date`: defaults to today's date, under universal time, printed according to RFC 8601 (for example, `"2014-03-11"`)
- `datetime`: defaults to today's date and time, under universal time, printed according to RFC 8601 (for example, `"2014-03-11T16:06:02+00:00"`).
- `author_name`: Defaults to `"Anonymous"`
- `author_email`: Defaults to `"anonymous@example.org"`
- `apps_dir`: Directory where OTP applications should be created in release projects. Defaults to `"apps/"`.
- `copyright_year`: Defaults to the current year, under universal time.


## Global Variables

Global variables can be set by editing the file at `$HOME/.rebar3/templates/globals`:

    {variables, [
        {author_name, "My Name Is A String"},
        {copyright_year, "2014-2022", "The year or range of years for copyright"},
        {my_custom_var, "hello there"}
    ]}.

This will let you define variables for all templates.

Variables left undefined will be ignored and revert to the default value.

The override order for these variables will be: Defaults < $HOME/.rebar3/templates/globals < command line invocation.

## Batteries-Included Templates ##

Rebar3 ships with a few templates installed, which can be listed by calling `rebar3 new`:

    → ./rebar3 new
    app (built-in): OTP Application
    lib (built-in): OTP Library application (no processes)
    release (built-in): OTP Release structure for executable programs
    plugin (built-in): Rebar3 plugin

Any custom plugins would be followed as `<plugin_name> (custom): <description>`.

Details for each individual plugin can be obtained by calling `rebar3 new help <plugin>`:

    → ./rebar3 new help plugin
    plugin:
            built-in template
            Description: Rebar3 plugin
            Variables:
                    name="myplugin" (Name of the plugin)
                    desc="A rebar plugin" (Short description of the plugin's purpose)
                    date="2014-11-10"
                    datetime="2014-11-10T18:29:41+00:00"
                    author_name="Anonymous"
                    author_email="anonymous@example.org"
                    copyright_year="2014"
                    apps_dir="apps/" (Directory where applications will be created if needed)

All the variables there have their default values shown, and an optional explanation in parentheses.

The variables can also be [overriden globally](#global-variables).

A template can be run by calling:

    → ./rebar3 new plugin name=demo author_name="Fred H."
    ...

Alternatively, the `name` variable is special -- if the first argument to a template has no key associated with it, `name` is automatically added. The call above is therefore equivalent to:

    → ./rebar3 new plugin demo author_name="Fred H."
    ...

Then go to the directory created for the project by rebar3.

## Custom Templates ##

Custom templates can be added in `$HOME/.rebar3/templates/`. Each template is at least two files:

- `my_template.dtl`: There can be many of these files. They are regular Erlang files using the django template syntax for variable replacements.
- `my_template.template`; Called the *template index*, there is one per template callable from `rebar3`. This one will be visible when calling `rebar3 new my_template`. This file regroups the different \*.dtl files into a more cohesive template.

### File Syntax ###

#### Template Index ####

The following options are available:

    {description, "This template does a thing"}.
    {variables, [
      {var1, "default value"},
      {var2, "default", "explain what this does in help files"},
      {app_dir, ".", "The directory where the application goes"}
    ]}.
    {dir, "{{appdir}}/src"}.
    {file, "mytemplate_README", "README"}.
    {chmod, "README", 8#644}.
    {template, "myapp/myapp.app.src.dtl", "{{appdir}}/src/{{name}}.app.src"}.

Specifically:

- `description`: takes a string explaining what the template is for.
- `variables`: takes a list of variables in two forms:
  - `{Name, DefaultString, HelpString}`;
  - `{Name, DefaultString}`.
- `{dir, TemplatablePathString}`: creates a given directory. Variable names can be used in the path name.
- `{file, FilePath, DestFilePath}`: copies a file literally to its destination.
- `{template, DtlFilePath, TemplatablePathString}`: evaluates a given template. The `DtlFilePath` is relative to the template index.
- `{chmod, FilePath, Int}`: changes the permission of a file, using the integer value specified. Octal values can be entered by doing `8#640`.

### Example ###

As an example, we'll create a template for Common Test test suites. Create the directory structure `~/.rebar/templates/` and then go in there.

We'll start with an index for our template, called `ct_suite.template`:

```erlang
{description, "A basic Common Test suite for an OTP application"}.
{variables, [
    {name, "suite", "Name of the suite, prepended to the standard _SUITE suffix"}
]}.

{dir, "test"}.
{template, "ct_suite.erl.dtl", "test/{{name}}_SUITE.erl"}.
```

This tells rebar3 to create the test directory and to evaluate an [ErlyDTL](https://github.com/erlydtl/erlydtl) template. All the paths are relative to the current working directory.

Let's create the template file:

```erlang
-module({{name}}_SUITE).

-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl"). % Eunit macros for convenience

-export([all/0
        ,groups/0
       %,init_per_suite/1, end_per_suite/1
       %,init_per_group/2, end_per_group/2
        ,init_per_testcase/2, end_per_testcase/2
        ]).

-export([fail/1]).

all() -> [fail].

groups() -> [].

init_per_testcase(_Name, Config) -> Config.

end_per_testcase(_Name, _Config) -> ok.

fail(_Config) ->
    ?assert(false).
```

This one does very simple variable substitution for the name (using `{{name}}`) and that's all it needs.

Let's get to any existing project you have and try it:

    → ./rebar3 new
    app (built-in): OTP Application
    ct_suite (custom): A basic Common Test suite for an OTP application
    lib (built-in): OTP Library application (no processes)
    release (built-in): OTP Release structure for executable programs
    plugin (built-in): Rebar3 plugin

The first line shows that our `ct_suite` temlate has been detected and is usable.
Let's look at the details:

    → ./rebar3 new help ct_suite
    ct_suite:
            custom template (/home/ferd/.rebar3/templates/ct_suite.template)
            Description: A basic Common Test suite for an OTP application
            Variables:
                    name="suite" (Name of the suite, prepended to the standard _SUITE suffix)
                    date="2014-11-10"
                    datetime="2014-11-10T18:46:33+00:00"
                    author_name="Anonymous"
                    author_email="anonymous@example.org"
                    copyright_year="2014"
                    apps_dir="apps/" (Directory where applications will be created if needed)

The documentation from variables and the description are well in place. To apply the template, go to any of your OTP application's top-level directory:

    → ./rebar3 new ct_suite demo
    ===> Writing test/demo_SUITE.erl

And you will see the code in place.