3
$\begingroup$

Shortly, I want something like this to work:

 template = TemplateObject[
   ...
   RowBox[{"TemplateSlot", "[", "\"planet\"", "]"}]  (*valid boxes*)
   ...
 ] 

 template @ <|"planet" -> "Mars"|>
"Mars" (*expression*)

While template should contain RawBox[...] information which I can extract later.

The problem is that Inserting/CombinerFunction are not enough since they work, more or less like:

CombinerFunction[template @@ (InsertingFunction /@ args)]

While I need:

CombinerFunction[ToExpression[template] @@ (InsertingFunction /@ args)]

Details and requirements:

As an answer I want an expression where the template content (here boxes) is supplied to an InitializationFunction (here ToExpression) just before it is filled by e.g. `TemplateApply.

I can't use custom MyTemplateObject because this template may be somewhere deep and I want it to be activated by the very outer TemplateApply that may come out of the blue. So too deep for upvalues and I would like not to make custom MyTemplateApply.

Summing up:

test = Grid[{{1, yourAnswer[RowBox[...]]}}];

TemplateApply[test, <|"planet" -> "Mars"|>]

1 Mars

But I still want to be able to extract original boxes from test.

Another use case can be to have a string template in its raw form because by default StringTemplate["``<*1*>"] evaluates to TemplateObject[{TemplateSlot[1], "", TemplateExpression[1]}, InsertionFunction -> TextString, CombinerFunction -> StringJoin]

I have a solution but I feel like I missed something basic so I will hold on with posting it to not bias others.

$\endgroup$
1
$\begingroup$

This is the idiom I use:

TemplateWith[
  "a" -> TemplateExpression @ initializationFunction @ rawTemplate
, TemplateSlot["a"]
]

For OP's example:

template =  TemplateWith[
  "$$this$$" -> TemplateExpression @ ToExpression @ RowBox[{"TemplateSlot", "[", "\"planet\"", "]"}]
, TemplateSlot["$$this$$"] (* "a" would not be very unique*)
];


TemplateApply[template, <|"planet" -> "Mars"|>]
"Mars"

And I have access to the raw template too:

template[[1, 2, 1, 1]] (*or with pattern matching*)
RowBox[{"TemplateSlot", "[", "\"planet\"", "]"}]

And a more secure version in case we want to prevent initialized template from evaluation:

rawTemplate = RowBox[
  {"ToCharacterCode", "@", RowBox[{"TemplateSlot", "@", "\"\<planet\>\""}]}
];

template = TemplateObject[
  TemplateWith[
    "$$this$$" -> TemplateExpression @ MakeExpression @ rawTemplate
  , TemplateSlot["$$this$$"]
  ]
, CombinerFunction -> ReleaseHold
]

TemplateApply[template, <|"planet" -> "Mars"|>]
{77, 97, 114, 115}
template[[1, 1, 2, 1, 1]]
RowBox[{"ToCharacterCode", "@", RowBox[{"TemplateSlot", "@", "\"planet\""}]}]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.