Take me over?
NAME
Interpolation - Arbitrary string interpolation semantics (using tie())
Version 0.74
Originaly by Mark-Jason Dominus (mjd-perl-interpolation@plover.com) Since version 0.66 maintained by Jenda@Krynicky.cz
SYNOPSIS
"la la la la $name{blah blah blah}"
;
# This is like doing:
$VAR
=
&function
(blah blah blah);
"la la la la $VAR"
;
DESCRIPTION
Beginners always want to write this:
"The sum of three and four is: 3+4"
;
And they want the 3+4
part to be evaluated, so that it prints this:
The sum of three and four is: 7
Of course, it's a double-quoted string, so it's not evaluated. The only things that are evaluated in double-quoted strings are variable references.
There are solutions to this, but most of them are ugly. This module is less ugly. Well .... this module IS ugly, but only inside. Your code may end up being nice.
The module also lets you define arbitrary interpolation semantics.
For example, you can say
And then you can write these:
"3 + 4 = $E{3+4}"
;
# Prints ``3 + 4 = 7''
$SALARY
= 57500;
"The salary is $money{$SALARY}"
;
# Prints ``The salary is $57,500.00''
$PLACE1
=
'SAN BERNADINO HIGH SCHOOL'
;
$PLACE2
=
'n.y. state'
;
"$placename{$PLACE1} is not near $placename{$PLACE2}"
;
# Prints ``San Bernadino High School is not near N.Y. State";
DETAILS
The arguments to the use
call should be name-function pairs. If the pair is ($n, $f)
, then $n
will be the name for the semantics provided by $f
. $f
must either be a reference to a function that you supply, or it can be the name of one of the built-in formatting functions provided by this package. Interpolation
will take over the %n
hash or $n
scalar in your package, and tie it so that acessing $n{X}
calls f(X)
and yields its return value.
If for some reason you want to, you can add new semantics at run time by using
import
Interpolation
name
=> function, ...
You can remove them again with
unimport Interpolation
'name'
, ...
Interpolators created by the import() or use statements are always PACKAGE variables, not lexicals! If you want a lexical interpolator you can create it like this:
my
%name
;
tie
%name
,
'Interpolation'
,
sub
{ ...
or
my
%name
;
tie
%name
,
'Interpolation'
,
'$$->$'
,
sub
{ ...
Built-ins
Interpolation
provides a few useful built-in formatting functions; you can refer to these by name in the use
or import
line. They are:
eval
- Evaluate the argument
null - Same as
eval
identity - Also the same as
eval
ucwords - Capitalize Input String Like This
commify -
1428571
=> 1,428,571.00
reverse
-
reverse
string
sprintf
- makes
"$S{'%.2f %03d'}{37.5,42}"
turn into
"37.50 042"
"$S{'%.2f %03d'}{37.5, 42}\n"
;
sprintf1 - makes
"$S{'%.2f %03d', 37.5,42}"
turn into
"37.50 042"
.
"$S{'%.2f %03d', 37.5, 42}\n"
;
sprintfX - makes
"$S{'%.2f %03d'}{37.5}{42}"
turn into
"37.50 042"
.
"$S{'%.2f %03d'}{37.5}{42}\n"
;
round - rounds the number
htmlescape - escapes characters special to HTML
"<b>
$htmlescape
{
$text
}</b>
tagescape - escapes characters special to HTML plus double and single quotes
qq{<input type=text name=foo value="$tagescape{$value}
">}
jsescape - escapes the text to be used in JavaScript
qq{<a href="JavaScript:foo( '$jsescape{$value}
' )">}
ADVANCED
It is posible to pass multiple (or no) arguments to your function. There are two alternate syntaxes:
$interpolator
{param1,param2}
$interpolator
{param1}{param2}
The first syntax will pass both arguments in $_[0] joined by $;, so you have to split them:
"3 + 4 = $add{3,4}\n"
;
The other syntax (used for example by builtin 'sprintf') requires quite some magic, so you probably wouldn't want to be forced to write it yourself. (See the source of this module if you want to know how strange is the code. )
The other problem is, that your interpolator might want to return an array. In that case you would anticipate to get all the items joined by $", but instead you would get only the last item. You have to join the list yourself:
To make your life easier this module provides a way to specify the "type" of the interpolator and then does the necessary splits, joins or magic itself.
The syntax is:
where the input is a list of '$'s, '@'s and '\@'s and the output is either '$' or '@'. The '$' means that the parameter/output should be left intact, while '@' forces a split/join on the parameter/output. Each character in the input list specifies the type of one brace in the call.
In addition you may add an asterisk to the end of the input type specification. This will allow for an arbitrary long list of parameters. Their type will be the last specified.
In previous version you had to "close" the interpolator call by $;. That is you would write something like "xxx $foo{par1}{par2}...{parn}{$;} xxx". While this is still suported it is NOT required anymore.
The default type is $->$.
Ex.:
'foo:$->$'
- pass the argument to function directly and evaluate it in
scalar
context
$foo
{param}
'foo:$->@'
- pass the argument to function directly, evaluate it in list context and
join
the result by $" (by
default
space)
$foo
{param}
'foo:@->$'
-
split
the first parameter by $; and pass the resulting list to the function,
evaluate in
scalar
context
$foo
{param1,param2,...}
'foo:@->@'
-
split
the first parameter by $; and pass the resulting list to the function,
evaluate in list context and
join
$foo
{param1,param2,...}
'foo:$$->$'
- ask
for
two parameters enclosed in braces
$foo
{param1}{param2}
'foo:$@->$'
- ask
for
two parameters enclosed in braces and
split
the second one
the list you get from the
split
will be added to
@_
flatlist
$foo
{paramA}{paramB1,paramB2,...}
'foo:$\@->$'
- ask
for
two parameters enclosed in braces and
split
the second one
the list you get from the
split
will be passed as a reference to an array
$foo
{paramA}{paramB1,paramB2,...}
'foo:$*->$ - ask
for
arbitrary number of
scalar
parameters
$foo
{par1}{par2}{par3}{$;}
'foo:->$ -
no
parameters. This creates a
tied
scalar
.
$foo
'foo:@->$'
=>
&bar
IS EQUAL TO
'foo'
=>
sub
{
&bar
(
split
/$;/o,
$_
[0])}
'foo:$->@'
=>
&bar
IS EQUAL TO
'foo'
=>
sub
{
join
$",
&bar
(
$_
[0])}
'foo:@->@'
=>
&bar
IS EQUAL TO
'foo'
=>
sub
{
join
$",
&bar
(
split
/$;/o,
$_
[0])}
'foo:\@->$'
=>
&bar
IS EQUAL TO
'foo'
=>
sub
{
&bar
([
split
/$;/o,
$_
[0] ])}
The builtin function sprintf could be implemented as: 'sprintf:$@->$' => sub {sprintf shift,@_}
Since version 0.69 it is possible to assign to interpolators of type '$->$', '$->@' and '->$'. The assigned value will be passed to the function you specified as the last parameter:
# print "Current count is $count\n";
if
(
@_
== 2) {
$count
{
$_
[0]} =
$_
[1]
}
else
{
$count
{
$_
[0]}++
}
};
# print "Current count of A is $count{A}\n";
Cool examples
- SQL
-
...
$db
->Sql(
"SELECT * FROM People WHERE LastName = $'{$lastname}'"
);
When passing strings to SQL you have to escape the apostrophes (and maybe some other characters) this crazy hack allows you do it quite easily.
Instead of "... = '$variable'" you write "... = $'{$variable}'" et voila ;-) You may of course use this syntax for whatever string escaping you like.
- IF
-
#or
#...
print
<<
"*END*"
Blah blah blah
There was
$count
$IF
{
$count
> 1}{jobs}{job}.
There was
$count
$?{
$count
> 1}{jobs}{job}.
There was
$count
job$?{
$count
> 1}{s}.
*END
*
Warnings
It's easy to forget that the index to a $hash{...}
is an arbitrary expression, unless it looks like an identifier. There are two gotchas here.
- Trap 1.
-
print
"$X{localtime}"
;
Here the
X
formatter is used to format the literal stringlocaltime
; thelocaltime
built-in function is not invoked. If you really want the current time, use one of these:print
"$X{+localtime}"
;
print
"$X{localtime()}"
;
- Trap 2.
-
print
"$X{What ho?}"
;
This won't compile---you get `search pattern not terminated'. Why? Because Perl sees the
?
and interprets it as the beginning of a pattern match operator, similar to/
. (Ah, you forgot that?
could be a pattern match delimiter even without a leadingm
, didn't you?) You really needprint
"$X{'What ho?'}"
;
The rule is simple: That thing in the braces that looks like a hash key really is a hash key, and so you need to put it in quotes under the same circumstances that you need to put any other hash key in quotes. You probably wouldn't expect this to work either:
$V
=
$X
{What ho?};
Author
Originaly, Mark-Jason Dominus (mjd-perl-interpolation@plover.com), Plover Systems co.
http://www.plover.com/~mjd/perl/Interpolation
http://Jenda.Krynicky.cz/#Interpolation