1use 5.006; 2use warnings; 3use strict; 4#use Smart::Comments; 5#use Smart::Comments '####'; 6 7package Template::Declare::Tags; 8 9our $VERSION = '0.43'; 10 11use Template::Declare; 12use base 'Exporter'; 13use Carp qw(carp croak); 14use Symbol 'qualify_to_ref'; 15 16our $self; 17 18our @EXPORT = qw( 19 template private current_template current_base_path 20 show show_page 21 attr with get_current_attr 22 outs outs_raw 23 xml_decl 24 under setting 25 smart_tag_wrapper create_wrapper 26 $self 27); 28 29our @TAG_SUB_LIST; 30our @TagSubs; 31*TagSubs = \@TAG_SUB_LIST; # For backward compatibility only 32 33our %ATTRIBUTES = (); 34our %ELEMENT_ID_CACHE = (); 35our $TAG_NEST_DEPTH = 0; 36our $TAG_INDENTATION = 1; 37our $EOL = "\n"; 38our @TEMPLATE_STACK = (); 39 40our $SKIP_XML_ESCAPING = 0; 41 42sub import { 43 my $self = shift; 44 my @set_modules; 45 if (!@_) { 46 push @_, 'HTML'; 47 } 48 ### @_ 49 ### caller: caller() 50 51 # XXX We can't reset @TAG_SUB_LIST here since 52 # use statements always run at BEGIN time. 53 # A better approach may be install such lists 54 # directly into the caller's namespace... 55 #undef @TAG_SUB_LIST; 56 57 while (@_) { 58 my $lang = shift; 59 my $opts; 60 if (ref $_[0] and ref $_[0] eq 'HASH') { 61 $opts = shift; 62 $opts->{package} ||= $opts->{namespace}; 63 # XXX TODO: carp if the derived package already exists? 64 } 65 $opts->{package} ||= scalar(caller); 66 my $module = $opts->{from} || 67 "Template::Declare::TagSet::$lang"; 68 69 ### Loading tag set: $module 70 if (! $module->can('get_tag_list') ) { 71 eval "use $module"; 72 if ($@) { 73 warn $@; 74 croak "Failed to load tagset module $module"; 75 } 76 } 77 ### TagSet options: $opts 78 my $tagset = $module->new($opts); 79 my $tag_list = $tagset->get_tag_list; 80 Template::Declare::Tags::install_tag($_, $tagset) 81 for @$tag_list; 82 } 83 __PACKAGE__->export_to_level(1, $self); 84} 85 86sub _install { 87 my ($override, $package, $subname, $coderef) = @_; 88 89 my $name = $package . '::' . $subname; 90 my $slot = qualify_to_ref($name); 91 return if !$override and *$slot{CODE}; 92 93 no warnings 'redefine'; 94 *$slot = $coderef; 95} 96 97=head1 NAME 98 99Template::Declare::Tags - Build and install XML Tag subroutines for Template::Declare 100 101=head1 SYNOPSIS 102 103 package MyApp::Templates; 104 105 use base 'Template::Declare'; 106 use Template::Declare::Tags 'HTML'; 107 108 template main => sub { 109 link {} 110 table { 111 row { 112 cell { "Hello, world!" } 113 } 114 } 115 img { attr { src => 'cat.gif' } } 116 img { src is 'dog.gif' } 117 }; 118 119Produces: 120 121 <link /> 122 <table> 123 <tr> 124 <td>Hello, world!</td> 125 </tr> 126 </table> 127 <img src="cat.gif" /> 128 <img src="dog.gif" /> 129 130Using XUL templates with a namespace: 131 132 package MyApp::Templates; 133 134 use base 'Template::Declare'; 135 use Template::Declare::Tags 136 'XUL', HTML => { namespace => 'html' }; 137 138 template main => sub { 139 groupbox { 140 caption { attr { label => 'Colors' } } 141 html::div { html::p { 'howdy!' } } 142 html::br {} 143 } 144 }; 145 146Produces: 147 148 <groupbox> 149 <caption label="Colors" /> 150 <html:div> 151 <html:p>howdy!</html:p> 152 </html:div> 153 <html:br></html:br> 154 </groupbox> 155 156=head1 DESCRIPTION 157 158C<Template::Declare::Tags> is used to generate templates and install 159subroutines for tag sets into the calling namespace. 160 161You can specify the tag sets to install by providing a list of tag modules in 162the C<use> statement: 163 164 use Template::Declare::Tags qw/ HTML XUL /; 165 166By default, Template::Declare::Tags uses the tag set provided by 167L<Template::Declare::TagSet::HTML>. So 168 169 use Template::Declare::Tags; 170 171is equivalent to 172 173 use Template::Declare::Tags 'HTML'; 174 175Currently L<Template::Declare> bundles the following tag sets: 176L<Template::Declare::TagSet::HTML>, L<Template::Declare::TagSet::XUL>, 177L<Template::Declare::TagSet::RDF>, and L<Template::Declare::TagSet::RDF::EM>. 178 179You can specify your own tag set classes, as long as they subclass 180L<Template::Declare::TagSet> and implement the corresponding methods (e.g. 181C<get_tag_list>). 182 183If you implement a custom tag set module named 184C<Template::Declare::TagSet::Foo>, you can load it into a template module like 185so: 186 187 use Template::Declare::Tags 'Foo'; 188 189If your tag set module is not under the 190L<Template::Declare::TagSet|Template::Declare::TagSet> namespace, use the 191C<from> option to load it. Fore example, if you created a tag set named 192C<MyTag::Foo>, then you could load it like so: 193 194 use Template::Declare::Tags Foo => { from => 'MyTag::Foo' }; 195 196XML namespaces are emulated by Perl packages. For example, to embed HTML tags 197within XUL using the C<html> namespace: 198 199 package MyApp::Templates; 200 201 use base 'Template::Declare'; 202 use Template::Declare::Tags 'XUL', HTML => { namespace => 'html' }; 203 204 template main => sub { 205 groupbox { 206 caption { attr { label => 'Colors' } } 207 html::div { html::p { 'howdy!' } } 208 html::br {} 209 } 210 }; 211 212This will output: 213 214 <groupbox> 215 <caption label="Colors" /> 216 <html:div> 217 <html:p>howdy!</html:p> 218 </html:div> 219 <html:br></html:br> 220 </groupbox> 221 222Behind the scenes, C<Template::Declare::Tags> generates a Perl package named 223C<html> and installs the HTML tag subroutines into that package. On the other 224hand, XUL tag subroutines are installed into the current package, namely, 225C<MyApp::Templates> in the previous example. 226 227There may be cases when you want to specify a different Perl package for a 228particular XML namespace. For instance, if the C<html> Perl package has 229already been used for other purposes in your application and you don't want to 230install subs there and mess things up, use the C<package> option to install 231them elsewhere: 232 233 package MyApp::Templates; 234 use base 'Template::Declare'; 235 use Template::Declare::Tags 'XUL', HTML => { 236 namespace => 'htm', 237 package => 'MyHtml' 238 }; 239 240 template main => sub { 241 groupbox { 242 caption { attr { label => 'Colors' } } 243 MyHtml::div { MyHtml::p { 'howdy!' } } 244 MyHtml::br {} 245 } 246 }; 247 248This code will generate something like the following: 249 250 <groupbox> 251 <caption label="Colors" /> 252 <htm:div> 253 <htm:p>howdy!</htm:p> 254 </htm:div> 255 <htm:br></htm:br> 256 </groupbox> 257 258=head1 METHODS AND SUBROUTINES 259 260=head2 Declaring templates 261 262=head3 template TEMPLATENAME => sub { 'Implementation' }; 263 264 template select_list => sub { 265 my $self = shift; 266 select { 267 option { $_ } for @_; 268 } 269 }; 270 271Declares a template in the current package. The first argument to the template 272subroutine will always be a C<Template::Declare> object. Subsequent arguments 273will be all those passed to C<show()>. For example, to use the above example 274to output a select list of colors, you'd call it like so: 275 276 Template::Declare->show('select_list', qw(red yellow green purple)); 277 278You can use any URL-legal characters in the template name; 279C<Template::Declare> will encode the template as a Perl subroutine and stash 280it where C<show()> can find it. 281 282(Did you know that you can have characters like ":" and "/" in your Perl 283subroutine names? The easy way to get at them is with C<can>). 284 285=cut 286 287sub template ($$) { 288 my $template_name = shift; 289 my $coderef = shift; 290 my $template_class = ( caller(0) )[0]; 291 292 no warnings qw( uninitialized redefine ); 293 294 # template "foo" ==> CallerPkg::_jifty_template_foo; 295 # template "foo/bar" ==> CallerPkg::_jifty_template_foo/bar; 296 my $codesub = sub { 297 local $self = shift || $self || $template_class; 298 unshift @_, $self, $coderef; 299 goto $self->can('_dispatch_template'); 300 }; 301 302 if (wantarray) { 303 # We're being called by something like private that doesn't want us to register ourselves 304 return ( $template_class, $template_name, $codesub ); 305 } else { 306 # We've been called in a void context and should register this template 307 Template::Declare::register_template( 308 $template_class, 309 $template_name, 310 $codesub, 311 ); 312 } 313} 314 315=head3 private template TEMPLATENAME => sub { 'Implementation' }; 316 317 private template select_list => sub { 318 my $self = shift; 319 select { 320 option { $_ } for @_; 321 } 322 }; 323 324Declares that a template isn't available to be called directly from client 325code. The resulting template can instead only be called from the package in 326which it's created. 327 328=cut 329 330sub private (@) { 331 my $class = shift; 332 my $subname = shift; 333 my $code = shift; 334 Template::Declare::register_private_template( $class, $subname, $code ); 335} 336 337=head2 Showing templates 338 339=head3 show [$template_name or $template_coderef], args 340 341 show( main => { user => 'Bob' } ); 342 343Displays templates. The first argument is the name of the template to be 344displayed. Any additional arguments will be passed directly to the template. 345 346C<show> can either be called with a template name or a package/object and a 347template. (It's both functional and OO.) 348 349If called from within a Template::Declare subclass, then private templates are 350accessible and visible. If called from something that isn't a 351Template::Declare, only public templates will be visible. 352 353From the outside world, users can either call C<< Template::Declare->show() >>, 354C<< show() >> exported from Template::Declare::Tags or 355C<Template::Declare::Tags::show()> directly to render a publicly visible template. 356 357Private templates may only be called from within the C<Template::Declare> 358package. 359 360=cut 361 362sub show { 363 my $template = shift; 364 365 # if we're inside a template, we should show private templates 366 if ( caller->isa('Template::Declare') ) { 367 _show_template( $template, 1, \@_ ); 368 return Template::Declare->buffer->data; 369 } else { 370 show_page( $template, @_); 371 } 372 373} 374 375=head3 show_page 376 377 show_page( main => { user => 'Bob' } ); 378 379Like C<show()>, but does not dispatch to private templates. It's used 380internally by C<show()> when when that method is called from outside a 381template class. 382 383=cut 384 385sub show_page { 386 my $template = shift; 387 my $args = \@_; 388 389 Template::Declare->buffer->push( 390 private => defined wantarray, 391 from => "T::D path $template", 392 ); 393 _show_template( $template, 0, $args ); 394 %ELEMENT_ID_CACHE = (); 395 return Template::Declare->buffer->pop; 396} 397 398=head2 Attributes 399 400=head3 attr HASH 401 402 attr { src => 'logo.png' }; 403 404Specifies attributes for the element tag in which it appears. For example, to 405add a class and ID to an HTML paragraph: 406 407 p { 408 attr { 409 class => 'greeting text', 410 id => 'welcome', 411 }; 412 'This is a welcoming paragraph'; 413 } 414 415=cut 416 417sub attr (&;@) { 418 my $code = shift; 419 my @rv = $code->(); 420 while ( my ( $field, $val ) = splice( @rv, 0, 2 ) ) { 421 422 # only defined whle in a tag context 423 append_attr( $field, $val ); 424 } 425 return @_; 426} 427 428=head3 ATTR is VALUE 429 430Attributes can also be specified by using C<is>, as in 431 432 p { 433 class is 'greeting text'; 434 id is 'welcome'; 435 'This is a welcoming paragraph'; 436 } 437 438A few tricks work for 'is': 439 440 http_equiv is 'foo'; # => http-equiv="foo" 441 xml__lang is 'foo'; # => xml:lang="foo" 442 443So double underscore replaced with colon and single underscore with dash. 444 445=cut 446 447# 'is' is declared later, when needed, using 'local *is::AUTOLOAD = sub {};' 448 449=head3 with 450 451 with ( id => 'greeting', class => 'foo' ), 452 p { 'Hello, World wide web' }; 453 454An alternative way to specify attributes for a tag, just for variation. The 455standard way to do the same as this example using C<attr> is: 456 457 p { attr { id => 'greeting', class => 'foo' } 458 'Hello, World wide web' }; 459 460=cut 461 462sub with (@) { 463 %ATTRIBUTES = (); 464 while ( my ( $key, $val ) = splice( @_, 0, 2 ) ) { 465 no warnings 'uninitialized'; 466 $ATTRIBUTES{$key} = $val; 467 468 if ( lc($key) eq 'id' ) { 469 if ( $ELEMENT_ID_CACHE{$val}++ ) { 470 my $msg = "HTML appears to contain illegal duplicate element id: $val"; 471 die $msg if Template::Declare->strict; 472 warn $msg; 473 } 474 } 475 476 } 477 wantarray ? () : ''; 478} 479 480=head2 Displaying text and raw data 481 482=head3 outs STUFF 483 484 p { outs 'Grettings & welcome pyoonie hyoomon.' } 485 486HTML-encodes its arguments and appends them to C<Template::Declare>'s output 487buffer. This is similar to simply returning a string from a tag function call, 488but is occasionally useful when you need to output a mix of things, as in: 489 490 p { outs 'hello'; em { 'world' } } 491 492=head3 outs_raw STUFF 493 494 p { outs_raw "That's what <em>I'm</em> talking about!' } 495 496Appends its arguments to C<Template::Declare>'s output buffer without HTML 497escaping. 498 499=cut 500 501sub outs { _outs( 0, @_ ); } 502sub outs_raw { _outs( 1, @_ ); } 503 504=head2 Installing tags and wrapping stuff 505 506=head3 install_tag TAGNAME, TAGSET 507 508 install_tag video => 'Template::Declare::TagSet::HTML'; 509 510Sets up TAGNAME as a tag that can be used in user templates. TAGSET is an 511instance of a subclass for L<Template::Declare::TagSet>. 512 513=cut 514 515sub install_tag { 516 my $tag = $_[0]; # we should not do lc($tag) here :) 517 my $name = $tag; 518 my $tagset = $_[1]; 519 520 my $alternative = $tagset->get_alternate_spelling($tag); 521 if ( defined $alternative ) { 522 _install( 523 0, # do not override 524 scalar(caller), $tag, 525 sub (&) { 526 die "$tag {...} is invalid; use $alternative {...} instead.\n"; 527 } 528 ); 529 ### Exporting place-holder sub: $name 530 # XXX TODO: more checking here 531 if ($name !~ /^(?:base|tr|time)$/) { 532 push @EXPORT, $name; 533 push @TAG_SUB_LIST, $name; 534 } 535 $name = $alternative or return; 536 } 537 538 # We don't need this since we directly install 539 # subs into the target package. 540 #push @EXPORT, $name; 541 push @TAG_SUB_LIST, $name; 542 543 no strict 'refs'; 544 no warnings 'redefine'; 545 #### Installing tag: $name 546 # XXX TODO: use sub _install to insert subs into the caller's package so as to support XML packages 547 my $code = sub (&;$) { 548 local *__ANON__ = $tag; 549 if ( defined wantarray and not wantarray ) { 550 551 # Scalar context - return a coderef that represents ourselves. 552 my @__ = @_; 553 my $_self = $self; 554 my $sub = sub { 555 local $self = $_self; 556 local *__ANON__ = $tag; 557 _tag($tagset, $tag, @__); 558 }; 559 bless $sub, 'Template::Declare::Tag'; 560 return $sub; 561 } else { 562 _tag($tagset, $tag, @_); 563 } 564 }; 565 _install( 566 1, # do override the existing sub with the same name 567 $tagset->package => $name => $code 568 ); 569} 570 571=head3 smart_tag_wrapper 572 573 # create a tag that has access to the arguments set with L</with>. 574 sub sample_smart_tag (&) { 575 my $code = shift; 576 577 smart_tag_wrapper { 578 my %args = @_; # set using 'with' 579 outs( 'keys: ' . join( ', ', sort keys %args) . "\n" ); 580 $code->(); 581 }; 582 } 583 584 # use it 585 with ( foo => 'bar', baz => 'bundy' ), sample_smart_tag { 586 outs( "Hello, World!\n" ); 587 }; 588 589The output would be 590 591 keys: baz, foo 592 Hello, World! 593 594The smart tag wrapper allows you to create code that has access to the 595attribute arguments specified via C<with>. It passes those arguments in to the 596wrapped code in C<@_>. It also takes care of putting the output in the right 597place and tidying up after itself. This might be useful to change the behavior 598of a template based on attributes passed to C<with>. 599 600=cut 601 602sub smart_tag_wrapper (&) { 603 my $coderef = shift; 604 605 Template::Declare->buffer->append($EOL); 606 Template::Declare->buffer->push( from => "T::D tag wrapper", private => 1 ); 607 608 my %attr = %ATTRIBUTES; 609 %ATTRIBUTES = (); # prevent leakage 610 611 my $last = join '', 612 map { ref($_) ? $_ : _postprocess($_) } 613 $coderef->(%attr); 614 615 my $content = Template::Declare->buffer->pop; 616 $content .= "$last" if not length $content and length $last; 617 Template::Declare->buffer->append( $content ); 618 619 return ''; 620} 621 622=head3 create_wrapper WRAPPERNAME => sub { 'Implementation' }; 623 624 create_wrapper basics => sub { 625 my $code = shift; 626 html { 627 head { title { 'Welcome' } }; 628 body { $code->() } 629 } 630 }; 631 632C<create_wrapper> declares a wrapper subroutine that can be called like a tag 633sub, but can optionally take arguments to be passed to the wrapper sub. For 634example, if you wanted to wrap all of the output of a template in the usual 635HTML headers and footers, you can do something like this: 636 637 package MyApp::Templates; 638 use Template::Declare::Tags; 639 use base 'Template::Declare'; 640 641 BEGIN { 642 create_wrapper wrap => sub { 643 my $code = shift; 644 my %params = @_; 645 html { 646 head { title { outs "Hello, $params{user}!"} }; 647 body { 648 $code->(); 649 div { outs 'This is the end, my friend' }; 650 }; 651 } 652 }; 653 } 654 655 template inner => sub { 656 wrap { 657 h1 { outs "Hello, Jesse, s'up?" }; 658 } user => 'Jesse'; 659 }; 660 661Note how the C<wrap> wrapper function is available for calling after it has 662been declared in a C<BEGIN> block. Also note how you can pass arguments to the 663function after the closing brace (you don't need a comma there!). 664 665The output from the "inner" template will look something like this: 666 667 <html> 668 <head> 669 <title>Hello, Jesse!</title> 670 </head> 671 <body> 672 <h1>Hello, Jesse, s'up?</h1> 673 <div>This is the end, my friend</div> 674 </body> 675 </html> 676 677=cut 678 679sub create_wrapper ($$) { 680 my $wrapper_name = shift; 681 my $coderef = shift; 682 my $template_class = caller; 683 684 # Shove the code ref into the calling class. 685 no strict 'refs'; 686 *{"$template_class\::$wrapper_name"} = sub (&;@) { goto $coderef }; 687} 688 689=head2 Helpers 690 691=head3 xml_decl HASH 692 693 xml_decl { 'xml', version => '1.0' }; 694 695Emits an XML declaration. For example: 696 697 xml_decl { 'xml', version => '1.0' }; 698 xml_decl { 'xml-stylesheet', href => "chrome://global/skin/", type => "text/css" }; 699 700Produces: 701 702 <?xml version="1.0"?> 703 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> 704 705=cut 706 707sub xml_decl (&;$) { 708 my $code = shift; 709 my @rv = $code->(); 710 my $name = shift @rv; 711 outs_raw("<?$name"); 712 while ( my ( $field, $val ) = splice( @rv, 0, 2 ) ) { 713 outs_raw(qq/ $field="$val"/); 714 } 715 outs_raw("?>$EOL"); 716 return @_; 717} 718 719=head3 current_template 720 721 my $path = current_template(); 722 723Returns the absolute path of the current template 724 725=cut 726 727sub current_template { 728 return $TEMPLATE_STACK[-1] || ''; 729} 730 731=head3 current_base_path 732 733 my $path = current_base_path(); 734 735Returns the absolute base path of the current template 736 737=cut 738 739sub current_base_path { 740 # Rip it apart 741 my @parts = split('/', current_template()); 742 743 # Remove the last element 744 pop @parts; 745 746 # Put it back together again 747 my $path = join('/', @parts); 748 749 # And serve 750 return $path; 751} 752 753=head3 under 754 755C<under> is a helper function providing semantic sugar for the C<mix> method 756of L<Template::Declare|Template::Declare/"mix">. 757 758=cut 759 760sub under ($) { return shift } 761 762=head3 setting 763 764C<setting> is a helper function providing semantic sugar for the C<mix> method 765of L<Template::Declare|Template::Declare/"mix">. 766 767=cut 768 769sub setting ($) { return shift } 770 771=begin comment 772 773=head2 get_current_attr 774 775Deprecated. 776 777=end comment 778 779=cut 780 781sub get_current_attr ($) { 782 $ATTRIBUTES{ $_[0] }; 783} 784 785sub _tag { 786 my $tagset = shift; 787 my $tag = shift; 788 my $code = shift; 789 my $more_code = shift; 790 $tag = $tagset->namespace . ":$tag" if defined $tagset->namespace; 791 792 Template::Declare->buffer->append( 793 $EOL 794 . ( " " x $TAG_NEST_DEPTH ) 795 . "<$tag" 796 . join( '', 797 map { qq{ $_="} . ( $ATTRIBUTES{$_} || '' ) . qq{"} } 798 sort keys %ATTRIBUTES ) 799 ); 800 801 my $attrs = ""; 802 my $last; 803 { 804 no warnings qw( uninitialized redefine once ); 805 806 local *is::AUTOLOAD = sub { 807 shift; 808 809 my $field = our $AUTOLOAD; 810 $field =~ s/.*:://; 811 812 $field =~ s/__/:/g; # xml__lang is 'foo' ====> xml:lang="foo" 813 $field =~ s/_/-/g; # http_equiv is 'bar' ====> http-equiv="bar" 814 815 # Squash empty values, but not '0' values 816 my $val = join ' ', grep { defined $_ && $_ ne '' } @_; 817 818 append_attr( $field, $val ); 819 }; 820 821 local *append_attr = sub { 822 my $field = shift; 823 my $val = shift; 824 825 $attrs .= ' ' . $field . q{="} . _postprocess($val, 1) . q{"}; 826 wantarray ? () : ''; 827 }; 828 829 local $TAG_NEST_DEPTH = $TAG_NEST_DEPTH + $TAG_INDENTATION; 830 %ATTRIBUTES = (); 831 Template::Declare->buffer->push( private => 1, from => "T::D tag $tag" ); 832 $last = join '', map { ref($_) && $_->isa('Template::Declare::Tag') ? $_ : _postprocess($_) } $code->(); 833 } 834 my $content = Template::Declare->buffer->pop; 835 $content .= "$last" if not length $content and length $last; 836 Template::Declare->buffer->append($attrs) if length $attrs; 837 838 if (length $content) { 839 Template::Declare->buffer->append(">$content"); 840 Template::Declare->buffer->append( $EOL . ( " " x $TAG_NEST_DEPTH )) if $content =~ /\</; 841 Template::Declare->buffer->append("</$tag>"); 842 } elsif ( $tagset->can_combine_empty_tags($tag) ) { 843 Template::Declare->buffer->append(" />"); 844 } else { 845 # Otherwise we supply a closing tag. 846 Template::Declare->buffer->append("></$tag>"); 847 } 848 849 return ( ref($more_code) && $more_code->isa('CODE') ) 850 ? $more_code->() 851 : ''; 852} 853 854sub _resolve_template_path { 855 my $template = shift; 856 857 my @parts; 858 if ( substr($template, 0, 1) ne '/' ) { 859 # relative 860 @parts = split '/', current_template(); 861 # Get rid of the parent's template name 862 pop @parts; 863 } 864 865 foreach ( split '/', $template ) { 866 if ( $_ eq '..' ) { 867 pop @parts; 868 } 869 # Get rid of "." and empty entries by the way 870 elsif ( $_ ne '.' && $_ ne '' ) { 871 push @parts, $_; 872 } 873 } 874 875 return join '/', @parts; 876} 877 878sub _show_template { 879 my $template = shift; 880 my $inside_template = shift; 881 my $args = shift; 882 $template = _resolve_template_path($template); 883 local @TEMPLATE_STACK = (@TEMPLATE_STACK, $template); 884 885 my $callable = 886 ( ref($template) && $template->isa('Template::Declare::Tag') ) 887 ? $template 888 : Template::Declare->resolve_template( $template, $inside_template ); 889 890 # If the template was not found let the user know. 891 unless ($callable) { 892 my $msg = "The template '$template' could not be found"; 893 $msg .= " (it might be private)" if !$inside_template; 894 croak $msg if Template::Declare->strict; 895 carp $msg; 896 return ''; 897 } 898 899 if (my $instrumentation = Template::Declare->around_template) { 900 $instrumentation->( 901 sub { &$callable($self, @$args) }, 902 $template, 903 $args, 904 $callable, 905 ); 906 } 907 else { 908 &$callable($self, @$args); 909 } 910 911 return; 912} 913 914sub _outs { 915 my $raw = shift; 916 my @phrases = (@_); 917 918 Template::Declare->buffer->push( 919 private => (defined wantarray and not wantarray), from => "T::D outs" 920 ); 921 922 foreach my $item ( grep {defined} @phrases ) { 923 my $returned = ref($item) eq 'CODE' 924 ? $item->() 925 : $raw 926 ? $item 927 : _postprocess($item); 928 Template::Declare->buffer->append( $returned ); 929 } 930 return Template::Declare->buffer->pop; 931} 932 933sub _postprocess { 934 my $val = shift; 935 my $skip_postprocess = shift; 936 937 return $val unless defined $val; 938 939 # stringify in case $val is object with overloaded "" 940 $val = "$val"; 941 if ( ! $SKIP_XML_ESCAPING ) { 942 no warnings 'uninitialized'; 943 $val =~ s/&/&/g; 944 $val =~ s/</</g; 945 $val =~ s/>/>/g; 946 $val =~ s/\(/(/g; 947 $val =~ s/\)/)/g; 948 $val =~ s/"/"/g; 949 $val =~ s/'/'/g; 950 } 951 $val = Template::Declare->postprocessor->($val) 952 unless $skip_postprocess; 953 954 return $val; 955} 956 957=begin comment 958 959=head2 append_attr 960 961C<append_attr> is a helper function providing an interface for setting 962attributes from within tags. But it's better to use C<attr> or C<is> to set 963your attributes. Nohting to see here, really. Move along. 964 965=end comment 966 967=cut 968 969sub append_attr { 970 die "Subroutine attr failed: $_[0] => '$_[1]'\n\t". 971 "(Perhaps you're using an unknown tag in the outer container?)"; 972} 973 974=head1 VARIABLES 975 976=over 4 977 978=item C<@Template::Declare::Tags::EXPORT> 979 980Holds the names of the static subroutines exported by this class. Tag 981subroutines generated by tag sets, however, are not included here. 982 983=item C<@Template::Declare::Tags::TAG_SUB_LIST> 984 985Contains the names of the tag subroutines generated from a tag set. 986 987Note that this array won't get cleared automatically before another 988C<< use Template::Decalre::Tags >> statement. 989 990C<@Template::Declare::Tags::TagSubs> is aliased to this variable for 991backward-compatibility. 992 993=item C<$Template::Declare::Tags::TAG_NEST_DEPTH> 994 995Controls the indentation of the XML tags in the final outputs. For example, 996you can temporarily disable a tag's indentation by the following lines of 997code: 998 999 body { 1000 pre { 1001 local $Template::Declare::Tags::TAG_NEST_DEPTH = 0; 1002 script { attr { src => 'foo.js' } } 1003 } 1004 } 1005 1006It generates 1007 1008 <body> 1009 <pre> 1010 <script src="foo.js"></script> 1011 </pre> 1012 </body> 1013 1014Note that now the C<script> tag has I<no> indentation and we've got what we 1015want. ;) 1016 1017=item C<$Template::Declare::Tags::SKIP_XML_ESCAPING> 1018 1019Disables XML escape postprocessing entirely. Use at your own risk. 1020 1021=back 1022 1023=head1 SEE ALSO 1024 1025L<Template::Declare::TagSet::HTML>, 1026L<Template::Declare::TagSet::XUL>, L<Template::Declare>. 1027 1028=head1 AUTHORS 1029 1030Jesse Vincent <jesse@bestpractical.com> 1031 1032Agent Zhang <agentzh@yahoo.cn> 1033 1034=head1 COPYRIGHT 1035 1036Copyright 2006-2009 Best Practical Solutions, LLC. 1037 1038=cut 1039 1040package Template::Declare::Tag; 1041 1042use overload '""' => \&stringify; 1043 1044sub stringify { 1045 my $self = shift; 1046 1047 if ( defined wantarray ) { 1048 Template::Declare->buffer->push( private => 1, from => "T::D stringify" ); 1049 my $returned = $self->(); 1050 return Template::Declare->buffer->pop . $returned; 1051 } else { 1052 return $self->(); 1053 } 1054} 1055 10561; 1057