http://www.perlmonks.org?node_id=1046837

wanna_code_perl has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

In some reporting code, I've decided to implement some simple markup to alleviate much of the tedium of including frequently used dynamic text in string outputs. It lets me turn something like this:

$obj->print(sprintf("Page %d - Section %d - %s", $obj->current_page, $obj->section->num, $obj->section->name, ) );

Into this (short codes shown here; they can also be spelled in full):

    $obj->print("Page ^(pg) - Section ^(sec:num) - ^(sec)");

(N.B.: I contrived this example so its purpose is immediately obvious. It still shows the expressiveness I want and bonus ability to re-use the same input string later with different results. The actual codes are extremely domain-specific.)

I've already written code for this that works, but my question is: what do you monks feel is the best syntax to allow escaping of a literal ^(foo) string? Suppose ^(foo) interpolates to 'BAR'. Here are the three options I thought of:

Option A - Backslash escapes

(Try to emulate Perl escapes, with limited success.)

BEFORE | AFTER | COMMENT -------------+--------+---------------- '^(foo)' | BAR | Regular use '\^(foo)' | ^(foo) | Escaped ^ "\^(foo)" | BAR | Perl squashes \^ | | in double quotes '\\^(foo)' | \^(foo)| Confused with '\BAR'? "\\^(foo)" | ^(foo) | Double quotes

Option B - ^^ escapes ^

(Similar to %% in printf)

BEFORE | AFTER | COMMENT -------------+--------+---------------- '^^(foo)' | ^(foo) | ^^ = escaped ^ '^^^(foo)' | ^BAR | ^^ = ^, ^(foo) '^^^^(foo)' | ^^BAR | ^^ = ^ twice '^ ^(foo)' | ^ BAR | No need to escape | ^ unless part of | ^(foo) match.

Option C - Special ^(...) code for literal carat

(Similar to HTML escapes or Pod C<$a E<lt>=E<gt> $b>, if a bit more concise.)

BEFORE | AFTER | COMMENT -------------+--------+----------------- '^(^)(foo)' | ^(foo) | ^(^) = escaped ^ '^^(foo)' | ^BAR | ^ literal if not | part of pattern '^(^)^(foo)' | ^BAR | Explicit escape '^^(^)(foo)' | ^^BAR | Or ^(^)^(^)^(foo)

I think most would agree that each of these invite potentially frustrating syntax (at least the errors are likely to be readily apparent), but I'd like to be as obvious as possible without a large documentation burden (while still supporting this sort of interpolation, of course).

A couple of other notes:

  • All interpolation patterns match m!\^\(\w+(?::\w+)?\)!
  • For (rare) cases where untrusted input or large sections of verbatim text must be included, there's a $obj->print_literal method (which is what $obj->print actually calls once it's completed the interpolation).
  • I don't need recommendations for String::Interpolate or existing parsing/templating systems. Recommend if you must, but please remember I'm looking for advice on semantics, not implementation.

Which syntax (including anything I haven't considered here) would you most prefer/most hate to use (and troubleshoot)? Why? I'd very much appreciate any relevant suggestions.