Badger

 view release on metacpan or  search on metacpan

lib/Badger/Class/Methods.pm  view on Meta::CPAN


Suppose you have a view class that renders a view of a tree. In classic
I<double dispatch> style, each node in the tree calls a method against the
view object corresponding to the node's type. A C<text> node calls
C<$view-E<gt>view_text($self)>, a C<bold> node calls
C<$view-E<gt>view_bold($self)>, and so on (we're assuming that this is some
kind of document object model we're rendering, but it could apply to
anything).

Our view methods might look something like this:

    sub view_text {
        my ($self, $node) = @_;
        print "TEXT: $node\n";
    }

    sub view_bold {
        my ($self, $node) = @_;
        print "BOLD: $node\n";
    }

This can get rather repetitive and boring if you've got lots of different
node types.  So instead of defining all the methods manually, you can declare
an C<auto_can> method that will create methods on demand.

    use Badger::Class
        auto_can => 'can_view';
        
    sub can_view {
        my ($self, $name) = @_;
        my $NAME = uc $name;
        
        return sub {
            my ($self, $node) = @_;
            print "$NAME: $node";
        }
    }

The method should return a subroutine reference or any false value if it
declines to generate a method.  For example, you might want to limit the 
generator method to only creating methods that match a particular format.

    sub can_view {
        my ($self, $name) = @_;
        
        # only create methods that are prefixed with 'view_'
        if ($name =~ s/^view_//) {
            my $NAME = uc $name;
            
            return sub {
                my ($self, $node) = @_;
                print "$NAME: $node";
            }
        }
        else {
            return undef;
        }
    }

The C<auto_can()> method adds C<AUTOLOAD()> and C<can()> methods to your 
class.  The C<can()> method first looks to see if the method is pre-defined
(i.e. it does what the default C<can()> method does).  If it isn't, it then
calls the C<can_view()> method that we've declared using the C<auto_can> 
option (you can call your method C<auto_can()> if you like, but in this 
case we're calling it C<can_view()> just to be different).  The end result
is that you can call C<can()> and it will generate any missing methods on
demand.

    # this calls can_view() which returns a CODE sub 
    my $method = $object->can('view_italic');

The C<AUTOLOAD()> method is invoked whenever you call a method that 
doesn't exist.  It calls the C<can()> method to automatically generate 
the method and then installs the new method in the package's symbol table.
The next time you call the method it will be there waiting for you.  There's
no need for the C<AUTOLOAD()> method to get involved from that point on.

    # this calls can_view() to create the method and then calls it
    $object->view_cheese('Camembert');      # CHEESE: Camembert
    
    # this directly calls the new method
    $object->view_cheese('Cheddar');        # CHEESE: Cheddar

If your C<can_view()> method returns a false value then C<AUTOLOAD()> 
will raise the familiar "Invalid method..." error that you would normally
get from calling a non-existent method.

=head1 INTERNAL METHODS

=head2 args(@args)

This methods inspect the arguments and performs the necessary validation
for the L<accessors()>, L<mutators()> and L<slots()> methods.

=head1 AUTHOR

Andy Wardley L<http://wardley.org/>

=head1 COPYRIGHT

Copyright (C) 2008-2009 Andy Wardley.  All Rights Reserved.

This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

=cut

# Local Variables:
# mode: perl
# perl-indent-level: 4
# indent-tabs-mode: nil
# End:
#
# vim: expandtab shiftwidth=4:



( run in 0.600 second using v1.01-cache-2.11-cpan-364913b4093 )