With the help of this nice site, I have discovered </$importvariables> today. It was exactly what I was looking for!
Here I have to say, that the official doc about the \import pragma would be better indicating the existence of the </\importvariables> widgets which can handle dynamic import, that means import not known at the coding point but at thhe run point.
I was trying to have a kind of Visitor design patterns for an application for managing games tournaments, where in particular the way to manage points are rules and scoring system dependent. So I was obliged to import all the stuff manually before deciding what to call. With this widget, my code is clean and I have far more less things to import!
To be clearer, here is some of my code below.
First, I have created a generic macro which is acting a bit like if I had class template or an interface in tiddlywiki (the idea is not to write javascript when you can do it in plai tiddlywiki).
== code for $:/user/tournix/macros/calcScores
(tagged $:/tags/Macro
) ==
\define calcScores(result)
<<callForgedMethod targetMethod:calcScores extraName:result extraValue:"""$result$""">>
\end
== code for $:/user/tournix/macros/forgeMethod (not tagged!)==
\define forgeMethod() $(rule)$_$(scoring)$_$(targetMethod)$
The idea is to build 3 variables to build the real names of the function to call according to my naming scheme. This is handled in the next macro.
== code in $:/user/tournix/macros/callForgedMethod
(tagged $:/tags/Macro
) ==
\define callForgedMethod(targetMethod round extraName:extra extraValue)
\import $:/user/tournix/macros/forgeMethod
<$let
targetMethod = """$targetMethod$"""
data = "$:/user/data"
tournmt = {{{ [<data>get[tournament]] }}}
tourn = {{{ [<data>addsuffix[/tourn/]addsuffix<tournmt>] }}}
rule = {{{ [<tourn>getindex[rule]!is[blank]else[hott]] }}}
scoring = {{{ [<tourn>getindex[scoring]!is[blank]else[24zero]] }}}
imported = {{{ [[$:/user/]addsuffix<rule>addsuffix[/macros/scoring/]addsuffix<scoring>addsuffix[/]] }}}
>
<$action-log $message="callForgedMethod(targetMethod~$targetMethod$, round~$round$, extraName~$extraName$, extraValue~$extraValue$)" $filter="forgeMethod imported"/>
<$importvariables filter="[prefix<imported>]">
<$macrocall $name=<<forgeMethod>> round="""$round$""" $extraName$="""$extraValue$"""/>
</$\importvariables>
</$let>
\end
This is a little bit more convoluted that I wished, but it does the job and is somehow not too messy.
As a side note, I had to declare forgeMethod
in a tiddler of its own because:
- if it were declared within
callForgedMethod
it would not been able to handle the$(variable)$
notation for the variables created byforgeMethod
- it allows me to not tag it with
$:/tags/Macro
and to hide it from outside world where it could be used in an improper way.
The great benefit of the <$importvariables>
widget is that I can now simplify my naming. At the beginning, I was importing all the function before calling one. So all the functions had to have a different name, hence the long names. Now, they can have a simple name. Not calcScores
in my example, because this the name of the “generic” method and it shall be unique. But it could be as simple as _calcScores
for each such function. That would also lead to a simpler forgeMethod
macro:
\define forgeMethod() _$(targetMethod)$
Any comment and ideas about making it even simpler would be greatly appreciated!