Passing parameters to freemarker macro dynamically - macros

I have a macro in freemarker say
<#macro printHelloWorld var1 var2>
${var1}
${var2}
</#macro>
When I call this macro as
<#macro printHelloWorld var1="hello" var2="world" />
It prints it in the expected manner
hello
world.
However, my problem is that I want to pass this variable names dynamically. I receive the macro arguments dynamically from a source,
and I want to be able to pass them on. Something along the lines of
$paramater1 = "var1"
$parameter2 = "var2"
$valueForParameter1 = "hello"
$valueForParameter2 = "world"
<#macro printHelloWorld paramater1=valueForParameter1 parameter2=valueForParameter2 />
which I want to be equivalent to the call
<#macro printHelloWorld var1="hello" var2="world" />
I have unable to find any solutions to it. Any tips ?
To describe the use-case more,
We actually have a freemarker macro, exposed via Java Tag which takes in dynamic attributes. I want to be able to call this macro, and provide the parameters to it dynamically.

There's no language feature that does quite that. There are two possibilities that do something similar:
One is simply passing an FTL hash (like a Map) to the macro, like <#myMacro params={'a': 1, 'b': 2}/>. In this case the parameter value expression can also be a Map dynamically created in Java.
The other is defining a macro like <#macro myMacro p1 p2 otherParams...>, in which case <#myMacro p1=11 p2=22 a=1 b=1/> will pass in {'a': 1, 'b': 2} as otherParams. In this case, however, you can't pass in an externally constructed hash as otherParams.

Related

Structures or javascript/json objects in progress ABL?

We're migrating to 11.6 and I think it's a great moment to rethink old habits and improve some concepts.
One of these things is the way we've been dealing with parameter definitions in functions and procedures.
Often times we have procedures and functions that need a lot of parameters, either inputs or outputs. Personally, for readability and maintainability reasons, I don't like to have methods with too many parameters explicitly declared.
In order to avoid this problem and still allow a large number of parameters, we've manually implemented a key-value pair approach with a single parameter.
But there are some drawbacks with this approach:
It's not possible to tell which parameters are needed just by inspecting
the method signature.
You'll always need some boilerplate code, like methods for pushing and pulling values.
So with that said, I would like to hear some others' thoughts.
Have you ever implemented something similar?
Is there something that could work as a javascript/json object in ABL?
Current implementation.
DEFINE VARIABLE param as CHARACTER NO-UNDO.
addValue('id', '1', param).
addValue('date', STRING(TODAY), param).
RUN internalProc (INPUT param).
Desired implementation
param.id = 1
param.date = TODAY
RUN internalProc (INPUT param)
Since you are mentioning 11.6, why not use a real class based object (available since 10.1A).
yourpackage\yourparameter.cls:
CLASS yourpackage.yourclass:
DEFINE PUBLIC PROPERTY date AS DATE NO-UNDO
GET.
SET.
DEFINE PUBLIC PROPERTY id AS INTEGER NO-UNDO
GET.
SET.
CONSTRUCTOR PUBLIC yourclass ():
SUPER ().
END CONSTRUCTOR.
CONSTRUCTOR PUBLIC yourclass (pid AS INTEGER, pdate AS DATE):
SUPER ().
ASSIGN THIS-OBJECT:id = pid
THIS-OBJECT:date = DATE .
END CONSTRUCTOR.
END CLASS.
and the internal procedure:
DEFINE INPUT PARAMETER poParameter AS yourpackage.yourclass NO-UNDO .
and the caller:
DEFINE VARIABLE o AS yourpackage.yourclass NO-UNDO.
o = NEW yourpackage.yourclass().
o:id = 42.
o:date = TODAY.
RUN internalProc (o) .
alternative caller:
RUN internalProc (NEW yourpackage.yourclass (1, TODAY)) .
The ABL provides full OO capabilities from 10.1A on and that can be mixed nicely with procedural code. And parameter objects (structs) is a great way to get started with a few inital classes in legacy code.

Use Freemarker macro call within string parameter of another macro

I have a macro A that formats some text
<#macro A text>...${text}...</#macro>
and another macro that has a parameter accepting text
<#macro B x>Another ${x} text</#macro>
I'd like to call B with the x paramter to be some text formatted by A, s.th. like
<#B x="<#A text='abc'/>" /> returns Another <#A text='abc'/>
Is this possible somehow?
I tried the ?interpret as suggested here by ddekany -
<#B x="<#A text='abc'/>"?interpret /> but this fails with the error:
Expecting a string, date or number here, Expression .... is
instead a freemarker.core.Interpret$TemplateProcessorModel
It seems that a macro call in FreeMarker is something different than a function call in other languages.
Macro calls aren't expressions, and hence can't be used inside expression (like a parameter value). Macros are called for their side effects, which is typically printing to the output, and have no return value. Functions (see #function) are called for their return values, and so function calls are expressions. So maybe you need functions, not a macros in this case.
But if you absolutely have to use the output of a macro call in an expression (or of any arbitrary template fragment), then you have to capture the output via <#assign someVar>...</#assign> or <#local someVar>...</#local>. (Beware with #escape. If you re-print the captured output with ${...}, it will be escaped again, so you will need #noescape.)
I found a workaround using assign:
<#assign a><#A text="abc"/></#assign>
<#B text=a/>
Anyway, it would be interesting to know if this is possible somehow.

Macro to evaluate expression and create import

This may seem odd and is perhaps impossible but I was wondering if there's a way to create a macro that evaluates the expression passed and performs an import.
I can get it to work easily enough if a string literal is the expression:
import macros
macro createImport(ex: expr): stmt =
result = newNimNode(nnkImportStmt)
result.add(ex)
createImport("strutils")
let a = ["foo", "bar", "baz"]
echo a.join("---") # using `join()` from the `strutils` module
But if a variable is passed, this of course will fail.
var s = "strutils"
createImport(s)
(Note that the import could be a string path do a module.)
I've attempted many adjustments to the macro and scoured the docs and source but I just can't find a way to get the actual value of the ex: expr to be useful in the import.
I can get the macro to create an echo call that reveals the string passed but any attempt to use it with the import ends up using the variable name itself.
I guess it makes since since it would seem that the value may not be available when the macro itself is evaluated. Is it possible to do this and if so, how?
I'm not quite sure why you need such a helper macro and whether it's a good idea, but the simplest way to achieve what you need is the following:
template my_import(x: static[string]) = import x
const x = "strutils"
my_import x

What does [parametertype[]]$Parameter mean?

I have seen PowerShell function parameters defined using the syntax param([parametertype[]]$Parameter) as well as param([parametertype]$Parameter).
Personally, I have always used the latter with (as far as I can tell) no problems. Can anyone explain what (if any) is the difference and why both are allowed and work?
[parametertype[]]$Parameter is a parametertype array of $Parameter
[parametertype]$Parameter is a $Parameter of parametertype
i.e.
> [string]$param_s = "parameter"
> [string[]]$param_a = "parameter", "param2", "param3"
> $param_s[1]
a
> $param_a[1]
param2
Note how param_s is a plain string and accesses the second position in the string when accessing index [1] compared to what's returned by param_a[1]
When used by the param keyword in a function / cmdlet definition, it just ensures the function will be passed correct data type
in powershell you don't have to define what parameter you are using but you can.
sometimes it can be handy if you want to define a parameter as [mandatory] for example.
in your example you defind an array type param[] and single type.
you can read more about Defining Parameters.

Use of option helper in Play Framework 2.0 templates

I'm trying to use views.html.helper.select (documentation here). I don't know scala, so i'm using java. I need to pass object of type Seq[(String)(String)] to the template right? Something like:
#(fooForm:Form[Foo])(optionValues:Seq[(String)(String)])
#import helper._
#form(routes.foo){
#select(field=myForm("selectField"),options=optionValues)
}
I don't know how to create Seq[(String)(String)] in java. I need to fill this collection with pairs (id,title) from my enum class.
Can somebody show me some expample how to use the select helper?
I found this thread on users group, but Kevin's answer didn't helped me a lot.
The right type is: Seq[(String, String)]. It means a sequence of pairs of String. In Scala there is a way to define pairs using the arrow: a->b == (a, b). So you could write e.g.:
#select(field = myForm("selectField"), options = Seq("foo"->"Foo", "bar"->"Bar"))
But there is another helper, as shown in the documentation, to build the sequence of select options: options, so you can rewrite the above code as:
#select(myForm("selectField"), options("foo"->"Foo", "bar"->"Bar"))
In the case your options values are the same as their label, you can even shorten the code to:
#select(myForm("selectField"), options(List("Foo", "Bar")))
(note: in Play 2.0.4 options(List("Foo", "Bar")) doesn't compile, so you can try this options(Seq("Foo", "Bar")))
To fill the options from Java code, the more convenient way is to use either the overloaded options function taking a java.util.List<String> as parameter (in this cases options values will be the same as their label) or the overloaded function taking a java.util.Map<String, String>.