Sam, I'm working from the standpoint of not making associate any more complex, actually less so from the end user standpoint. If you look at the code all I've done is added three checks for ($associated_object->can('param') && $option{associate_by_methods}), their associated blocks of code (which are duplicates of existing) and a 17 line function to lookup the methods. The thought of instantiating another object to do what can be done in a few lines of code internally seems far more complex to me. This should also be a boost in performance as you are going directly against the object's methods rather than a layer of indirection that param creates. If a new function is created in my object I only need add the TMPL_VAR to the .tmpl without the need to add support for it to a param method. Of course all of the existing param functionalty will still work as is, so I'm not suggesting a rework of what is already there, just a great deal more flexibility from a small bit of code.
diff -u output (pod included): --- /usr/local/lib/perl5/site_perl/5.8.4/HTML/Template.pm 2004-06-18 13:42:06.000000000 -0400 +++ ./Template.pm 2005-02-11 14:33:42.998984000 -0500 @@ -712,6 +712,28 @@ =item * +associate_by_methods - this will force HTML::Template to look at an objects +methods and retrieve data from them rather than via param (i.e., associated +object does not need to define param). This should maintain backwards +compatibility with existing param use. + +=item * + +associate_by_methods_respect_privacy - this is a prefix that will be looked +for when examining object methods, if found then those methods will not be +useable in the template. Setting to 1 will cause the default of '_' to be +used. This allows you to actually keep private methods private: + + my $template = HTML::Template->new(filename => 'template.tmpl', + associate => [$query, $other_obj], + associate_by_methods => 1, + associate_by_methods_respect_privacy => 1); + + $other_obj->_some_private_method(); # '_some_private_method' is NOT a TMPL_VAR + $other_obj->some_public_method(); # 'some_public_method' is a TMPL_VAR + +=item * + case_sensitive - setting this option to true causes HTML::Template to treat template variable names case-sensitively. The following example would only set one parameter without the "case_sensitive" option: @@ -2538,6 +2560,36 @@ } } +# This accepts an object or package name and will return a list of methods +# +# $self->_get_object_methods('HTML::Template',1) +# would return ['associateCGI','carp','clear_params','confess','croak','md5_hex','new','new_array_ref','new_file','new_filehandle','new_scalar_ref','output','param','query'] +# +# Params: +# pkg - either an object or package/module name to be examined +# respect_private - This is a prefix to hide private methods from the list. +# Defaults to '_' if set to 1. TODO://let a regex be passed +# +# Based on function and symTable from http://search.cpan.org/~mpocock/MRP-1.0/MRP/Introspection.pm +# +sub _get_object_methods { + my $self = shift; + my $pkg = shift; + my $respect_private = shift; # won't return methods beginning with an this value, '_' by default + $respect_private = '_' if($respect_private == 1); + $pkg = (ref $pkg || $pkg) . '::'; + + my @methods; + my ($name, $glob); + + no strict 'refs'; + while(($name, $glob) = each %{\%$pkg}) { + defined (*$glob{CODE}) && do { push @methods, $name unless($respect_private && $name =~ /^$respect_private/) }; + } + + return @methods; +} + # obsolete implementation of associate sub associateCGI { @@ -2600,36 +2652,56 @@ # globalize vars - this happens here to localize the circular # references created by global_vars. $self->_globalize_vars() if ($options->{global_vars}); - - # support the associate magic, searching for undefined params and - # attempting to fill them from the associated objects. + if (scalar(@{$options->{associate}})) { - # prepare case-mapping hashes to do case-insensitive matching + # prepare case-mapping hashes to do case-insensitive matching # against associated objects. This allows CGI.pm to be # case-sensitive and still work with asssociate. my (%case_map, $lparam); foreach my $associated_object (@{$options->{associate}}) { # what a hack! This should really be optimized out for case_sensitive. - if ($options->{case_sensitive}) { - map { - $case_map{$associated_object}{$_} = $_ - } $associated_object->param(); - } else { - map { - $case_map{$associated_object}{lc($_)} = $_ - } $associated_object->param(); + if ($associated_object->can('param') && !$options->{associate_by_methods}) { + if ($options->{case_sensitive}) { + map { + $case_map{$associated_object}{$_} = $_ + } $associated_object->param(); + } else { + map { + $case_map{$associated_object}{lc($_)} = $_ + } $associated_object->param(); + } + } else { ### get the object's methods + if ($options->{case_sensitive}) { + map { + $case_map{$associated_object}{$_} = $_ + } $self->_get_object_methods($associated_object,$options->{associate_by_methods_respect_privacy}); + } else { + map { + $case_map{$associated_object}{lc($_)} = $_ + } $self->_get_object_methods($associated_object,$options->{associate_by_methods_respect_privacy}); + } } + } foreach my $param (keys %{$self->{param_map}}) { unless (defined($self->param($param))) { OBJ: foreach my $associated_object (reverse @{$options->{associate}}) { - $self->param($param, scalar $associated_object->param($case_map{$associated_object}{$param})), last OBJ - if (exists($case_map{$associated_object}{$param})); + + if ($associated_object->can('param') && !$options->{associate_by_methods}) { ### + print STDERR "\n". ref($associated_object) . "::param('" . $case_map{$associated_object}{$param} . "');\n"; + $self->param($param, scalar $associated_object->param($case_map{$associated_object}{$param})), last OBJ + if (exists($case_map{$associated_object}{$param})); + } else { + my $method = $case_map{$associated_object}{$param}; + $self->param($param, scalar $associated_object->$method), last OBJ + if (exists($case_map{$associated_object}{$param})); + } + } } } - } + } use vars qw($line @parse_stack); local(*line, *parse_stack); @@ -3331,3 +3403,4 @@ USA =cut + --- Sam Tregar <[EMAIL PROTECTED]> wrote: > On Fri, 11 Feb 2005, Scottsweep wrote: > > > I want to propose the following PATCH to > > HTML::Template. This would allow objects to be > > associated without the need to define a param > method > > (all public methods can be TMPL_VARs). > > This seems like a reasonable thing to want, but I > think it would be > better done with a wrapper object. Imagine: > > use HTML::Template; > use Class::ParamWrapper; > > my $t = HTML::Template->new(filename => $foo, > associate => > Class::ParamWrapper->new($some_object)); > > Class::ParamWrapper would provide a param() method > which proxies calls > to the wrapped object. You can add any > configuration you need to the > Class::ParamWrapper->new() call. > > This has the benefit of not increasing the > complexity of > HTML::Template's associate implementation which is > already pretty > unmanageable. It also opens up your code to use in > other contexts. > > -sam > > PS: If you want to submit a patch in the future > please prepare it > using 'diff -u'. > __________________________________ Do you Yahoo!? Yahoo! Mail - Helps protect you from nasty viruses. http://promotions.yahoo.com/new_mail ------------------------------------------------------- SF email is sponsored by - The IT Product Guide Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now. http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click _______________________________________________ Html-template-users mailing list Html-template-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/html-template-users