Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / i486-linux-gnu-thread-multi / Template / View.pm
1 #============================================================= -*-Perl-*-
2 #
3 # Template::View
4 #
5 # DESCRIPTION
6 #   A custom view of a template processing context.  Can be used to 
7 #   implement custom "skins".
8 #
9 # AUTHOR
10 #   Andy Wardley   <abw@kfs.org>
11 #
12 # COPYRIGHT
13 #   Copyright (C) 2000 Andy Wardley.  All Rights Reserved.
14 #
15 #   This module is free software; you can redistribute it and/or
16 #   modify it under the same terms as Perl itself.
17 #
18 # TODO
19 #  * allowing print to have a hash ref as final args will cause problems
20 #    if you do this: [% view.print(hash1, hash2, hash3) %].  Current
21 #    work-around is to do [% view.print(hash1); view.print(hash2); 
22 #    view.print(hash3) %] or [% view.print(hash1, hash2, hash3, { }) %]
23 #
24 #============================================================================
25
26 package Template::View;
27
28 use strict;
29 use warnings;
30 use base 'Template::Base';
31
32 our $VERSION  = 2.91;
33 our $DEBUG    = 0 unless defined $DEBUG;
34 our @BASEARGS = qw( context );
35 our $AUTOLOAD;
36 our $MAP = {
37     HASH    => 'hash',
38     ARRAY   => 'list',
39     TEXT    => 'text',
40     default => '',
41 };
42
43
44 #------------------------------------------------------------------------
45 # _init(\%config)
46 #
47 # Initialisation method called by the Template::Base class new() 
48 # constructor.  $self->{ context } has already been set, by virtue of
49 # being named in @BASEARGS.  Remaining config arguments are presented 
50 # as a hash reference.
51 #------------------------------------------------------------------------
52
53 sub _init {
54     my ($self, $config) = @_;
55
56     # move 'context' somewhere more private
57     $self->{ _CONTEXT } = $self->{ context };
58     delete $self->{ context };
59     
60     # generate table mapping object types to templates
61     my $map = $config->{ map } || { };
62     $map->{ default } = $config->{ default } unless defined $map->{ default };
63     $self->{ map } = {
64         %$MAP,
65         %$map,
66     };
67
68     # local BLOCKs definition table
69     $self->{ _BLOCKS } = $config->{ blocks } || { };
70     
71     # name of presentation method which printed objects might provide
72     $self->{ method } = defined $config->{ method } 
73                               ? $config->{ method } : 'present';
74     
75     # view is sealed by default preventing variable update after 
76     # definition, however we don't actually seal a view until the 
77     # END of the view definition
78     my $sealed = $config->{ sealed };
79     $sealed = 1 unless defined $sealed;
80     $self->{ sealed } = $sealed ? 1 : 0;
81
82     # copy remaining config items from $config or set defaults
83     foreach my $arg (qw( base prefix suffix notfound silent )) {
84         $self->{ $arg } = $config->{ $arg } || '';
85     }
86
87     # name of data item used by view()
88     $self->{ item } = $config->{ item } || 'item';
89
90     # map methods of form ${include_prefix}_foobar() to include('foobar')?
91     $self->{ include_prefix } = $config->{ include_prefix } || 'include_';
92     # what about mapping foobar() to include('foobar')?
93     $self->{ include_naked  } = defined $config->{ include_naked } 
94                                       ? $config->{ include_naked } : 1;
95
96     # map methods of form ${view_prefix}_foobar() to include('foobar')?
97     $self->{ view_prefix } = $config->{ view_prefix } || 'view_';
98     # what about mapping foobar() to view('foobar')?
99     $self->{ view_naked  } = $config->{ view_naked  } || 0;
100
101     # the view is initially unsealed, allowing directives in the initial 
102     # view template to create data items via the AUTOLOAD; once sealed via
103     # call to seal(), the AUTOLOAD will not update any internal items.
104     delete @$config{ qw( base method map default prefix suffix notfound item 
105                          include_prefix include_naked silent sealed
106                          view_prefix view_naked blocks ) };
107     $config = { %{ $self->{ base }->{ data } }, %$config }
108         if $self->{ base };
109     $self->{ data   } = $config;
110     $self->{ SEALED } = 0;
111
112     return $self;
113 }
114
115
116 #------------------------------------------------------------------------
117 # seal()
118 # unseal()
119 #
120 # Seal or unseal the view to allow/prevent new datat items from being
121 # automatically created by the AUTOLOAD method.
122 #------------------------------------------------------------------------
123
124 sub seal {
125     my $self = shift;
126     $self->{ SEALED } = $self->{ sealed };
127 }
128
129 sub unseal {
130     my $self = shift;
131     $self->{ SEALED } = 0;
132 }
133
134
135 #------------------------------------------------------------------------
136 # clone(\%config)
137 #
138 # Cloning method which takes a copy of $self and then applies to it any 
139 # modifications specified in the $config hash passed as an argument.
140 # Configuration items may also be specified as a list of "name => $value"
141 # arguments.  Returns a reference to the cloned Template::View object.
142 #
143 # NOTE: may need to copy BLOCKS???
144 #------------------------------------------------------------------------
145
146 sub clone {
147     my $self   = shift;
148     my $clone  = bless { %$self }, ref $self;
149     my $config = ref $_[0] eq 'HASH' ? shift : { @_ };
150
151     # merge maps
152     $clone->{ map } = {
153         %{ $self->{ map } },
154         %{ $config->{ map } || { } },
155     };
156
157     # "map => { default=>'xxx' }" can be specified as "default => 'xxx'"
158     $clone->{ map }->{ default } = $config->{ default }
159         if defined $config->{ default };
160
161     # update any remaining config items
162     my @args = qw( base prefix suffix notfound item method include_prefix 
163                    include_naked view_prefix view_naked );
164     foreach my $arg (@args) {
165         $clone->{ $arg } = $config->{ $arg } if defined $config->{ $arg };
166     }
167     push(@args, qw( default map ));
168     delete @$config{ @args };
169
170     # anything left is data
171     my $data = $clone->{ data } = { %{ $self->{ data } } };
172     @$data{ keys %$config } = values %$config;
173
174     return $clone;
175 }
176
177
178 #------------------------------------------------------------------------
179 # print(@items, ..., \%config)
180 #
181 # Prints @items in turn by mapping each to an approriate template using 
182 # the internal 'map' hash.  If an entry isn't found and the item is an 
183 # object that implements the method named in the internal 'method' item,
184 # (default: 'present'), then the method will be called passing a reference
185 # to $self, against which the presenter method may make callbacks (e.g. 
186 # to view_item()).  If the presenter method isn't implemented, then the 
187 # 'default' map entry is consulted and used if defined.  The final argument 
188 # may be a reference to a hash array providing local overrides to the internal
189 # defaults for various items (prefix, suffix, etc).  In the presence
190 # of this parameter, a clone of the current object is first made, applying
191 # any configuration updates, and control is then delegated to it.
192 #------------------------------------------------------------------------
193
194 sub print {
195     my $self = shift;
196
197     # if final config hash is specified then create a clone and delegate to it
198     # NOTE: potential problem when called print(\%data_hash1, \%data_hash2);
199     if ((scalar @_ > 1) && (ref $_[-1] eq 'HASH')) {
200         my $cfg = pop @_;
201         my $clone = $self->clone($cfg)
202             || return;
203         return $clone->print(@_) 
204             || $self->error($clone->error());
205     }
206     my ($item, $type, $template, $present);
207     my $method = $self->{ method };
208     my $map = $self->{ map };
209     my $output = '';
210     
211     # print each argument
212     foreach $item (@_) {
213         my $newtype;
214         
215         if (! ($type = ref $item)) {
216             # non-references are TEXT
217             $type = 'TEXT';
218             $template = $map->{ $type };
219         }
220         elsif (! defined ($template = $map->{ $type })) {
221             # no specific map entry for object, maybe it implements a 
222             # 'present' (or other) method?
223             if ( $method && UNIVERSAL::can($item, $method) ) {
224                 $present = $item->$method($self);       ## call item method
225                 # undef returned indicates error, note that we expect 
226                 # $item to have called error() on the view
227                 return unless defined $present;
228                 $output .= $present;
229                 next;                                   ## NEXT
230             }   
231             elsif ( ref($item) eq 'HASH' 
232                     && defined($newtype = $item->{$method})
233                     && defined($template = $map->{"$method=>$newtype"})) {
234             }
235             elsif ( defined($newtype)
236                     && defined($template = $map->{"$method=>*"}) ) {
237                 $template =~ s/\*/$newtype/;
238             }    
239             elsif (! ($template = $map->{ default }) ) {
240                 # default not defined, so construct template name from type
241                 ($template = $type) =~ s/\W+/_/g;
242             }
243         }
244 #       else {
245 #           $self->DEBUG("defined map type for $type: $template\n");
246 #       }
247         $self->DEBUG("printing view '", $template || '', "', $item\n") if $DEBUG;
248         $output .= $self->view($template, $item)
249             if $template;
250     }
251     return $output;
252 }
253
254
255 #------------------------------------------------------------------------
256 # view($template, $item, \%vars)
257 #
258 # Wrapper around include() which expects a template name, $template,
259 # followed by a data item, $item, and optionally, a further hash array
260 # of template variables.  The $item is added as an entry to the $vars
261 # hash (which is created empty if not passed as an argument) under the
262 # name specified by the internal 'item' member, which is appropriately
263 # 'item' by default.  Thus an external object present() method can
264 # callback against this object method, simply passing a data item to
265 # be displayed.  The external object doesn't have to know what the
266 # view expects the item to be called in the $vars hash.
267 #------------------------------------------------------------------------
268
269 sub view {
270     my ($self, $template, $item) = splice(@_, 0, 3);
271     my $vars = ref $_[0] eq 'HASH' ? shift : { @_ };
272     $vars->{ $self->{ item } } = $item if defined $item;
273     $self->include($template, $vars);
274 }
275
276
277 #------------------------------------------------------------------------
278 # include($template, \%vars)
279 #
280 # INCLUDE a template, $template, mapped according to the current prefix,
281 # suffix, default, etc., where $vars is an optional hash reference 
282 # containing template variable definitions.  If the template isn't found
283 # then the method will default to any 'notfound' template, if defined 
284 # as an internal item.
285 #------------------------------------------------------------------------
286
287 sub include {
288     my ($self, $template, $vars) = @_;
289     my $context = $self->{ _CONTEXT };
290
291     $template = $self->template($template);
292
293     $vars = { } unless ref $vars eq 'HASH';
294     $vars->{ view } ||= $self;
295
296     $context->include( $template, $vars );
297
298 # DEBUGGING
299 #    my $out = $context->include( $template, $vars );
300 #    print STDERR "VIEW return [$out]\n";
301 #    return $out;
302 }
303
304
305 #------------------------------------------------------------------------
306 # template($template)
307 #
308 # Returns a compiled template for the specified template name, according
309 # to the current configuration parameters.
310 #------------------------------------------------------------------------
311
312 sub template {
313     my ($self, $name) = @_;
314     my $context = $self->{ _CONTEXT };
315     return $context->throw(Template::Constants::ERROR_VIEW,
316                            "no view template specified")
317         unless $name;
318
319     my $notfound = $self->{ notfound };
320     my $base = $self->{ base };
321     my ($template, $block, $error);
322
323     return $block
324         if ($block = $self->{ _BLOCKS }->{ $name });
325     
326     # try the named template
327     $template = $self->template_name($name);
328     $self->DEBUG("looking for $template\n") if $DEBUG;
329     eval { $template = $context->template($template) };
330
331     # try asking the base view if not found
332     if (($error = $@) && $base) {
333         $self->DEBUG("asking base for $name\n") if $DEBUG;
334         eval { $template = $base->template($name) };
335     }
336
337     # try the 'notfound' template (if defined) if that failed
338     if (($error = $@) && $notfound) {
339         unless ($template = $self->{ _BLOCKS }->{ $notfound }) {
340             $notfound = $self->template_name($notfound);
341             $self->DEBUG("not found, looking for $notfound\n") if $DEBUG;
342             eval { $template = $context->template($notfound) };
343
344             return $context->throw(Template::Constants::ERROR_VIEW, $error)
345                 if $@;  # return first error
346         }
347     }
348     elsif ($error) {
349         $self->DEBUG("no 'notfound'\n") 
350             if $DEBUG;
351         return $context->throw(Template::Constants::ERROR_VIEW, $error);
352     }
353     return $template;
354 }
355
356     
357 #------------------------------------------------------------------------
358 # template_name($template)
359 #
360 # Returns the name of the specified template with any appropriate prefix
361 # and/or suffix added.
362 #------------------------------------------------------------------------
363
364 sub template_name {
365     my ($self, $template) = @_;
366     $template = $self->{ prefix } . $template . $self->{ suffix }
367         if $template;
368
369     $self->DEBUG("template name: $template\n") if $DEBUG;
370     return $template;
371 }
372
373
374 #------------------------------------------------------------------------
375 # default($val)
376 #
377 # Special case accessor to retrieve/update 'default' as an alias for 
378 # '$map->{ default }'.
379 #------------------------------------------------------------------------
380
381 sub default {
382     my $self = shift;
383     return @_ ? ($self->{ map }->{ default } = shift) 
384               :  $self->{ map }->{ default };
385 }
386
387
388 #------------------------------------------------------------------------
389 # AUTOLOAD
390 #
391
392 # Returns/updates public internal data items (i.e. not prefixed '_' or
393 # '.') or presents a view if the method matches the view_prefix item,
394 # e.g. view_foo(...) => view('foo', ...).  Similarly, the
395 # include_prefix is used, if defined, to map include_foo(...) to
396 # include('foo', ...).  If that fails then the entire method name will
397 # be used as the name of a template to include iff the include_named
398 # parameter is set (default: 1).  Last attempt is to match the entire
399 # method name to a view() call, iff view_naked is set.  Otherwise, a
400 # 'view' exception is raised reporting the error "no such view member:
401 # $method".
402 #------------------------------------------------------------------------
403
404 sub AUTOLOAD {
405     my $self = shift;
406     my $item = $AUTOLOAD;
407     $item =~ s/.*:://;
408     return if $item eq 'DESTROY';
409
410     if ($item =~ /^[\._]/) {
411         return $self->{ _CONTEXT }->throw(Template::Constants::ERROR_VIEW,
412                             "attempt to view private member: $item");
413     }
414     elsif (exists $self->{ $item }) {
415         # update existing config item (e.g. 'prefix') if unsealed
416         return $self->{ _CONTEXT }->throw(Template::Constants::ERROR_VIEW,
417                             "cannot update config item in sealed view: $item")
418             if @_ && $self->{ SEALED };
419         $self->DEBUG("accessing item: $item\n") if $DEBUG;
420         return @_ ? ($self->{ $item } = shift) : $self->{ $item };
421     }
422     elsif (exists $self->{ data }->{ $item }) {
423         # get/update existing data item (must be unsealed to update)
424         if (@_ && $self->{ SEALED }) {
425             return $self->{ _CONTEXT }->throw(Template::Constants::ERROR_VIEW,
426                                   "cannot update item in sealed view: $item")
427                 unless $self->{ silent };
428             # ignore args if silent
429             @_ = ();
430         }
431         $self->DEBUG(@_ ? "updating data item: $item <= $_[0]\n" 
432                         : "returning data item: $item\n") if $DEBUG;
433         return @_ ? ($self->{ data }->{ $item } = shift) 
434                   :  $self->{ data }->{ $item };
435     }
436     elsif (@_ && ! $self->{ SEALED }) {
437         # set data item if unsealed
438         $self->DEBUG("setting unsealed data: $item => @_\n") if $DEBUG;
439         $self->{ data }->{ $item } = shift;
440     }
441     elsif ($item =~ s/^$self->{ view_prefix }//) {
442         $self->DEBUG("returning view($item)\n") if $DEBUG;
443         return $self->view($item, @_);
444     }
445     elsif ($item =~ s/^$self->{ include_prefix }//) {
446         $self->DEBUG("returning include($item)\n") if $DEBUG;
447         return $self->include($item, @_);
448     }
449     elsif ($self->{ include_naked }) {
450         $self->DEBUG("returning naked include($item)\n") if $DEBUG;
451         return $self->include($item, @_);
452     }
453     elsif ($self->{ view_naked }) {
454         $self->DEBUG("returning naked view($item)\n") if $DEBUG;
455         return $self->view($item, @_);
456     }
457     else {
458         return $self->{ _CONTEXT }->throw(Template::Constants::ERROR_VIEW,
459                                          "no such view member: $item");
460     }
461 }
462
463
464 1;
465
466
467 __END__
468
469 =head1 NAME
470
471 Template::View - customised view of a template processing context
472
473 =head1 SYNOPSIS
474
475     # define a view
476     [% VIEW view
477             # some standard args
478             prefix        => 'my_', 
479             suffix        => '.tt2',
480             notfound      => 'no_such_file'
481             ...
482
483             # any other data
484             title         => 'My View title'
485             other_item    => 'Joe Random Data'
486             ...
487     %]
488        # add new data definitions, via 'my' self reference
489        [% my.author = "$abw.name <$abw.email>" %]
490        [% my.copy   = "&copy; Copyright 2000 $my.author" %]
491
492        # define a local block
493        [% BLOCK header %]
494        This is the header block, title: [% title or my.title %]
495        [% END %]
496
497     [% END %]
498
499     # access data items for view
500     [% view.title %]
501     [% view.other_item %]
502
503     # access blocks directly ('include_naked' option, set by default)
504     [% view.header %]
505     [% view.header(title => 'New Title') %]
506
507     # non-local templates have prefix/suffix attached
508     [% view.footer %]           # => [% INCLUDE my_footer.tt2 %]
509
510     # more verbose form of block access
511     [% view.include( 'header', title => 'The Header Title' ) %]
512     [% view.include_header( title => 'The Header Title' ) %]
513
514     # very short form of above ('include_naked' option, set by default)
515     [% view.header( title => 'The Header Title' ) %]
516
517     # non-local templates have prefix/suffix attached
518     [% view.footer %]           # => [% INCLUDE my_footer.tt2 %]
519
520     # fallback on the 'notfound' template ('my_no_such_file.tt2')
521     # if template not found 
522     [% view.include('missing') %]
523     [% view.include_missing %]
524     [% view.missing %]
525
526     # print() includes a template relevant to argument type
527     [% view.print("some text") %]     # type=TEXT, template='text'
528
529     [% BLOCK my_text.tt2 %]           # 'text' with prefix/suffix
530        Text: [% item %]
531     [% END %]
532
533     # now print() a hash ref, mapped to 'hash' template
534     [% view.print(some_hash_ref) %]   # type=HASH, template='hash'
535
536     [% BLOCK my_hash.tt2 %]           # 'hash' with prefix/suffix
537        hash keys: [% item.keys.sort.join(', ')
538     [% END %]
539
540     # now print() a list ref, mapped to 'list' template
541     [% view.print(my_list_ref) %]     # type=ARRAY, template='list'
542
543     [% BLOCK my_list.tt2 %]           # 'list' with prefix/suffix
544        list: [% item.join(', ') %]
545     [% END %]
546
547     # print() maps 'My::Object' to 'My_Object'
548     [% view.print(myobj) %]
549
550     [% BLOCK my_My_Object.tt2 %]
551        [% item.this %], [% item.that %]
552     [% END %]
553
554     # update mapping table
555     [% view.map.ARRAY = 'my_list_template' %]
556     [% view.map.TEXT  = 'my_text_block'    %]
557
558
559     # change prefix, suffix, item name, etc.
560     [% view.prefix = 'your_' %]
561     [% view.default = 'anyobj' %]
562     ...
563
564 =head1 DESCRIPTION
565
566 TODO
567
568 =head1 METHODS
569
570 =head2 new($context, \%config)
571
572 Creates a new Template::View presenting a custom view of the specified 
573 $context object.
574
575 A reference to a hash array of configuration options may be passed as the 
576 second argument.
577
578 =over 4
579
580 =item prefix
581
582 Prefix added to all template names.
583
584     [% USE view(prefix => 'my_') %]
585     [% view.view('foo', a => 20) %]     # => my_foo
586
587 =item suffix
588
589 Suffix added to all template names.
590
591     [% USE view(suffix => '.tt2') %]
592     [% view.view('foo', a => 20) %]     # => foo.tt2
593
594 =item map 
595
596 Hash array mapping reference types to template names.  The print() 
597 method uses this to determine which template to use to present any
598 particular item.  The TEXT, HASH and ARRAY items default to 'test', 
599 'hash' and 'list' appropriately.
600
601     [% USE view(map => { ARRAY   => 'my_list', 
602                          HASH    => 'your_hash',
603                          My::Foo => 'my_foo', } ) %]
604
605     [% view.print(some_text) %]         # => text
606     [% view.print(a_list) %]            # => my_list
607     [% view.print(a_hash) %]            # => your_hash
608     [% view.print(a_foo) %]             # => my_foo
609
610     [% BLOCK text %]
611        Text: [% item %]
612     [% END %]
613
614     [% BLOCK my_list %]
615        list: [% item.join(', ') %]
616     [% END %]
617
618     [% BLOCK your_hash %]
619        hash keys: [% item.keys.sort.join(', ')
620     [% END %]
621
622     [% BLOCK my_foo %] 
623        Foo: [% item.this %], [% item.that %]
624     [% END %]
625
626 =item method
627
628 Name of a method which objects passed to print() may provide for presenting
629 themselves to the view.  If a specific map entry can't be found for an 
630 object reference and it supports the method (default: 'present') then 
631 the method will be called, passing the view as an argument.  The object 
632 can then make callbacks against the view to present itself.
633
634     package Foo;
635
636     sub present {
637         my ($self, $view) = @_;
638         return "a regular view of a Foo\n";
639     }
640
641     sub debug {
642         my ($self, $view) = @_;
643         return "a debug view of a Foo\n";
644     }
645
646 In a template:
647
648     [% USE view %]
649     [% view.print(my_foo_object) %]     # a regular view of a Foo
650
651     [% USE view(method => 'debug') %]
652     [% view.print(my_foo_object) %]     # a debug view of a Foo
653
654 =item default
655
656 Default template to use if no specific map entry is found for an item.
657
658     [% USE view(default => 'my_object') %]
659
660     [% view.print(objref) %]            # => my_object
661
662 If no map entry or default is provided then the view will attempt to 
663 construct a template name from the object class, substituting any 
664 sequence of non-word characters to single underscores, e.g.
665
666     # 'fubar' is an object of class Foo::Bar
667     [% view.print(fubar) %]             # => Foo_Bar
668
669 Any current prefix and suffix will be added to both the default template 
670 name and any name constructed from the object class.
671
672 =item notfound
673
674 Fallback template to use if any other isn't found.
675
676 =item item
677
678 Name of the template variable to which the print() method assigns the current
679 item.  Defaults to 'item'.
680
681     [% USE view %]
682     [% BLOCK list %] 
683        [% item.join(', ') %] 
684     [% END %]
685     [% view.print(a_list) %]
686
687     [% USE view(item => 'thing') %]
688     [% BLOCK list %] 
689        [% thing.join(', ') %] 
690     [% END %]
691     [% view.print(a_list) %]
692
693 =item view_prefix
694
695 Prefix of methods which should be mapped to view() by AUTOLOAD.  Defaults
696 to 'view_'.
697
698     [% USE view %]
699     [% view.view_header() %]                    # => view('header')
700
701     [% USE view(view_prefix => 'show_me_the_' %]
702     [% view.show_me_the_header() %]             # => view('header')
703
704 =item view_naked
705
706 Flag to indcate if any attempt should be made to map method names to 
707 template names where they don't match the view_prefix.  Defaults to 0.
708
709     [% USE view(view_naked => 1) %]
710
711     [% view.header() %]                 # => view('header')
712
713 =back
714
715 =head2 print( $obj1, $obj2, ... \%config)
716
717 TODO
718
719 =head2 view( $template, \%vars, \%config );
720
721 TODO
722
723 =head1 AUTHOR
724
725 Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/>
726
727 =head1 COPYRIGHT
728
729 Copyright (C) 2000-2007 Andy Wardley.  All Rights Reserved.
730
731 This module is free software; you can redistribute it and/or
732 modify it under the same terms as Perl itself.
733
734 =head1 SEE ALSO
735
736 L<Template::Plugin>
737
738 =cut
739
740
741
742
743