Badger
view release on metacpan or search on metacpan
lib/Badger/Prototype.pm view on Meta::CPAN
__END__
=head1 NAME
Badger::Prototype - base class for creating prototype classes
=head1 SYNOPSIS
package Badger::Example;
use base 'Badger::Prototype';
sub greeting {
my $self = shift;
# get prototype object if called as a class method
$self = $self->prototype() unless ref $self;
# continue as normal, now $self is an object
if (@_) {
# set greeting if called with args
return ($self->{ greeting } = shift);
}
else {
# otherwise get greeting
return $self->{ greeting };
}
}
=head1 DESCRIPTION
This module is a subclass of L<Badger::Base> that additionally provides
the L<prototype()> method. It is used as a base class for modules that
have methods that can be called as either class or object methods.
# object method
my $object = Badger::Example->new();
$object->greeting('Hello World');
# class method
Badger::Example->greeting('Hello World');
The L<prototype()> method returns a singleton object instance which can be
used as a default object by methods that have been called as class methods.
Here's an example of a C<greeting()> method that can be called with an argument
to set a greeting message:
$object->greeting('Hello World');
Or without any arguments to get the current message:
print $object->greeting; # Hello World
As well as being called as an object method, we want to be able to call it
as a class method:
Badger::Example->greeting('Hello World');
print Badger::Example->greeting(); # Hello World
Here's what the C<greeting()> method looks like.
package Badger::Example;
use base 'Badger::Prototype';
sub greeting {
my $self = shift;
# get prototype object if called as a class method
$self = $self->prototype() unless ref $self;
# continue as normal, now $self is an object
if (@_) {
# set greeting if called with args
return ($self->{ greeting } = shift);
}
else {
# otherwise get greeting
return $self->{ greeting };
}
}
We use C<ref $self> to determine if C<greeting()> has been called as an object
method (C<$self> contains an object reference) or as a class method (C<$self>
contains the class name, in this case C<Badger::Example>). In the latter
case, we call L<prototype()> as a class method (remember, C<$self> contains
the C<Badger::Example> class name at this point) to return a prototype
object instance which we then store back into C<$self>.
# get prototype object if called as a class method
$self = $self->prototype() unless ref $self;
For the rest of the method we can continue as if called as an object
method because C<$self> now contains a C<Badger::Example> object
either way.
Note that the prototype object reference is stored in the C<$PROTOTYPE>
variable in the package of the calling object's class. So if you call
prototype on a C<Badger::Example::One> object that is subclassed from
C<Badger::Prototype> then the prototype object will be stored in the
C<$Badger::Example::One::PROTOTYPE> package variable.
=head1 METHODS
=head2 prototype(@args)
Constructor method to create a prototype object and cache it in the
C<$PROTOTYPE> package variable for subsequent use. This is usually
called from inside methods that can operate as class or object methods,
as shown in the earlier example.
sub example {
my $self = shift;
# upgrade $self to an object when called as a class method
$self = $self->prototype() unless ref $self;
# ...code follows...
}
If you prefer a more succinct idiom and aren't too worried about calling the
( run in 0.662 second using v1.01-cache-2.11-cpan-364913b4093 )