File Coverage

blib/lib/Interpolation.pm
Criterion Covered Total %
statement 171 204 83.8
branch 40 66 60.6
condition 17 32 53.1
subroutine 33 34 97.0
pod n/a
total 261 336 77.6


line stmt bran cond sub pod time code
1             # -*- mode: cperl; cperl-indent-level: 2 -*-
2             #
3             # This module is copyright 1998 Mark-Jason Dominus.
4             # (mjd-perl-interpolation@plover.com)
5             # and 2002-2009 Jenda Krynicky
6            
7             package Interpolation;
8 4     4   89668 use vars '$VERSION';
  4         10  
  4         244  
9             $VERSION = '0.74';
10 4     4   21 use strict 'vars';
  4         9  
  4         114  
11 4     4   18 use warnings;
  4         12  
  4         115  
12 4     4   19 no warnings 'uninitialized'; # I don't want to be forced to use "if (defined $foo and $foo)
  4         21  
  4         132  
13            
14 4     4   19 use Carp;
  4         8  
  4         6996  
15            
16             %Interpolation::builtin = (
17             null => sub { $_[0] },
18             'eval' => sub { $_[0] },
19             identity => sub { $_[0] },
20             ucwords =>
21             sub {
22             my $s = lc shift;
23             $s =~ s/\b(\w)/\u$1/g;
24             $s
25             },
26             commify =>
27             sub {
28             local $_ = sprintf("%.2f", shift());
29             1 while s/^(-?\d+)(\d{3})/$1,$2/;
30             $_;
31             },
32             'reverse' =>
33             sub { reverse $_[0] },
34            
35             # Idea for funky sprintf trick thanks to Ken Fox
36             'sprintf' =>
37             sub {
38             my %fakehash;
39             my $format = shift;
40             tie %fakehash, Interpolation,
41             sub { sprintf($format, split /$;/o,$_[0])};
42             \%fakehash;
43             },
44             'sprintf1' =>
45             sub {
46             my ($fmt, @args) = split(/$;/o, shift());
47             sprintf($fmt, @args);
48             },
49             'sprintfx' => sub {sprintf shift(), @_},
50             'sqlescape' => sub {$_ = $_[0]; s/'/''/g; "'".$_},
51             'htmlescape' => sub {HTML::Entities::encode($_[0], '^\r\n\t !\#\$%\"\'-;=?-~')},
52             'tagescape' => sub {HTML::Entities::encode($_[0], '^\r\n\t !\#\$%\(-;=?-~')},
53             'jsescape' => sub {my $s = $_[0];$s =~ s/(['"])/\\$1/g;HTML::Entities::encode($s, '^\r\n\t !\#\$%\(-;=?-~')},
54             'round' => sub {
55             my ($number, $scale);
56             if (defined $_[1]) {
57             ($number, $scale) = @_;
58             } else {
59             ($number, $scale) = split /$;/o, $_[0];
60             }
61             $scale = 1 unless $scale;
62             return POSIX::floor(($number / $scale) + 0.5) * $scale;
63             }
64             );
65            
66             %Interpolation::needmodules = (
67             'htmlescape' => 'use HTML::Entities;',
68             'tagescape' => 'use HTML::Entities;',
69             'jsescape' => 'use HTML::Entities;',
70             'round' => 'use POSIX;',
71             );
72            
73             my %is_scalar;
74            
75             sub import {
76 27     27   217450 my $caller_pack = caller;
77 27         51 shift; # the "Interpolation"
78             # print STDERR "exporter args: (@_); caller pack: $caller_pack\n";
79 27 50       122 if (@_ % 2) {
80 0         0 croak "Argument list in `use Interpolation' must be list of pairs; aborting";
81             }
82 27         84 while (@_) {
83 23         47 my $hashname = shift;
84 23         41 my $function = shift;
85 23         29 my $type;
86            
87 23 50       72 $function = $hashname unless $function;
88            
89 23 100       113 if ($hashname =~ /^(.+):([\$\@\*\\]*->[\$\@])$/) {
90             # there is a type specification !
91 9         21 $type = $2;
92 9         16 $hashname = $1;
93 9 100       28 if ($type eq '->$') {
94 1         4 $is_scalar{$caller_pack . '::' . $hashname} = undef;
95 1         1 my $fakescalar;
96 1         4 tie $fakescalar, 'Interpolation::Scalar', $function;
97 1         2 *{$caller_pack . '::' . $hashname} = \$fakescalar;
  1         4  
98 1         4 next;
99             }
100             } else {
101 14         27 $type = '$->$';
102             }
103            
104 22         32 my %fakehash;
105 22         240 tie %fakehash, 'Interpolation', $type, $function;
106 22         39 *{$caller_pack . '::' . $hashname} = \%fakehash;
  22         143  
107             }
108 27         4795 return 1
109             }
110            
111             sub TIEHASH {
112 35     35   14923 shift;
113 35         70 my $function = pop();
114 35         67 my $type = shift();
115 35         52 my $my_pack;
116            
117 35 100 100     408 if ($type eq '' or $type eq '$->$') {
    100          
    100          
    100          
118 22         46 $my_pack = 'Interpolation::base'
119             } elsif ($type eq '$->@') {
120 4         11 $my_pack = 'Interpolation::S2A';
121             } elsif ($type eq '@->$') {
122 2         5 $my_pack = 'Interpolation::A2S';
123             } elsif ($type eq '@->@') {
124 2         5 $my_pack = 'Interpolation::A2A';
125             } else {
126 5         13 $my_pack = 'Interpolation::general';
127             }
128            
129 35 100       97 if (ref $function) {
130 20 50       78 croak "'use Interpolation' needs a reference to a subroutine or a builtin name!" unless ref $function eq 'CODE';
131             } else {
132 15         36 my $lc_function = lc $function;
133 15         15 my $lc_hashname;
134 15 50       44 if (exists $Interpolation::builtin{$lc_function}) {
135 15 100       51 if (exists $Interpolation::needmodules{$lc_function}) {
136 3     1   264 eval $Interpolation::needmodules{$lc_function};
  1     1   10  
  1     1   1  
  1         63  
  1         8  
  1         2  
  1         42  
  1         7  
  1         2  
  1         36  
137 3 50       9 croak $@ if $@;
138 3         8 delete $Interpolation::needmodules{$lc_function}
139             }
140 15         36 $function = $Interpolation::builtin{$lc_function};
141             } else {
142 0         0 croak "Unknown builtin $function!\n";
143             }
144             }
145            
146 35         200 $my_pack->TIEHASH($function, $type);
147             }
148            
149             sub unimport {
150 4     4   27 no warnings 'untie';
  4         9  
  4         1919  
151 1     1   3 my $caller_pack = caller;
152 1         2 my $my_pack = shift;
153 1         5 while (@_) {
154 1         3 my $varname = shift;
155 1 50       6 if (!exists $is_scalar{$caller_pack . '::' . $varname}) {
156 1         2 my $oldvar = *{$caller_pack . '::' . $varname}{HASH};
  1         5  
157 1         2 my %fakehash;
158 1         2 *{$caller_pack . '::' . $varname} = \%fakehash;
  1         3  
159 1         5 untie %$oldvar;
160             } else {
161 0         0 my $oldvar = *{$caller_pack . '::' . $varname}{SCALAR};
  0         0  
162 0         0 my $fakescalar;
163 0         0 *{$caller_pack . '::' . $varname} = \$fakescalar;
  0         0  
164 0         0 untie $$oldvar;
165 0         0 delete $is_scalar{$caller_pack . '::' . $varname};
166             }
167             }
168             }
169            
170             package Interpolation::base;
171 4     4   24 use Carp;
  4         7  
  4         2597  
172            
173             sub TIEHASH {
174 30     30   61 my $pack = shift;
175 30         54 my $cref = shift;
176 30 50       113 unless (ref $cref) { # Convert symbolic name to function ref
177 0 0       0 croak "Unknown builtin function `$cref'; aborting"
178             unless exists $Interpolation::builtin{lc $cref};
179            
180 0 0       0 eval $Interpolation::needmodules{lc $cref}
181             if (exists $Interpolation::needmodules{lc $cref});
182 0 0       0 croak $@ if $@;
183            
184 0         0 $cref = $Interpolation::builtin{lc $cref};
185             }
186 30         304 bless $cref => $pack; # That's it? Yup!
187             }
188            
189             # This is where the magic is.
190             sub FETCH {
191 75     75   23126 &{$_[0]}($_[1]); # For pre-5.004_04 compatibility
  75         378  
192             #$_[0]->($_[1]); # Line of the day?
193             }
194            
195             sub cut_it_out {
196 0     0   0 my $object = shift;
197 0         0 my $caller = (caller(1))[3];
198 0         0 croak "Not allowed to use $caller on an Interpolation variable; aborting";
199             }
200            
201             sub STORE {
202 2     2   2521 &{$_[0]}($_[1], $_[2]); # For pre-5.004_04 compatibility
  2         12  
203             #$_[0]->($_[1]); # Line of the day?
204             }
205            
206             *DELETE = \&cut_it_out;
207             *CLEAR = \&cut_it_out;
208             *EXISTS = \&cut_it_out;
209             *FIRSTKEY = \&cut_it_out;
210             *NEXTKEY = \&cut_it_out;
211            
212 22     22   5569 sub UNTIE {};
213            
214             package Interpolation::S2A;
215            
216             @Interpolation::S2A::ISA = ('Interpolation::base');
217             sub FETCH {
218 12     12   17157 join $", &{$_[0]}($_[1]);
  12         49  
219             }
220            
221             sub STORE {
222 2 50   2   2497 if (defined wantarray) {
223 2         9 join $", &{$_[0]}($_[1], $_[2]);
  2         13  
224             } else {
225 0         0 &{$_[0]}($_[1], $_[2]);
  0         0  
226             }
227             }
228            
229             package Interpolation::A2A;
230            
231             @Interpolation::A2A::ISA = ('Interpolation::base');
232             sub FETCH {
233 4     4   1027 join $", &{$_[0]}(split /$;/o,$_[1]);
  4         21  
234             }
235            
236             package Interpolation::A2S;
237            
238             @Interpolation::A2S::ISA = ('Interpolation::base');
239             sub FETCH {
240 6     6   3388 &{$_[0]}(split /$;/o,$_[1]);
  6         32  
241             }
242            
243             package Interpolation::general;
244 4     4   29 use Carp;
  4         9  
  4         4393  
245            
246             @Interpolation::general::ISA = ('Interpolation::base');
247            
248             sub TIEHASH {
249 5     5   11 my $pack = shift;
250 5         12 my $cref = shift;
251 5         11 my $type = shift;
252 5         12 my $self = [];
253 5 50       22 unless (ref $cref) {
254 0 0       0 croak "Unknown builtin function `$cref'; aborting"
255             unless exists $Interpolation::builtin{$cref};
256 0         0 $cref = $Interpolation::builtin{$cref};
257             }
258 5         18 $self->[0] = reverse $type;
259 5         11 $self->[1] = $cref;
260 5         34 bless $self => $pack; # That's it? Yup!
261             }
262            
263             sub FETCH {
264 19     19   11260 my $self = shift;
265 19         56 my $type = $self->[0];
266 19         44 my $par1type = chop ($type);
267 19         25 my (@param,$par1subtype);
268 19 100 66     126 if (($par1type eq '\\') and (($par1subtype = chop($type)) eq '@')) {
    50          
269 6         64 $param[0] = [split /$;/o, $_[0]]
270             } elsif ($par1type eq '@') {
271 0         0 @param = split /$;/o, $_[0]
272             } else {
273 13         40 $param[0] = $_[0]
274             }
275 19 50 66     204 if ($type =~ /^(.)>-$/ or ($type =~ /\*$/ and $_[0] eq $; and (undef @param or 1))) {
      0        
      33        
      33        
276 0         0 my $code = $self->[1];
277 0 0       0 if ($1 eq '$') {
278 0         0 &{$code}(@param);
  0         0  
279             } else {
280 0         0 join $", &{$code}(@param);
  0         0  
281             }
282             } else {
283 19 100       2383 if ($type =~ /\*$/) {$type .= $par1subtype.$par1type}; ##
  14         36  
284 19         27 my %fakehash;
285 19         129 tie %fakehash, Interpolation::internal, [$type, $self->[1], @param];
286 19         354 bless \%fakehash, Interpolation::internal;
287             }
288             }
289            
290             package Interpolation::internal;
291            
292             @Interpolation::internal::ISA = ('Interpolation::base');
293            
294             sub TIEHASH {
295 47     47   80 my ($pack, $self) = @_;
296 47         237 bless $self => $pack; # That's it? Yup!
297             }
298            
299             sub FETCH {
300 30     30   47 my $self = $_[0];
301 30         70 my $par1type = chop ($self->[0]);
302 30         35 my (@param,$par1subtype);
303 30 100 66     159 if ($par1type eq '\\' and (($par1subtype = chop($self->[0])) eq '@')) {
    50 33        
304 6         42 $param[0] = [split /$;/o, $_[1]]
305             } elsif ($par1type eq '@' and $self->[0] !~ /\*$/) {
306 0         0 @param = split /$;/o, $_[1]
307             } else {
308 24         60 $param[0] = $_[1]
309             }
310 30         65 push @$self, @param;
311 30 100 66     588 if ($self->[0] =~ /^(.)>-$/ or ($self->[0] =~ /\*$/ and $_[1] eq $; and pop @$self)) {
      66        
      33        
312 2         4 shift @$self;
313 2         6 my $code = shift @$self;
314 2 50       12 if ($1 eq '$') {
315 0         0 &{$code}(@$self);
  0         0  
316             } else {
317 2         4 join $", &{$code}(@$self);
  2         9  
318             }
319             } else {
320 28         38 my %fakehash;
321 28 50       104 if ($self->[0] =~ /\*$/) {$self->[0] .= $par1subtype.$par1type}; ##
  28         68  
322 28         84 tie %fakehash, Interpolation::internal, $self;
323 28         163 bless \%fakehash, Interpolation::internal;
324             }
325             }
326            
327             use overload '""' => sub {
328 17     17   27 my $self = tied(%{$_[0]});
  17         47  
329 17         106 my ($type, $code, @param) = @$self;
330 17 50       76 if ($type =~ /^\$/) {
331 17         27 &{$code}(@param);
  17         62  
332             } else {
333 0         0 join $", &{$code}(@param);
  0         0  
334             }
335 4     4   6823 };
  4         4044  
  4         38  
336            
337             package Interpolation::Scalar;
338            
339 4     4   4203 use Tie::Scalar;
  4         2310  
  4         110  
340 4     4   24 use Carp;
  4         8  
  4         1071  
341             our @ISA=(Tie::Scalar);
342            
343             sub TIESCALAR {
344 1     1   1 my $pack = shift;
345 1         2 my $cref = shift;
346 1 50       3 unless (ref $cref) { # symbolic names not supported
347 0         0 croak "Builtins not supported for type (void)->\$";
348             }
349 1         4 bless $cref => $pack; # That's it? Yup!
350             }
351            
352             sub FETCH {
353 5     5   2033 &{$_[0]}(); # For pre-5.004_04 compatibility
  5         22  
354             #$_[0]->($_[1]); # Line of the day?
355             }
356            
357             sub STORE {
358 1     1   419 &{$_[0]}($_[1]); # For pre-5.004_04 compatibility
  1         4  
359             #$_[0]->($_[1]); # Line of the day?
360             }
361            
362            
363             1;
364            
365             =head1 NAME
366            
367             Interpolation - Arbitrary string interpolation semantics (using tie())
368            
369             Version 0.74
370            
371             Originaly by Mark-Jason Dominus (mjd-perl-interpolation@plover.com)
372             Since version 0.66 maintained by Jenda@Krynicky.cz
373            
374             =head1 SYNOPSIS
375            
376             use Interpolation name => \&function, ...;
377             print "la la la la $name{blah blah blah}";
378            
379             # This is like doing:
380             $VAR = &function(blah blah blah);
381             print "la la la la $VAR";
382            
383             =head1 DESCRIPTION
384            
385             Beginners always want to write this:
386            
387             print "The sum of three and four is: 3+4";
388            
389             And they want the C<3+4> part to be evaluated, so that it prints
390             this:
391            
392             The sum of three and four is: 7
393            
394             Of course, it's a double-quoted string, so it's not evaluated. The
395             only things that are evaluated in double-quoted strings are variable
396             references.
397            
398             There are solutions to this, but most of them are ugly. This module
399             is less ugly. Well .... this module IS ugly, but only inside. Your code may end up being nice.
400            
401             The module also lets you define arbitrary interpolation semantics.
402            
403             For example, you can say
404            
405             use Interpolation money => \&commify_with_dollar_sign,
406             E => 'eval',
407             placename => 'ucwords',
408             ;
409            
410             And then you can write these:
411            
412             print "3 + 4 = $E{3+4}";
413             # Prints ``3 + 4 = 7''
414            
415             $SALARY = 57500;
416             print "The salary is $money{$SALARY}";
417             # Prints ``The salary is $57,500.00''
418            
419             $PLACE1 = 'SAN BERNADINO HIGH SCHOOL';
420             $PLACE2 = 'n.y. state';
421             print "$placename{$PLACE1} is not near $placename{$PLACE2}";
422             # Prints ``San Bernadino High School is not near N.Y. State";
423            
424             =head1 DETAILS
425            
426             The arguments to the C call should be name-function pairs. If
427             the pair is C<($n, $f)>, then C<$n> will be the name for the semantics
428             provided by C<$f>. C<$f> must either be a reference to a function
429             that you supply, or it can be the name of one of the built-in
430             formatting functions provided by this package. C will
431             take over the C<%n> hash or C<$n> scalar in your package, and tie it so that acessing
432             C<$n{X}> calls C and yields its return value.
433            
434             If for some reason you want to, you can add new semantics at run time
435             by using
436            
437             import Interpolation name => function, ...
438            
439             You can remove them again with
440            
441             unimport Interpolation 'name', ...
442            
443             Interpolators created by the import() or use statements are always PACKAGE variables, not lexicals!
444             If you want a lexical interpolator you can create it like this:
445            
446             my %name;
447             tie %name, 'Interpolation', sub { ...
448             or
449             my %name;
450             tie %name, 'Interpolation', '$$->$', sub { ...
451            
452            
453             =head2 Built-ins
454            
455             C provides a few useful built-in formatting functions;
456             you can refer to these by name in the C or C line. They are:
457            
458             eval - Evaluate the argument
459             null - Same as eval
460             identity - Also the same as eval
461            
462             ucwords - Capitalize Input String Like This
463            
464             commify - 1428571 => 1,428,571.00
465            
466             reverse - reverse string
467            
468             sprintf - makes "$S{'%.2f %03d'}{37.5,42}" turn into "37.50 042"
469             use Interpolation S => 'sprintf';
470             print "$S{'%.2f %03d'}{37.5, 42}\n";
471            
472             sprintf1 - makes "$S{'%.2f %03d', 37.5,42}" turn into "37.50 042".
473             use Interpolation S => 'sprintf1';
474             print "$S{'%.2f %03d', 37.5, 42}\n";
475            
476             sprintfX - makes "$S{'%.2f %03d'}{37.5}{42}" turn into "37.50 042".
477             use Interpolation 'S:$$*->$' => 'sprintfX';
478             print "$S{'%.2f %03d'}{37.5}{42}\n";
479            
480             sqlescape - escapes single quotes for use in SQL queries
481            
482             round - rounds the number
483             use Interpolation round => 'round'; print "The sum is: $round{$sum, 0.01}\n";
484             use Interpolation 'round:$$->$' => 'round'; print "The sum is: $round{$sum}{0.01}\n";
485            
486             htmlescape - escapes characters special to HTML
487             "$htmlescape{$text}
488             tagescape - escapes characters special to HTML plus double and single quotes
489             qq{}
490             jsescape - escapes the text to be used in JavaScript
491             qq{}
492             (the last three require module HTML::Entities)
493            
494             =head1 ADVANCED
495            
496             It is posible to pass multiple (or no) arguments to your function.
497             There are two alternate syntaxes:
498            
499             $interpolator{param1,param2}
500             $interpolator{param1}{param2}
501            
502             The first syntax will pass both arguments in $_[0] joined by $;, so you have to split them:
503            
504             use Interpolation add => sub{@_ = split /$;/o, $_[0]; $_[0] + $_[1]};
505             print "3 + 4 = $add{3,4}\n";
506            
507             The other syntax (used for example by builtin 'sprintf') requires quite some magic,
508             so you probably wouldn't want to be forced to write it yourself.
509             (See the source of this module if you want to know how strange is the code. )
510            
511             The other problem is, that your interpolator might want to return an array.
512             In that case you would anticipate to get all the items joined by $",
513             but instead you would get only the last item. You have to join the list yourself:
514            
515             use Interpolation foo => sub {join $", &bar($_[0])};
516            
517             To make your life easier this module provides a way to specify the "type" of the interpolator
518             and then does the necessary splits, joins or magic itself.
519            
520             The syntax is:
521            
522             use Interpolation 'name:input->output' => sub { ...
523            
524             where the input is a list of '$'s, '@'s and '\@'s and the output is either '$' or '@'.
525             The '$' means that the parameter/output should be left intact, while '@'
526             forces a split/join on the parameter/output. Each character in the input list
527             specifies the type of one brace in the call.
528            
529             In addition you may add an asterisk
530             to the end of the input type specification. This will allow for an arbitrary long
531             list of parameters. Their type will be the last specified.
532            
533             In previous version you had to "close" the interpolator call by $;.
534             That is you would write something like "xxx $foo{par1}{par2}...{parn}{$;} xxx".
535             While this is still suported it is NOT required anymore.
536            
537             The default type is $->$.
538            
539             Ex.:
540             'foo:$->$' - pass the argument to function directly and evaluate it in scalar context
541             $foo{param}
542             'foo:$->@' - pass the argument to function directly, evaluate it in list context and join
543             the result by $" (by default space)
544             $foo{param}
545             'foo:@->$' - split the first parameter by $; and pass the resulting list to the function,
546             evaluate in scalar context
547             $foo{param1,param2,...}
548             'foo:@->@' - split the first parameter by $; and pass the resulting list to the function,
549             evaluate in list context and join
550             $foo{param1,param2,...}
551             'foo:$$->$' - ask for two parameters enclosed in braces
552             $foo{param1}{param2}
553             'foo:$@->$' - ask for two parameters enclosed in braces and split the second one
554             the list you get from the split will be added to @_ flatlist
555             $foo{paramA}{paramB1,paramB2,...}
556             'foo:$\@->$' - ask for two parameters enclosed in braces and split the second one
557             the list you get from the split will be passed as a reference to an array
558             $foo{paramA}{paramB1,paramB2,...}
559             'foo:$*->$ - ask for arbitrary number of scalar parameters
560             $foo{par1}{par2}{par3}{$;}
561             'foo:->$ - no parameters. This creates a tied scalar.
562             $foo
563            
564            
565             'foo:@->$' => &bar IS EQUAL TO 'foo' => sub {&bar(split /$;/o, $_[0])}
566             'foo:$->@' => &bar IS EQUAL TO 'foo' => sub {join $", &bar($_[0])}
567             'foo:@->@' => &bar IS EQUAL TO 'foo' => sub {join $", &bar(split /$;/o, $_[0])}
568             'foo:\@->$' => &bar IS EQUAL TO 'foo' => sub {&bar([split /$;/o, $_[0] ])}
569            
570             The builtin function sprintf could be implemented as:
571             'sprintf:$@->$' => sub {sprintf shift,@_}
572            
573             Since version 0.69 it is possible to assign to interpolators of type '$->$', '$->@' and '->$'.
574             The assigned value will be passed to the function you specified as the last parameter:
575            
576             use Interpolation 'count:->$' => sub {if (@_) {$count = $_[0]} else {$count++}};
577             # print "Current count is $count\n";
578             use Interpolation 'count:$->$' => sub {
579             if (@_ == 2) {
580             $count{$_[0]} = $_[1]
581             } else {
582             $count{$_[0]}++
583             }
584             };
585             # print "Current count of A is $count{A}\n";
586            
587            
588            
589             =head1 Cool examples
590            
591             =over 2
592            
593             =item SQL
594            
595             use Interpolation "'" => sub {$_ = $_[0]; s/'/''/g; "'".$_};
596             ...
597             $db->Sql("SELECT * FROM People WHERE LastName = $'{$lastname}'");
598            
599             When passing strings to SQL you have to escape the apostrophes
600             (and maybe some other characters) this crazy hack allows you do it quite easily.
601            
602             Instead of "... = '$variable'" you write "... = $'{$variable}'" et voila ;-)
603             You may of course use this syntax for whatever string escaping you like.
604            
605             =item IF
606            
607             use Interpolation 'IF:$*->$' => sub {$_[0] ? $_[1] : $_[2]};
608             #or
609             use Interpolation '?:$*->$' => sub {$_[0] ? $_[1] : $_[2]};
610             #...
611             print <<"*END*"
612             Blah blah blah
613             There was $count $IF{$count > 1}{jobs}{job}.
614             There was $count $?{$count > 1}{jobs}{job}.
615             There was $count job$?{$count > 1}{s}.
616             *END*
617            
618             =back
619            
620             =head1 Warnings
621            
622             It's easy to forget that the index to a C<$hash{...}> is an arbitrary
623             expression, unless it looks like an identifier. There are two gotchas here.
624            
625             =over 4
626            
627             =item Trap 1.
628            
629             print "$X{localtime}";
630            
631             Here the C formatter is used to format the literal string
632             C; the C built-in function is not invoked. If
633             you really want the current time, use one of these:
634            
635             print "$X{+localtime}";
636             print "$X{localtime()}";
637            
638             =item Trap 2.
639            
640             print "$X{What ho?}";
641            
642             This won't compile---you get `search pattern not terminated'. Why?
643             Because Perl sees the C and interprets it as the beginning of a
644             pattern match operator, similar to C. (Ah, you forgot that C
645             could be a pattern match delimiter even without a leading C, didn't
646             you?) You really need
647            
648             print "$X{'What ho?'}";
649            
650             =back
651            
652             The rule is simple: That thing in the braces that looks like a hash
653             key really is a hash key, and so you need to put it in quotes under
654             the same circumstances that you need to put any other hash key in
655             quotes. You probably wouldn't expect this to work either:
656            
657             $V = $X{What ho?};
658            
659            
660             =head1 Author
661            
662             =begin text
663            
664             Originaly, Mark-Jason Dominus (C), Plover Systems co.
665             http://www.plover.com/~mjd/perl/Interpolation
666            
667             Now maintained by, C .
668             http://Jenda.Krynicky.cz/#Interpolation
669            
670             =end text
671            
672             =begin man
673            
674             Originaly, Mark-Jason Dominus (C), Plover Systems co.
675             http://www.plover.com/~mjd/perl/Interpolation
676            
677             Now maintained by, C .
678             http://Jenda.Krynicky.cz/#Interpolation
679            
680             =end man
681            
682             =begin html
683            
684            

Originaly, Mark-Jason Dominus (mjd-perl-interpolation@plover.com), Plover Systems co.

685             http://www.plover.com/~mjd/perl/Interpolation

686            
687             Now maintained by, Jenda Krynicky.
688             http://Jenda.Krynicky.cz/#Interpolation

689            
690             =end html
691            
692            
693             =cut
694            
695