Computed values¶
A computed value is derived from answers, data and other computed values. It is declared once and available everywhere, so a template does not repeat the same expression in twelve files.
[computed]
package_name = "{{ project_name | lower | replace(' ', '-') }}"
module_name = "{{ package_name | replace('-', '_') }}"
year_range = "{{ start_year }}–{{ end_year }}"
Computed values sit in the same namespace as answers, so a template reads them the same way:
They may depend on:
- answers
- other computed values
- loaded data
- template metadata
Ordering¶
You do not declare an order. It is derived from the expressions, the same way question order is — see Questions § Evaluation order.
So this is fine, even though module_name is declared first:
[computed]
module_name = "{{ package_name | replace('-', '_') }}"
package_name = "{{ project_name | lower }}"
And this is an error, reported before any prompt appears:
Available while prompting¶
A computed value is resolved as soon as its dependencies are, which means a later question can use it:
[questions.project_name]
type = "string"
prompt = "Project name"
[computed]
package_name = "{{ project_name | lower | replace(' ', '-') }}"
[questions.crate_path]
type = "string"
prompt = "Crate directory"
default = "crates/{{ package_name }}"
The sequence is: ask project_name → compute package_name → ask crate_path
with crates/<computed> pre-filled.
Values, not strings¶
An expression that produces a single value keeps that value's type:
[computed]
# a boolean, not the string "true"
needs_tokio = "{{ cli and project_type == 'application' }}"
# a list, not "['a', 'b']"
all_features = "{{ data.features.base + extra_features }}"
This matters when the result is used in {% if %}, iterated, or serialised. An
expression that interpolates into surrounding text is a string, as you would
expect:
Names must not collide¶
A computed value may not have the same name as a question. They share a namespace, so one would silently shadow the other and which one won would depend on evaluation order.
Name collision in template `rust-library`.
`package_name` is declared both as a question and as a computed value.
Answers and computed values share one namespace, so a template cannot
tell them apart. Rename one.
Computed values are not recorded¶
Only answers are written to .config/git.tpl.toml. Computed values are
recomputed on every render, by design: they are a function of the answers and the
template, and a template that changes how package_name is derived should change
it for existing projects too.
Filtering choices¶
A computed value that resolves to a list can be pointed at by choices_from,
which is how a question's choices are filtered:
[questions.kind]
type = "choice"
choices = ["library", "application"]
[computed]
servers = "{{ ['nginx', 'caddy'] if kind == 'application' else [] }}"
[questions.server]
type = "choice"
choices_from = "servers"
The graph guarantees kind is answered before servers is computed, and
servers before server is asked. If the list comes out empty the question is
skipped entirely. See Choices.