Freemarker - dynamic name for user-defined directive invocation - freemarker

I'm trying to port some old Apache Tiles stuff to Freemarker, and one of the things the tiles code does is pass around variables with the names of tiles (jsp files more or less). These variables decide at runtime which templates are transcluded into the current template.
I'm trying to figure out if there's a way to do that with Freemarker macros. Something like this:
<#macro mything>
test
</#macro>
<#macro myotherthing>
other
</#macro>
<#"my${which}thing" />
If which="other", then the result should be
other
If which="", then the result should be:
test
However, I get an error:
Syntax error in nameless template in line 9, column 12:
Encountered "}", but was expecting one of:
"."
".."
<DOT_DOT_LESS>
"..*"
"?"
"??"
"!"
","
":"
"["
"("
<TERMINATING_EXCLAM>
I'm guessing a user-defined directive invocation can't be an expression or something. I guess I can use the include directive instead, but is there any way to do this with macro invocation--dynamically pick the macro name to invoke at runtime?

Like this:
<#.vars["my${which}thing"] />
Explanation:
<#macro m>...</#macro> just assigns the macro (macros are values) to the variable m
In <#m />, the m part is interpreted as a usual expression. It happens to be a simple variable reference expression in this case, but it could be a more complex expression as well (parenthesis may be needed around it though).
Variables with dynamic name can be read through the reserved .vars hash, like .vars[nameExpression].

Related

Prolog writeln with variables

I need to use writeln specifically in Prolog with a variable in it. What I am trying to make is an error that takes the first element of a list, and format does what I need almost perfectly, but again it specifically needs to be writeln.
I experimented for awhile and tried using '+' to concatenate the string like how it works in other languages, and when I use this
writeln("ERROR: \"" + Head + "\" is invalid.")
I almost succeed in what I want, and it prints
ERROR: " + a + " is invalid.
with the variable 'a' highlighted (another requirement) when I am trying to get
ERROR: "a" is invalid.
But I am unable to print it without using characters such as +, -, or | to contain the variable. I don't really understand what is going on and I haven't been able to find a reason on my own.
Using string_concat twice makes the proper string, but the variable is not highlighted like it is supposed to be.
As you already mentioned, using string_concat solves your problem as you want. String concatenation does not work like this in Prolog as it does in different languages. The reason why it still prints something when using the + while it throws without it is that the + is in an infix operator and is displayed as such in when using writeln because it also writes out the predicate names.
It will write the + infix when provided as prefix such as in this example:
writeln(+(3,2)).
It does not work without the + because then you simply have three different values after another. Quoted Atom, Variable filled with an Atom, Quoted Atom. Prolog expects a term though, so you run into a syntax error.

In YAML, is there any way to use variables inside a literal block scalar?

I'd like to use a variable inside a YAML literal block scalar.
Here's what I'd like to do:
markup: |
<title>
{{ title }}
</title>
Can that be done somehow?
I appreciate that this example would be trivial to execute without using a literal block scalar, but my actual use case inside a Foundation 6 stack would contain more markup and more variables than what I'm showing here.
There is no such thing as a variable inside a literal block scalar.
First of all there are no variables in YAML (the word variable, occurs only once in the YAML specification, in an example document, nr. 2.28).
And second, this is called literal for a reason. No interpretation is done of any of the characters.
Of course it is possible that some program that loads your document does something with the text between curly braces ({}). E.g interprets it as a jinja2 template. But without knowing what such a program does or expects, it is equally valid to expect something like that for the information between angle brackets (<>).
Therefore within YAML there is no way to use variables, neither inside of literal block-style scalars, nor outside them.
As for the templating: I have worked with program that generated YAML from a template and applied templates on the loaded string scalars (by recursively walking the tree). Your example could be either.

How to use variables with a dash in the name in Freemarker?

I'm trying to render a map that has keys containing minus signs (e.g. first-name), e.g.:
<head><title>Data - ${first-name} </title>
When I render it with FreeMarker, it complains and throws an exception. When I remove the '-' from the variable name, it works OK.
Is there any way to escape these variables in the Groovy template text?
The reason I'm doing it this way is to render a JSON blob from a 3rd party API, where I have no control over the variable-names.
Just checked the Freemarker manual. In chapter "Retrieving variables" you have the following statement:
For example, to read the variable whose name is "data-id", the
expression is data\-id, as data-id would be interpreted as "data minus
id". (Note that these escapes only work in identifiers, not in string
literals.)
These type of expressions work fine in Freemarker 2.3.23 (just tested to verify the documentation):
<#if test\-dash??>
${test\-dash}
</#if>
Only if you are using freemarker version from 2.3.22 or above. See freemarker variable syntax:
In this kind of expression, the variable name can only contain letters (including non-Latin letters), digits (including non-Latin digits), underline (_), dollar ($), at sign (#). Furthermore, the first character can't be a ASCII digit (0-9). Starting from FreeMarker 2.3.22, the variable name can also contain minus (-), dot (.), and colon (:) at any position, but these must be escaped with a preceding backslash (\), or else they would be interpreted as operators.

Access template model from a macro using parameter

I have a form with input field (the example is simplified):
<input type="text" value="${model.person.age}">
This is working as expected and now I want to write a macro for this:
<#macro input path inputType="text">
<input type="${inputType}" value="${model[path]}">
</#macro>
that can be used with
<#lib.input "person.age" />
I found ${model[path]} solution here but it does not work in my case. I'm using Freemarker 2.3.21 and Spring MVC 4.1.0.
Can't you just pass in the value itself, like <#lib.input person.age>? Anyway, if you absolutely have to pass in that expression unevaluated, then in the macro you can use value="${path?eval}". It need not be a "path" of course, it can be any kind of expression. (model[path] doesn't work, since the value inside the [] meant to be a variable name, which can contain any characters, not some kind of path expression.)

Freemarker Interpolation stripping whitespace?

I seem to be having issues with leading/trailing spaces in textareas!
If the last user has typed values into a textarea with leading/trailing spaces across multiple lines, they all disappear with exception to one space in the beginning & end.
Example:
If the textbox had the following lines: (quotes present only to help illustrate spaces)
" 3.0"
" 2.2 "
"0.3 "
it would be saved in the backend as
"<textarea id=... > 3.0/n 2.2 /n0.3 </textarea>"
My template (for this part) is fairly straightforward (entire template, not as easy...): ${label} ${textField}
When I load up the values again, I notice getTextField() is properly getting the desired string, quoted earlier... But when I look at the html page it's showing
" 3.0"
"2.2"
"0.3 "
And of course when "View Sourcing" it doesn't have the string seen in getTextField()
What I've tried:
Ensure the backend has setWhitespaceStripping(false); set
Adding the <#ftl strip_whitespace=false>
Adding the <#nl> on the same line as ${textField}
No matter what I've tried, I'm not having luck keeping the spaces after the interpolation.
Any help would be very appreciated!
Maybe you are inside a <#compress>...</#compress> (or <#compress>...</#compress>) block. Those filter the whole output on runtime and reduce whitespace regardless where it comes from. I recommend not using this directive. It makes the output somewhat smaller, but it has runtime overhead, and can corrupt output in cases like this.
FreeMarker interpolations don't remove whitespace from the inserted value, or change the value in any way. Except, if you are lexically inside an <#escape ...>....</#escape>, block, that will be automatically applied. But it's unlikely that you have an escaping expression that corrupts whitespace. But to be sure., you can check if there's any <#escape ...> in the same template file (no need to check elsewhere, as it's not a runtime directive).
strip_whitespace and #nt are only removing white-space during parsing (that's before execution), so they are unrelated.
You can also check if the whitespace is still there in the inserted value before inserting like this:
${textField?replace(" ", "[S]")?replace("\n", "[N]")?replace("\t", "[T]")}
If you find that they were already removed that probably means that they were already removed before the value was put into the data-model. So then if wasn't FreeMarker.

Resources