1package Text::NeatTemplate; 2$Text::NeatTemplate::VERSION = '0.1101'; 3use strict; 4use warnings; 5 6=head1 NAME 7 8Text::NeatTemplate - a fast, middleweight template engine. 9 10=head1 VERSION 11 12version 0.1101 13 14=head1 SYNOPSIS 15 16 use Text::NeatTemplate; 17 18 my $tobj = Text::NeatTemplate->new(); 19 20 $result = $tobj->fill_in(data_hash=>\%data, 21 show_names=>\%names, 22 template=>$text); 23 24=head1 DESCRIPTION 25 26This module provides a simple, middleweight but fast template engine, 27for when you need speed rather than complex features, yet need more features 28than simple variable substitution. 29 30=head2 Markup Format 31 32The markup format is as follows: 33 34=over 35 36=item {$varname} 37 38A variable; will display the value of the variable, or nothing if 39that value is empty. 40 41=item {$varname:format} 42 43A formatted variable; will apply the formatting directive(s) to 44the value before displaying it. 45 46=item {?varname stuff [$varname] more stuff} 47 48A conditional. If the value of 'varname' is not empty, this will 49display "stuff value-of-variable more stuff"; otherwise it displays 50nothing. 51 52 {?var1 stuff [$var1] thing [$var2]} 53 54This would use both the values of var1 and var2 if var1 is not 55empty. 56 57=item {?varname stuff [$varname] more stuff!!other stuff} 58 59A conditional with "else". If the value of 'varname' is not empty, this 60will display "stuff value-of-variable more stuff"; otherwise it displays 61"other stuff". 62 63This version can likewise use multiple variables in its display parts. 64 65 {?var1 stuff [$var1] thing [$var2]!![$var3]} 66 67=item {&funcname(arg1,...,argN)} 68 69Call a function with the given args; the return value of the 70function will be what is put in its place. 71 72 {&MyPackage::myfunc(stuff,[$var1])} 73 74This would call the function myfunc in the package MyPackage, with the 75arguments "stuff", and the value of var1. 76 77Note, of course, that if you have a more complicated function and 78are processing much data, this will slow things down. 79 80=back 81 82=head2 Limitations 83 84To make the parsing simpler (and therefore faster) there are certain 85restrictions in what this module can do: 86 87=over 88 89=item * 90 91One cannot escape '{' '}' '[' or ']' characters. However, the substitution 92is clever enough so that you may be able to use them inside conditional 93constructs, provided the use does not resemble a variable. 94 95For example, to get a value surrounded by {}, the following 96will not work: 97 98{{$Var1}} 99 100However, this will: 101 102{?Var1 {[$Var1]}} 103 104=item * 105 106One cannot have nested variables. 107 108=item * 109 110Conditionals are limited to testing whether or not the variable 111has a value. If you want more elaborate tests, or tests on more 112than one value, you'll have to write a function to do it, and 113use the {&function()} construct. 114 115=item * 116 117Function arguments (as given with the {&funcname(arg1,arg2...)} format) 118cannot have commas in them, since commas are used to separate the 119arguments. 120 121=back 122 123=head2 Justification For Existence 124 125When I was writing SQLite::Work, I originally tried using L<Text::Template> 126(my favourite template engine) and also tried L<Text::FillIn>. Both 127of them had some lovely, powerful features. Unfortunately, they were 128also relatively slow. In testing them with a 700-row table, using 129Text::Template took about 15 seconds to generate the report, and using 130Text::FillIn took 45 seconds! Rolling my own very simple template 131engine cut the time down to about 7 seconds. 132 133The reasons for this aren't that surprising. Because Text::Template 134is basically an embedded Perl engine, it has to run the interpreter 135on each substitution. And Text::FillIn has a lot to do, what with being 136very generic and very recursive. 137 138The trade-off for the speed-gain of Text::NeatTemplate is that 139it is quite simple. There is no nesting or recursion, there are 140no loops. But I do think I've managed to grab some of the nicer features 141of other template engines, such as limited conditionals, and formatting, 142and, the most powerful of all, calling external functions. 143 144This is a middleweight engine rather than a lightweight one, because 145I needed more than just simple variable substitution, such as one 146has with L<Template::Trivial>. I consider the trade-off worth it, 147and others might also, so I made this a separate module. 148 149=head1 FORMATTING 150 151As well as simple substitution, this module can apply formatting 152to values before they are displayed. 153 154For example: 155 156{$Money:dollars} 157 158will give the value of the I<Money> variable formatted as a dollar value. 159 160Formatting directives are: 161 162=over 163 164=item alpha 165 166Convert to a string containing only alphanumeric characters 167(useful for anchors or filenames) 168 169=item alphadash 170 171Convert to a string containing alphanumeric characters, dashes 172and underscores; spaces are converted to underscores. 173(useful for anchors or filenames) 174 175=item comma_front 176 177Put anything after the last comma at the front (as with an author name) 178For example, "Smith,Sarah Jane" becomes "Sarah Jane Smith". 179 180=item dollars 181 182Return as a dollar value (float of precision 2) 183 184=item email 185 186Convert to a HTML mailto link. 187 188=item float 189 190Convert to float. 191 192=item hmail 193 194Convert to a "humanized" version of the email, with the @ and '.' 195replaced with "at" and "dot". This is useful to prevent spambots 196harvesting email addresses. 197 198=item html 199 200Convert to simple HTML (simple formatting) 201 202=item int 203 204Convert to integer 205 206=item itemI<num> 207 208Assume that the value is multiple values separated by the "pipe" symbol (|) and 209select the item with an index of I<num> (starting at zero) 210 211=item items_I<directive> 212 213Assume that the value is multiple values separated by the "pipe" symbol (|) and 214split the values into an array, apply the I<directive> directive to them, and 215join them together with a space. 216 217=item itemsjslash_I<directive> 218 219Like items_I<directive>, but the results are joined together with a slash between them. 220 221=item itemslashI<num> 222 223Assume that the value is multiple values separated by the "slash" symbol (/) and 224select the item with an index of I<num> (starting at zero) 225Good for selecting out components of pathnames. 226 227=item lower 228 229Convert to lower case. 230 231=item month 232 233Convert the number value to an English month name. 234 235=item namedalpha 236 237Similar to 'alpha', but prepends the 'name' of the value. 238Assumes that the name is only alphanumeric. 239 240=item nth 241 242Convert the number value to a N-th value. Numbers ending with 1 have 'st' 243appended, 2 have 'nd' appended, 3 have 'rd' appended, and everything 244else has 'th' appended. 245 246=item percent 247 248Show as if the value is a percentage. 249 250=item pipetocomma 251 252Assume that the value is multiple values separated by the "pipe" symbol (|) and replace 253those with a comma and space. 254 255=item pipetoslash 256 257Assume that the value is multiple values separated by the "pipe" symbol (|) and replace 258those with a forward slash (/). 259 260=item proper 261 262Convert to a Proper Noun. 263 264=item string 265 266Return the value with no change. 267 268=item title 269 270Put any trailing ",The" ",A" or ",An" at the front (as this is a title) 271 272=item truncateI<num> 273 274Truncate to I<num> length. 275 276=item upper 277 278Convert to upper case. 279 280=item url 281 282Convert to a HTML href link. 283 284=item wikilink 285 286Format the value as the most common kind of wikilink, that is [[I<value>]] 287 288=item wordsI<num> 289 290Give the first I<num> words of the value. 291 292=back 293 294=cut 295 296 297=head1 CLASS METHODS 298 299=head2 new 300 301my $tobj = Text::NeatTemplate->new(); 302 303Make a new template object. 304 305=cut 306 307sub new { 308 my $class = shift; 309 my %parameters = @_; 310 my $self = bless ({%parameters}, ref ($class) || $class); 311 312 return ($self); 313} # new 314 315 316=head1 METHODS 317 318=head2 fill_in 319 320Fill in the given values. 321 322 $result = $tobj->fill_in(data_hash=>\%data, 323 show_names=>\%names, 324 template=>$text); 325 326The 'data_hash' is a hash containing names and values. 327 328The 'show_names' is a hash saying which of these "variable names" 329ought to be displayed, and which suppressed. This can be useful 330if you want to use a more generic template, and then dynamically 331suppress certain values at runtime. 332 333The 'template' is the text of the template. 334 335=cut 336sub fill_in { 337 my $self = shift; 338 my %args = ( 339 data_hash=>undef, 340 show_names=>undef, 341 template=>undef, 342 @_ 343 ); 344 345 my $out = $args{template}; 346 $out =~ s/{([^}]+)}/$self->do_replace(data_hash=>$args{data_hash},show_names=>$args{show_names},targ=>$1)/eg; 347 348 return $out; 349} # fill_in 350 351=head2 get_varnames 352 353Find variable names inside the given template. 354 355 @varnames = $tobj->get_varnames(template=>$text); 356 357=cut 358sub get_varnames { 359 my $self = shift; 360 my %args = ( 361 template=>undef, 362 @_ 363 ); 364 my $template = $args{template}; 365 366 return '' if (!$template); 367 368 my %varnames = (); 369 # { (the regex below needs matching) 370 while ($template =~ m/{([^}]+)}/g) 371 { 372 my $targ = $1; 373 374 if ($targ =~ /^\$(\w+[-:\w]*)$/) 375 { 376 my $val_id = $1; 377 $varnames{$val_id} = 1; 378 } 379 elsif ($targ =~ /^\?([-\w]+)\s(.*)!!(.*)$/) 380 { 381 my $val_id = $1; 382 my $yes_t = $2; 383 my $no_t = $3; 384 385 $varnames{$val_id} = 1; 386 387 foreach my $substr ($yes_t, $no_t) 388 { 389 while ($substr =~ /\[(\$[^\]]+)\]/) 390 { 391 $varnames{$1} = 1; 392 } 393 } 394 } 395 elsif ($targ =~ /^\?([-\w]+)\s(.*)$/) 396 { 397 my $val_id = $1; 398 my $yes_t = $2; 399 400 $varnames{$val_id} = 1; 401 while ($yes_t =~ /\[(\$[^\]]+)\]/) 402 { 403 $varnames{$1} = 1; 404 } 405 } 406 elsif ($targ =~ /^\&([-\w:]+)\((.*)\)$/) 407 { 408 # function 409 my $func_name = $1; 410 my $fargs = $2; 411 while ($fargs =~ /\[(\$[^\]]+)\]/) 412 { 413 $varnames{$1} = 1; 414 } 415 } 416 } 417 return sort keys %varnames; 418} # get_varnames 419 420=head2 do_replace 421 422Replace the given value. 423 424 $val = $tobj->do_replace(targ=>$targ, 425 data_hash=>$data_hashref, 426 show_names=>\%show_names); 427 428Where 'targ' is the target value, which is either a variable target, 429or a conditional target. 430 431The 'data_hash' is a hash containing names and values. 432 433The 'show_names' is a hash saying which of these "variable names" 434ought to be displayed, and which suppressed. 435 436This can do templating by using the exec ability of substitution, for 437example: 438 439 $out =~ s/{([^}]+)}/$tobj->do_replace(data_hash=>$data_hash,targ=>$1)/eg; 440 441=cut 442sub do_replace { 443 my $self = shift; 444 my %args = ( 445 targ=>'', 446 data_hash=>undef, 447 show_names=>undef, 448 @_ 449 ); 450 my $targ = $args{targ}; 451 452 return '' if (!$targ); 453 if ($targ =~ /^\$(\w+[-:\w]*)$/) 454 { 455 my $val = $self->get_value(val_id=>$1, 456 data_hash=>$args{data_hash}, 457 show_names=>$args{show_names}); 458 if (defined $val) 459 { 460 return $val; 461 } 462 else # not a variable -- return nothing 463 { 464 return ''; 465 } 466 } 467 elsif ($targ =~ /^\?([-\w]+)\s(.*)!!(.*)$/) 468 { 469 my $val_id = $1; 470 my $yes_t = $2; 471 my $no_t = $3; 472 my $val = $self->get_value(val_id=>$val_id, 473 data_hash=>$args{data_hash}, 474 show_names=>$args{show_names}); 475 if ($val) 476 { 477 $yes_t =~ s/\[(\$[^\]]+)\]/$self->do_replace(data_hash=>$args{data_hash},show_names=>$args{show_names},targ=>$1)/eg; 478 return $yes_t; 479 } 480 else # no value, return alternative 481 { 482 $no_t =~ s/\[(\$[^\]]+)\]/$self->do_replace(data_hash=>$args{data_hash},show_names=>$args{show_names},targ=>$1)/eg; 483 return $no_t; 484 } 485 } 486 elsif ($targ =~ /^\?([-\w]+)\s(.*)$/) 487 { 488 my $val_id = $1; 489 my $yes_t = $2; 490 my $val = $self->get_value(val_id=>$val_id, 491 data_hash=>$args{data_hash}, 492 show_names=>$args{show_names}); 493 if ($val) 494 { 495 $yes_t =~ s/\[(\$[^\]]+)\]/$self->do_replace(data_hash=>$args{data_hash},show_names=>$args{show_names},targ=>$1)/eg; 496 return $yes_t; 497 } 498 else # no value, return nothing 499 { 500 return ''; 501 } 502 } 503 elsif ($targ =~ /^\&([-\w:]+)\((.*)\)$/) 504 { 505 # function 506 my $func_name = $1; 507 my $fargs = $2; 508 # split the args first, and replace each one separately 509 # just in case the data values have commas 510 my @fargs = split(/,/,$fargs); 511 my @processed = (); 512 foreach my $fa (@fargs) 513 { 514 $fa =~ s/\[(\$[^\]]+)\]/$self->do_replace(data_hash=>$args{data_hash},show_names=>$args{show_names},targ=>$1)/eg; 515 push @processed, $fa; 516 } 517 { 518 no strict('refs'); 519 return &{$func_name}(@processed); 520 } 521 } 522 else 523 { 524 print STDERR "UNKNOWN ==$targ==\n"; 525 } 526 return ''; 527} # do_replace 528 529=head2 get_value 530 531$val = $tobj->get_value(val_id=>$val_id, 532 data_hash=>$data_hashref, 533 show_names=>\%show_names); 534 535Get and format the given value. 536 537=cut 538sub get_value { 539 my $self = shift; 540 my %args = ( 541 val_id=>'', 542 data_hash=>undef, 543 show_names=>undef, 544 @_ 545 ); 546 my ($varname, @formats) = split(':', $args{val_id}); 547 548 my $value; 549 if (exists $args{data_hash}->{$varname}) 550 { 551 if (!$args{show_names} 552 or $args{show_names}->{$varname}) 553 { 554 $value = $args{data_hash}->{$varname}; 555 } 556 else 557 { 558 return ''; 559 } 560 } 561 else 562 { 563 return undef; 564 } 565 566 # we have a value to format 567 foreach my $format (@formats) { 568 $value = $self->convert_value(value=>$value, 569 format=>$format, 570 name=>$varname); 571 } 572 if ($value and $self->{escape_html}) 573 { 574 # filter out some HTML stuff 575 $value =~ s/ & / & /g; 576 } 577 return $value; 578} # get_value 579 580=head2 convert_value 581 582 my $val = $tobj->convert_value(value=>$val, 583 format=>$format, 584 name=>$name); 585 586Convert a value according to the given formatting directive. 587 588See L</FORMATTING> for details of all the formatting directives. 589 590 591=cut 592sub convert_value { 593 my $self = shift; 594 my %args = @_; 595 my $value = $args{value}; 596 my $style = $args{format}; 597 my $name = $args{name}; 598 599 $value ||= ''; 600 ($_=$style) || ($_ = 'string'); 601 SWITCH: { 602 /^upper/i && (return uc($value)); 603 /^lower/i && (return lc($value)); 604 /^int/i && (return (defined $value ? int($value) : 0)); 605 /^float/i && (return (defined $value && sprintf('%f',($value || 0))) || ''); 606 /^string/i && (return $value); 607 /^trunc(?:ate)?(\d+)/ && (return substr(($value||''), 0, $1)); 608 /^dollars/i && 609 (return (defined $value && length($value) 610 && sprintf('%.2f',($value || 0)) || '')); 611 /^percent/i && 612 (return (($value<0.2) && 613 sprintf('%.1f%%',($value*100)) 614 || sprintf('%d%%',int($value*100)))); 615 /^url/i && (return "<a href='$value'>$value</a>"); 616 /^wikilink/i && (return "[[$value]]"); 617 /^email/i && (return "<a mailto='$value'>$value</a>"); 618 /^hmail/i && do { 619 $value =~ s/@/ at /; 620 $value =~ s/\./ dot /g; 621 return $value; 622 }; 623 /^html/i && (return $self->simple_html($value)); 624 /^title/i && do { 625 $value =~ s/(.*)[,;]\s*(A|An|The)$/$2 $1/; 626 return $value; 627 }; 628 /^comma_front/i && do { 629 $value =~ s/(.*)[,]([^,]+)$/$2 $1/; 630 return $value; 631 }; 632 /^proper/i && do { 633 $value =~ s/(^w|\b\w)/uc($1)/eg; 634 return $value; 635 }; 636 /^month/i && do { 637 return $value if !$value; 638 return ($value == 1 639 ? 'January' 640 : ($value == 2 641 ? 'February' 642 : ($value == 3 643 ? 'March' 644 : ($value == 4 645 ? 'April' 646 : ($value == 5 647 ? 'May' 648 : ($value == 6 649 ? 'June' 650 : ($value == 7 651 ? 'July' 652 : ($value == 8 653 ? 'August' 654 : ($value == 9 655 ? 'September' 656 : ($value == 10 657 ? 'October' 658 : ($value == 11 659 ? 'November' 660 : ($value == 12 661 ? 'December' 662 : $value 663 ) 664 ) 665 ) 666 ) 667 ) 668 ) 669 ) 670 ) 671 ) 672 ) 673 ) 674 ); 675 }; 676 /^nth/i && do { 677 return $value if !$value; 678 return ($value =~ /1[123]$/ 679 ? "${value}th" 680 : ($value =~ /1$/ 681 ? "${value}st" 682 : ($value =~ /2$/ 683 ? "${value}nd" 684 : ($value =~ /3$/ 685 ? "${value}rd" 686 : "${value}th" 687 ) 688 ) 689 ) 690 ); 691 }; 692 /^facettag/i && do { 693 $value =~ s!/! !g; 694 $value =~ s/^\s+//; 695 $value =~ s/\s+$//; 696 $value =~ s/[^\w\s:_-]//g; 697 $value =~ s/\s\s+/ /g; 698 $value =~ s/ /_/g; 699 $value = join(':', $name, $value); 700 return $value; 701 }; 702 /^namedalpha/i && do { 703 $value =~ s/[^a-zA-Z0-9]//g; 704 $value = join('_', $name, $value); 705 return $value; 706 }; 707 /^alphadash/i && do { 708 $value =~ s!/! !g; 709 $value =~ s/[^a-zA-Z0-9_\s-]//g; 710 $value =~ s/^\s+//; 711 $value =~ s/\s+$//; 712 $value =~ s/\s\s+/ /g; 713 $value =~ s/ /_/g; 714 return $value; 715 }; 716 /^alpha/i && do { 717 $value =~ s/[^a-zA-Z0-9]//g; 718 return $value; 719 }; 720 /^pipetocomma/i && do { 721 $value =~ s/\|/, /g; 722 return $value; 723 }; 724 /^pipetoslash/i && do { 725 $value =~ s/\|/\//g; 726 return $value; 727 }; 728 /^words(\d+)/ && do { 729 my $ct = $1; 730 ($ct>0) || return ''; 731 my @sentence = split(/\s+/, $value); 732 my (@words) = splice(@sentence,0,$ct); 733 return join(' ', @words); 734 }; 735 /^wlink_(\w+)/ && do { 736 my $prefix = $1; 737 return "[[$prefix/$value]]"; 738 }; 739 /^tagify/i && do { 740 $value =~ s/\|/,/g; 741 $value =~ s!/! !g; 742 $value =~ s/!/ /g; 743 $value =~ s/^\s+//; 744 $value =~ s/\s+$//; 745 $value =~ s/[^\w,\s_-]//g; 746 $value =~ s/\s\s+/ /g; 747 $value =~ s/ /_/g; 748 return $value; 749 }; 750 /^item(\d+)/ && do { 751 my $ct = $1; 752 ($ct>=0) || return ''; 753 my @items = split(/\|/, $value); 754 return $items[$ct]; 755 }; 756 /^itemslash(\d+)/ && do { 757 my $ct = $1; 758 ($ct>=0) || return ''; 759 my @items = split(/\//, $value); 760 return $items[$ct]; 761 }; 762 /^items_(\w+)/ && do { 763 my $next = $1; 764 my @items = split(/[\|,]\s*/, $value); 765 my @next_items = (); 766 foreach my $item (@items) 767 { 768 push @next_items, $self->convert_value(%args, value=>$item, format=>$next); 769 } 770 return join(' ', @next_items); 771 }; 772 /^itemsjslash_(\w+)/ && do { 773 my $next = $1; 774 my @items = split(/[\|,]\s*/, $value); 775 my @next_items = (); 776 foreach my $item (@items) 777 { 778 push @next_items, $self->convert_value(%args, value=>$item, format=>$next); 779 } 780 return join(' / ', @next_items); 781 }; 782 /^itemsjcomma_(\w+)/ && do { 783 my $next = $1; 784 my @items = split(/[\|,]\s*/, $value); 785 my @next_items = (); 786 foreach my $item (@items) 787 { 788 push @next_items, $self->convert_value(%args, value=>$item, format=>$next); 789 } 790 return join(',', @next_items); 791 }; 792 793 # otherwise, give up 794 return " {{{ style $style not supported }}} "; 795 } 796} # convert_value 797 798=head2 simple_html 799 800$val = $tobj->simple_html($val); 801 802Do a simple HTML conversion of the value. 803bold, italic, <br> 804 805=cut 806sub simple_html { 807 my $self = shift; 808 my $value = shift; 809 810 $value =~ s#\n[\s][\s][\s]+#<br/>\n #sg; 811 $value =~ s#\s*\n\s*\n#<br/><br/>\n#sg; 812 $value =~ s#\*([^*]+)\*#<i>$1</i>#sg; 813 $value =~ s/\^([^^]+)\^/<b>$1<\/b>/sg; 814 $value =~ s/\#([^#<>]+)\#/<b>$1<\/b>/sg; 815 $value =~ s/\s&\s/ & /sg; 816 return $value; 817} # simple_html 818 819=head1 Callable Functions 820 821=head2 safe_backtick 822 823{&safe_backtick(myprog,arg1,arg2...argN)} 824 825Return the results of a program, without risking evil shell calls. 826This requires that the program and the arguments to that program 827be given separately. 828 829=cut 830sub safe_backtick { 831 my @prog_and_args = @_; 832 my $progname = $prog_and_args[0]; 833 834 # if they didn't give us anything, return 835 if (!$progname) 836 { 837 return ''; 838 } 839 # call the program 840 # do a fork and exec with an open; 841 # this should preserve the environment and also be safe 842 my $result = ''; 843 my $fh; 844 my $pid = open($fh, "-|"); 845 if ($pid) # parent 846 { 847 { 848 # slurp up the result all at once 849 local $/ = undef; 850 $result = <$fh>; 851 } 852 close($fh) || warn "$progname program script exited $?"; 853 } 854 else # child 855 { 856 # call the program 857 # force exec to use an indirect object, 858 # so that evil shell stuff will die, even 859 # for a program with no arguments 860 exec { $progname } @prog_and_args or die "$progname failed: $!\n"; 861 # NOTREACHED 862 } 863 return $result; 864} # safe_backtick 865 866=head2 format_items 867 868{&format_items(fieldname,value,delim,outdelim,format,prefix,suffix)} 869 870Format a field made of multiple items. 871 872=cut 873sub format_items { 874 my $fieldname = shift; 875 my $value = shift; 876 my @args = @_; 877 878 # if they didn't give us anything, return 879 if (!$fieldname) 880 { 881 return ''; 882 } 883 if (!$value) 884 { 885 return ''; 886 } 887 888 my $delim = $args[0] || '|'; 889 my $outdelim = $args[1] || ' '; 890 my $format = $args[2] || 'raw'; 891 my $prefix = $args[3] || ''; 892 my $suffix = $args[4] || ''; 893 $delim =~ s/comma/,/g; 894 $delim =~ s/pipe/|/g; 895 $delim =~ s!slash!/!g; 896 $outdelim =~ s/comma/,/g; 897 $outdelim =~ s/pipe/|/g; 898 $outdelim =~ s!slash!/!g; 899 my @items = split(/\Q$delim\E\s*/, $value); 900 my @next_items = (); 901 foreach my $item (@items) 902 { 903 push @next_items, 904 Text::NeatTemplate->convert_value(name=>$fieldname, 905 value=>$item, 906 format=>$format); 907 } 908 return $prefix . join($outdelim, @next_items) . $suffix; 909} # format_items 910 911 912=head1 REQUIRES 913 914 Test::More 915 916=head1 INSTALLATION 917 918To install this module, run the following commands: 919 920 perl Build.PL 921 ./Build 922 ./Build test 923 ./Build install 924 925Or, if you're on a platform (like DOS or Windows) that doesn't like the 926"./" notation, you can do this: 927 928 perl Build.PL 929 perl Build 930 perl Build test 931 perl Build install 932 933In order to install somewhere other than the default, such as 934in a directory under your home directory, like "/home/fred/perl" 935go 936 937 perl Build.PL --install_base /home/fred/perl 938 939as the first step instead. 940 941This will install the files underneath /home/fred/perl. 942 943You will then need to make sure that you alter the PERL5LIB variable to 944find the module. 945 946Therefore you will need to change the PERL5LIB variable to add 947/home/fred/perl/lib 948 949 PERL5LIB=/home/fred/perl/lib:${PERL5LIB} 950 951=head1 SEE ALSO 952 953L<Text::Template> 954L<Text::FillIn> 955L<Text::QuickTemplate> 956L<Template::Trivial> 957L<Template::Toolkit> 958L<HTML::Template> 959 960=head1 BUGS 961 962Please report any bugs or feature requests to the author. 963 964=head1 AUTHOR 965 966 Kathryn Andersen (RUBYKAT) 967 perlkat AT katspace dot com 968 http://www.katspace.org/tools 969 970=head1 COPYRIGHT AND LICENCE 971 972Copyright (c) 2006 by Kathryn Andersen 973 974This program is free software; you can redistribute it and/or modify it 975under the same terms as Perl itself. 976 977=cut 978 9791; # End of Text::NeatTemplate 980__END__ 981