File Coverage

blib/lib/Catalyst/View/TT/FunctionGenerator.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package Catalyst::View::TT::FunctionGenerator;
4 2     2   37677 use base qw/Catalyst::View::TT/;
  2         5  
  2         1206  
5              
6 2     2   13 use strict;
  2         5  
  2         73  
7 2     2   31 use warnings;
  2         4  
  2         67  
8              
9 2     2   2187 use Catalyst::Utils ();
  0            
  0            
10             use Class::Inspector ();
11             use Scalar::Util qw/weaken/;
12             use Carp ();
13              
14             our $VERSION = "0.02";
15              
16             __PACKAGE__->mk_accessors(qw/context/);
17              
18             sub ACCEPT_CONTEXT {
19             my ( $self, $c ) = @_;
20             bless { %$self, context => $c }, ref $self;
21             }
22              
23             sub generate_functions {
24             my ( $self, @objects ) = @_;
25              
26             my $c = $self->context;
27              
28             # FIXME
29             # need to add per instance view data whose lifetime is linked to $c's lifetime
30             push @{ $c->{_evil_function_generator_data}{ref $self} }, map {
31             my $meths = ref($_) ? $_ : $c->$_;
32              
33             if ( ref $meths eq "ARRAY" ) {
34             if ( not ref $meths->[0] ) {
35             my ( $name, @methods ) = @$meths;
36             $meths = [ $c->$name => @methods ];
37             }
38             } else {
39             $meths = [ $meths, @{ Class::Inspector->methods( ( ref $meths || $meths ), 'public' ) || Carp::croak("$meths has no methods") } ];
40             }
41              
42             # if there is a closure with $c in it, and it's saved inside $c we have a circular referrence
43             weaken($meths->[0]) if ( $meths->[0] == $c );
44              
45             $meths;
46             } @objects;
47             }
48              
49             # for each item passed to sub, check if its an arrayref, if it is, and the first
50             # item in it is not a ref, then assume its the name of a method on $c, and
51             # call it to get the object. Else assume an entire object (This will end up
52             # with an [name, (method names)] if you pass in a string?). Return an arrayref,
53             # which gets added to the evil list.
54              
55             sub template_vars {
56             my ( $self, $c ) = @_;
57              
58             return (
59             $self->NEXT::template_vars( $c ),
60             map {
61             my ( $obj, @methods ) = @$_;
62             weaken( $obj ) if ( $obj == $c );
63             #see above
64             map { my $method = $_; $method => sub { $obj->$method(@_) } } @methods;
65             }
66             @{ $c->{_evil_function_generator_data}{ref $self} || [] }
67             );
68             }
69              
70             # for each item (arrayref) in the evil list, create a template var using the
71             # method names, that calls that method, on the object in the first slot of the array.
72              
73             __PACKAGE__;
74              
75             __END__
76              
77             =pod
78              
79             =head1 NAME
80              
81             Catalyst::View::TT::FunctionGenerator - Generate functions from ... to be used from a TT view
82              
83             =head1 SYNOPSIS
84              
85             # running this:
86              
87             prompty_wompty> scripts/myapp_create.pl create view ViewName TT
88              
89             # generates a Template Toolkit view component.
90             # change the base class like this:
91              
92             use base 'Catalyst::View::TT::FunctionGenerator';
93              
94             # In a nearby action method (in Controller code)
95             sub action : Local {
96             my ( $self, $c ) = @_;
97              
98             $c->view("ViewName")->generate_functions('prototype');
99             # OR
100             $c->view("ViewName")->generate_functions($c->prototype);
101             # OR
102             $c->view("ViewName")->generate_functions([$c, 'uri_for']);
103              
104             }
105              
106             # In your template, we can now have:
107             [% link_to_remote("foo", { url => uri_for("blah") } ) %]
108              
109             # instead of saying this:
110             [% c.prototype.link_to_remote("foo", { url => c.uri_for("blah") } ) %]
111              
112             Note that the most appropriate place to put this code is probably in an C<end>
113             action at the top level of your application so that access to these functions
114             in uniform accross your templates.
115              
116             =head1 DESCRIPTION
117              
118             This module stuffs given methods as coderefs into your TT variables, enabling the
119             use of shorter names in your templates. To use this plugin, you will need to
120             be using the Singleton plugin as well (so that we only populate one correct
121             copy of the context object).
122              
123             To use, first create a L<Catalyst::View::TT> module in the usual way (see
124             synopsis), then change its base class to this module. To add the method
125             shortcuts, call the generate_functions method in your controller code, in an
126             action, before forwarding to your template.
127              
128             =head1 METHODS
129              
130             =over 4
131              
132             =item generate_functions
133              
134             This is the only available method. It's parameters are a list of one or more
135             of the following:
136              
137             =over 4
138              
139             =item [ $object or method name, (list of method names)]
140              
141             An arrayref, where the first item in the array is either an object (e.g. what
142             C<< $c->prototype >> returns), or a method name that will return an object,
143             when called upon C<$c>, e.g. "prototype". The other array items are the method
144             names of the given object that will be created as template vars.
145              
146             =item $object
147              
148             An object (blessed reference). All methods found for the object will be
149             created as template vars.
150              
151             =item A method name
152              
153             The method name will be called upon <$c>, and all methods for the resulting
154             object will be added as template vars.
155              
156             =back
157              
158             =back
159              
160             =head2 Overriden methods
161              
162             =over 4
163              
164             =item template_vars
165              
166             =back
167              
168             =head1 SEE ALSO
169              
170             L<Catalyst::View::TT>
171             L<Catalyst::Plugin::Singleton>
172              
173             =head1 AUTHORS
174              
175             Yuval Kogman, C<nothingmuch@woobling.org>
176              
177             Jess Robinson, Marcus Ramberg (POD)
178              
179              
180             =head1 COPYRIGHT & LICENSE
181              
182             Copyright (c) 2005 the aforementioned authors. All rights
183             reserved. This program is free software; you can redistribute
184             it and/or modify it under the same terms as Perl itself.
185              
186             =cut
187              
188