|
Packit |
69e8b9 |
=pod
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=for comment
|
|
Packit |
69e8b9 |
DO NOT EDIT. This Pod was generated by Swim.
|
|
Packit |
69e8b9 |
See http://github.com/ingydotnet/swim-pm#readme
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=encoding utf8
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 NAME
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy - Spiffy Perl Interface Framework For You
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=for html
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 SYNOPSIS
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package Keen;
|
|
Packit |
69e8b9 |
use Spiffy -Base;
|
|
Packit |
69e8b9 |
field 'mirth';
|
|
Packit |
69e8b9 |
const mood => ':-)';
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
sub happy {
|
|
Packit |
69e8b9 |
if ($self->mood eq ':-(') {
|
|
Packit |
69e8b9 |
$self->mirth(-1);
|
|
Packit |
69e8b9 |
print "Cheer up!";
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
super;
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 DESCRIPTION
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
"Spiffy" is a framework and methodology for doing object oriented (OO)
|
|
Packit |
69e8b9 |
programming in Perl. Spiffy combines the best parts of Exporter.pm, base.pm,
|
|
Packit |
69e8b9 |
mixin.pm and SUPER.pm into one magic foundation class. It attempts to fix all
|
|
Packit |
69e8b9 |
the nits and warts of traditional Perl OO, in a clean, straightforward and
|
|
Packit |
69e8b9 |
(perhaps someday) standard way.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy borrows ideas from other OO languages like Python, Ruby, Java and Perl
|
|
Packit |
69e8b9 |
6. It also adds a few tricks of its own.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
If you take a look on CPAN, there are a ton of OO related modules. When
|
|
Packit |
69e8b9 |
starting a new project, you need to pick the set of modules that makes most
|
|
Packit |
69e8b9 |
sense, and then you need to use those modules in each of your classes. Spiffy,
|
|
Packit |
69e8b9 |
on the other hand, has everything you'll probably need in one module, and you
|
|
Packit |
69e8b9 |
only need to use it once in one of your classes. If you make Spiffy.pm the
|
|
Packit |
69e8b9 |
base class of the basest class in your project, Spiffy will automatically pass
|
|
Packit |
69e8b9 |
all of its magic to all of your subclasses. You may eventually forget that
|
|
Packit |
69e8b9 |
you're even using it!
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
The most striking difference between Spiffy and other Perl object oriented
|
|
Packit |
69e8b9 |
base classes, is that it has the ability to export things. If you create a
|
|
Packit |
69e8b9 |
subclass of Spiffy, all the things that Spiffy exports will automatically be
|
|
Packit |
69e8b9 |
exported by your subclass, in addition to any more things that you want to
|
|
Packit |
69e8b9 |
export. And if someone creates a subclass of your subclass, all of those
|
|
Packit |
69e8b9 |
things will be exported automatically, and so on. Think of it as "Inherited
|
|
Packit |
69e8b9 |
Exportation", and it uses the familiar Exporter.pm specification syntax.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
To use Spiffy or any subclass of Spiffy as a base class of your class, you
|
|
Packit |
69e8b9 |
specify the C<-base> argument to the C<use> command.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
use MySpiffyBaseModule -base;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
You can also use the traditional C<use base 'MySpiffyBaseModule';> syntax and
|
|
Packit |
69e8b9 |
everything will work exactly the same. The only caveat is that Spiffy.pm must
|
|
Packit |
69e8b9 |
already be loaded. That's because Spiffy rewires base.pm on the fly to do all
|
|
Packit |
69e8b9 |
the Spiffy magics.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy has support for Ruby-like mixins with Perl6-like roles. Just like
|
|
Packit |
69e8b9 |
C<base> you can use either of the following invocations:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
use mixin 'MySpiffyBaseModule';
|
|
Packit |
69e8b9 |
use MySpiffyBaseModule -mixin;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
The second version will only work if the class being mixed in is a subclass of
|
|
Packit |
69e8b9 |
Spiffy. The first version will work in all cases, as long as Spiffy has
|
|
Packit |
69e8b9 |
already been loaded.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
To limit the methods that get mixed in, use roles. (Hint: they work just like
|
|
Packit |
69e8b9 |
an Exporter list):
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
use MySpiffyBaseModule -mixin => qw(:basics x y !foo);
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
In object oriented Perl almost every subroutine is a method. Each method gets
|
|
Packit |
69e8b9 |
the object passed to it as its first argument. That means practically every
|
|
Packit |
69e8b9 |
subroutine starts with the line:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
my $self = shift;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy provides a simple, optional filter mechanism to insert that line for
|
|
Packit |
69e8b9 |
you, resulting in cleaner code. If you figure an average method has 10 lines
|
|
Packit |
69e8b9 |
of code, that's 10% of your code! To turn this option on, you just use the C<-
|
|
Packit |
69e8b9 |
Base> option instead of the C<-base> option, or add the C<-selfless> option.
|
|
Packit |
69e8b9 |
If source filtering makes you queazy, don't use the feature. I personally find
|
|
Packit |
69e8b9 |
it addictive in my quest for writing squeaky clean, maintainable code.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
A useful feature of Spiffy is that it exports two functions: C<field> and
|
|
Packit |
69e8b9 |
C<const> that can be used to declare the attributes of your class, and
|
|
Packit |
69e8b9 |
automatically generate accessor methods for them. The only difference between
|
|
Packit |
69e8b9 |
the two functions is that C<const> attributes can not be modified; thus the
|
|
Packit |
69e8b9 |
accessor is much faster.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
One interesting aspect of OO programming is when a method calls the same
|
|
Packit |
69e8b9 |
method from a parent class. This is generally known as calling a super method.
|
|
Packit |
69e8b9 |
Perl's facility for doing this is butt ugly:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
sub cleanup {
|
|
Packit |
69e8b9 |
my $self = shift;
|
|
Packit |
69e8b9 |
$self->scrub;
|
|
Packit |
69e8b9 |
$self->SUPER::cleanup(@_);
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy makes it, er, super easy to call super methods. You just use the
|
|
Packit |
69e8b9 |
C<super> function. You don't need to pass it any arguments because it
|
|
Packit |
69e8b9 |
automatically passes them on for you. Here's the same function with Spiffy:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
sub cleanup {
|
|
Packit |
69e8b9 |
$self->scrub;
|
|
Packit |
69e8b9 |
super;
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy has a special method for parsing arguments called C<parse_arguments>,
|
|
Packit |
69e8b9 |
that it also uses for parsing its own arguments. You declare which arguments
|
|
Packit |
69e8b9 |
are boolean (singletons) and which ones are paired, with two special methods
|
|
Packit |
69e8b9 |
called C<boolean_arguments> and C<paired_arguments>. Parse arguments pulls out
|
|
Packit |
69e8b9 |
the booleans and pairs and returns them in an anonymous hash, followed by a
|
|
Packit |
69e8b9 |
list of the unmatched arguments.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Finally, Spiffy can export a few debugging functions C<WWW>, C<XXX>, C<YYY>
|
|
Packit |
69e8b9 |
and C<ZZZ>. Each of them produces a YAML dump of its arguments. WWW warns the
|
|
Packit |
69e8b9 |
output, XXX dies with the output, YYY prints the output, and ZZZ confesses the
|
|
Packit |
69e8b9 |
output. If YAML doesn't suit your needs, you can switch all the dumps to
|
|
Packit |
69e8b9 |
Data::Dumper format with the C<-dumper> option.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
That's Spiffy!
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 EXPORTING
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy implements a completely new idea in Perl. Modules that act both as
|
|
Packit |
69e8b9 |
object oriented classes and that also export functions. But it takes the
|
|
Packit |
69e8b9 |
concept of Exporter.pm one step further; it walks the entire C<@ISA> path of a
|
|
Packit |
69e8b9 |
class and honors the export specifications of each module. Since Spiffy calls
|
|
Packit |
69e8b9 |
on the Exporter module to do this, you can use all the fancy interface
|
|
Packit |
69e8b9 |
features that Exporter has, including tags and negation.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy considers all the arguments that don't begin with a dash to comprise
|
|
Packit |
69e8b9 |
the export specification.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package Vehicle;
|
|
Packit |
69e8b9 |
use Spiffy -base;
|
|
Packit |
69e8b9 |
our $SERIAL_NUMBER = 0;
|
|
Packit |
69e8b9 |
our @EXPORT = qw($SERIAL_NUMBER);
|
|
Packit |
69e8b9 |
our @EXPORT_BASE = qw(tire horn);
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package Bicycle;
|
|
Packit |
69e8b9 |
use Vehicle -base, '!field';
|
|
Packit |
69e8b9 |
$self->inflate(tire);
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
In this case, C<< Bicycle->isa('Vehicle') >> and also all the things that
|
|
Packit |
69e8b9 |
C<Vehicle> and C<Spiffy> export, will go into C<Bicycle>, except C<field>.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Exporting can be very helpful when you've designed a system with hundreds of
|
|
Packit |
69e8b9 |
classes, and you want them all to have access to some functions or constants
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
or variables. Just export them in your main base class and every subclass
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
will get the functions they need.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
You can do almost everything that Exporter does because Spiffy delegates the
|
|
Packit |
69e8b9 |
job to Exporter (after adding some Spiffy magic). Spiffy offers a
|
|
Packit |
69e8b9 |
C<@EXPORT_BASE> variable which is like C<@EXPORT>, but only for usages that
|
|
Packit |
69e8b9 |
use C<-base>.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 MIXINS & ROLES
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
If you've done much OO programming in Perl you've probably used Multiple
|
|
Packit |
69e8b9 |
Inheritance (MI), and if you've done much MI you've probably run into weird
|
|
Packit |
69e8b9 |
problems and headaches. Some languages like Ruby, attempt to resolve MI
|
|
Packit |
69e8b9 |
issues using a technique called mixins. Basically, all Ruby classes use only
|
|
Packit |
69e8b9 |
Single Inheritance (SI), and then I<mixin> functionality from other modules
|
|
Packit |
69e8b9 |
if they need to.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Mixins can be thought of at a simplistic level as I<importing> the methods of
|
|
Packit |
69e8b9 |
another class into your subclass. But from an implementation standpoint that's
|
|
Packit |
69e8b9 |
not the best way to do it. Spiffy does what Ruby does. It creates an empty
|
|
Packit |
69e8b9 |
anonymous class, imports everything into that class, and then chains the new
|
|
Packit |
69e8b9 |
class into your SI ISA path. In other words, if you say:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package AAA;
|
|
Packit |
69e8b9 |
use BBB -base;
|
|
Packit |
69e8b9 |
use CCC -mixin;
|
|
Packit |
69e8b9 |
use DDD -mixin;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
You end up with a single inheritance chain of classes like this:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
AAA << AAA-DDD << AAA-CCC << BBB;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
C<AAA-DDD> and C<AAA-CCC> are the actual package names of the generated
|
|
Packit |
69e8b9 |
classes. The nice thing about this style is that mixing in CCC doesn't clobber
|
|
Packit |
69e8b9 |
any methods in AAA, and DDD doesn't conflict with AAA or CCC either. If you
|
|
Packit |
69e8b9 |
mixed in a method in CCC that was also in AAA, you can still get to it by
|
|
Packit |
69e8b9 |
using C<super>.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
When Spiffy mixes in CCC, it pulls in all the methods in CCC that do not begin
|
|
Packit |
69e8b9 |
with an underscore. Actually it goes farther than that. If CCC is a subclass
|
|
Packit |
69e8b9 |
it will pull in every method that CCC C<can> do through inheritance. This is
|
|
Packit |
69e8b9 |
very powerful, maybe too powerful.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
To limit what you mixin, Spiffy borrows the concept of Roles from Perl6. The
|
|
Packit |
69e8b9 |
term role is used more loosely in Spiffy though. It's much like an import list
|
|
Packit |
69e8b9 |
that the Exporter module uses, and you can use groups (tags) and negation. If
|
|
Packit |
69e8b9 |
the first element of your list uses negation, Spiffy will start with all the
|
|
Packit |
69e8b9 |
methods that your mixin class can do.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
use EEE -mixin => qw(:tools walk !run !:sharp_tools);
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
In this example, C<walk> and C<run> are methods that EEE can do, and C<tools>
|
|
Packit |
69e8b9 |
and C<sharp_tools> are roles of class EEE. How does class EEE define these
|
|
Packit |
69e8b9 |
roles? It very simply defines methods called C<_role_tools> and
|
|
Packit |
69e8b9 |
C<_role_sharp_tools> which return lists of more methods. (And possibly other
|
|
Packit |
69e8b9 |
roles!) The neat thing here is that since roles are just methods, they too can
|
|
Packit |
69e8b9 |
be inherited. Take B<that> Perl6!
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 FILTERING
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
By using the C<-Base> flag instead of C<-base> you never need to write the
|
|
Packit |
69e8b9 |
line:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
my $self = shift;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
This statement is added to every subroutine in your class by using a source
|
|
Packit |
69e8b9 |
filter. The magic is simple and fast, so there is litte performance penalty
|
|
Packit |
69e8b9 |
for creating clean code on par with Ruby and Python.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package Example;
|
|
Packit |
69e8b9 |
use Spiffy -Base;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
sub crazy {
|
|
Packit |
69e8b9 |
$self->nuts;
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
sub wacky { }
|
|
Packit |
69e8b9 |
sub new() {
|
|
Packit |
69e8b9 |
bless [], shift;
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
is exactly the same as:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package Example;
|
|
Packit |
69e8b9 |
use Spiffy -base;
|
|
Packit |
69e8b9 |
use strict;use warnings;
|
|
Packit |
69e8b9 |
sub crazy {my $self = shift;
|
|
Packit |
69e8b9 |
$self->nuts;
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
sub wacky {my $self = shift; }
|
|
Packit |
69e8b9 |
sub new {
|
|
Packit |
69e8b9 |
bless [], shift;
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
;1;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Note that the empty parens after the subroutine C<new> keep it from having a
|
|
Packit |
69e8b9 |
$self added. Also note that the extra code is added to existing lines to
|
|
Packit |
69e8b9 |
ensure that line numbers are not altered.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
C<-Base> also turns on the strict and warnings pragmas, and adds that annoying
|
|
Packit |
69e8b9 |
'1;' line to your module.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 PRIVATE METHODS
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy now has support for private methods when you use the '-Base' filter
|
|
Packit |
69e8b9 |
mechanism. You just declare the subs with the C<my> keyword, and call them
|
|
Packit |
69e8b9 |
with a C<'$'> in front. Like this:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package Keen;
|
|
Packit |
69e8b9 |
use SomethingSpiffy -Base;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
# normal public method
|
|
Packit |
69e8b9 |
sub swell {
|
|
Packit |
69e8b9 |
$self->$stinky;
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
# private lexical method. uncallable from outside this file.
|
|
Packit |
69e8b9 |
my sub stinky {
|
|
Packit |
69e8b9 |
...
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 SPIFFY DEBUGGING
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
The XXX function is very handy for debugging because you can insert it almost
|
|
Packit |
69e8b9 |
anywhere, and it will dump your data in nice clean YAML. Take the following
|
|
Packit |
69e8b9 |
statement:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
my @stuff = grep { /keen/ } $self->find($a, $b);
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
If you have a problem with this statement, you can debug it in any of the
|
|
Packit |
69e8b9 |
following ways:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
XXX my @stuff = grep { /keen/ } $self->find($a, $b);
|
|
Packit |
69e8b9 |
my @stuff = XXX grep { /keen/ } $self->find($a, $b);
|
|
Packit |
69e8b9 |
my @stuff = grep { /keen/ } XXX $self->find($a, $b);
|
|
Packit |
69e8b9 |
my @stuff = grep { /keen/ } $self->find(XXX $a, $b);
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
XXX is easy to insert and remove. It is also a tradition to mark uncertain
|
|
Packit |
69e8b9 |
areas of code with XXX. This will make the debugging dumpers easy to spot if
|
|
Packit |
69e8b9 |
you forget to take them out.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
WWW and YYY are nice because they dump their arguments and then return the
|
|
Packit |
69e8b9 |
arguments. This way you can insert them into many places and still have the
|
|
Packit |
69e8b9 |
code run as before. Use ZZZ when you need to die with both a YAML dump and a
|
|
Packit |
69e8b9 |
full stack trace.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
The debugging functions are exported by default if you use the C<-base>
|
|
Packit |
69e8b9 |
option, but only if you have previously used the C<-XXX> option. To export all
|
|
Packit |
69e8b9 |
4 functions use the export tag:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
use SomeSpiffyModule ':XXX';
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
To force the debugging functions to use Data::Dumper instead of YAML:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
use SomeSpiffyModule -dumper;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 SPIFFY FUNCTIONS
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
This section describes the functions the Spiffy exports. The C<field>,
|
|
Packit |
69e8b9 |
C<const>, C<stub> and C<super> functions are only exported when you use the
|
|
Packit |
69e8b9 |
C<-base> or C<-Base> options.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=over
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item field
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Defines accessor methods for a field of your class:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package Example;
|
|
Packit |
69e8b9 |
use Spiffy -Base;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
field 'foo';
|
|
Packit |
69e8b9 |
field bar => [];
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
sub lalala {
|
|
Packit |
69e8b9 |
$self->foo(42);
|
|
Packit |
69e8b9 |
push @{$self->{bar}}, $self->foo;
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
The first parameter passed to C<field> is the name of the attribute being
|
|
Packit |
69e8b9 |
defined. Accessors can be given an optional default value. This value will be
|
|
Packit |
69e8b9 |
returned if no value for the field has been set in the object.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item const
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
const bar => 42;
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
The C<const> function is similar to <field> except that it is immutable.
|
|
Packit |
69e8b9 |
It also does not store data in the object. You probably always want to
|
|
Packit |
69e8b9 |
give a C<const> a default value, otherwise the generated method will be
|
|
Packit |
69e8b9 |
somewhat useless.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item stub
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
stub 'cigar';
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
The C<stub> function generates a method that will die with an appropriate
|
|
Packit |
69e8b9 |
message. The idea is that subclasses must implement these methods so that the
|
|
Packit |
69e8b9 |
stub methods don't get called.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item super
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
If this function is called without any arguments, it will call the same method
|
|
Packit |
69e8b9 |
that it is in, higher up in the ISA tree, passing it all the same arguments.
|
|
Packit |
69e8b9 |
If it is called with arguments, it will use those arguments with C<$self> in
|
|
Packit |
69e8b9 |
the front. In other words, it just works like you'd expect.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
sub foo {
|
|
Packit |
69e8b9 |
super; # Same as $self->SUPER::foo(@_);
|
|
Packit |
69e8b9 |
super('hello'); # Same as $self->SUPER::foo('hello');
|
|
Packit |
69e8b9 |
$self->bar(42);
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
sub new() {
|
|
Packit |
69e8b9 |
my $self = super;
|
|
Packit |
69e8b9 |
$self->init;
|
|
Packit |
69e8b9 |
return $self;
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
C<super> will simply do nothing if there is no super method. Finally, C<super>
|
|
Packit |
69e8b9 |
does the right thing in AUTOLOAD subroutines.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=back
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 METHODS
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
This section lists all of the methods that any subclass of Spiffy
|
|
Packit |
69e8b9 |
automatically inherits.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=over
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item mixin
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
A method to mixin a class at runtime. Takes the same arguments as C
|
|
Packit |
69e8b9 |
...>. Makes the target class a mixin of the caller.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
$self->mixin('SomeClass');
|
|
Packit |
69e8b9 |
$object->mixin('SomeOtherClass' => 'some_method');
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item parse_arguments
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
This method takes a list of arguments and groups them into pairs. It allows
|
|
Packit |
69e8b9 |
for boolean arguments which may or may not have a value (defaulting to 1).
|
|
Packit |
69e8b9 |
The method returns a hash reference of all the pairs as keys and values in
|
|
Packit |
69e8b9 |
the hash. Any arguments that cannot be paired, are returned as a list. Here
|
|
Packit |
69e8b9 |
is an example:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
sub boolean_arguments { qw(-has_spots -is_yummy) }
|
|
Packit |
69e8b9 |
sub paired_arguments { qw(-name -size) }
|
|
Packit |
69e8b9 |
my ($pairs, @others) = $self->parse_arguments(
|
|
Packit |
69e8b9 |
'red', 'white',
|
|
Packit |
69e8b9 |
-name => 'Ingy',
|
|
Packit |
69e8b9 |
-has_spots =>
|
|
Packit |
69e8b9 |
-size => 'large',
|
|
Packit |
69e8b9 |
'black',
|
|
Packit |
69e8b9 |
-is_yummy => 0,
|
|
Packit |
69e8b9 |
);
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
After this call, C<$pairs> will contain:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
{
|
|
Packit |
69e8b9 |
-name => 'Ingy',
|
|
Packit |
69e8b9 |
-has_spots => 1,
|
|
Packit |
69e8b9 |
-size => 'large',
|
|
Packit |
69e8b9 |
-is_yummy => 0,
|
|
Packit |
69e8b9 |
}
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
and C<@others> will contain 'red', 'white', and 'black'.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item boolean_arguments
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Returns the list of arguments that are recognized as being boolean. Override
|
|
Packit |
69e8b9 |
this method to define your own list.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item paired_arguments
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Returns the list of arguments that are recognized as being paired. Override
|
|
Packit |
69e8b9 |
this method to define your own list.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=back
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 ARGUMENTS
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
When you C<use> the Spiffy module or a subclass of it, you can pass it a list
|
|
Packit |
69e8b9 |
of arguments. These arguments are parsed using the C<parse_arguments> method
|
|
Packit |
69e8b9 |
described above. The special argument C<-base>, is used to make the current
|
|
Packit |
69e8b9 |
package a subclass of the Spiffy module being used.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Any non-paired parameters act like a normal import list; just like those used
|
|
Packit |
69e8b9 |
with the Exporter module.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 USING SPIFFY WITH BASE.PM
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
The proper way to use a Spiffy module as a base class is with the C<-base>
|
|
Packit |
69e8b9 |
parameter to the C<use> statement. This differs from typical modules where you
|
|
Packit |
69e8b9 |
would want to C<use base>.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package Something;
|
|
Packit |
69e8b9 |
use Spiffy::Module -base;
|
|
Packit |
69e8b9 |
use base 'NonSpiffy::Module';
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Now it may be hard to keep track of what's Spiffy and what is not. Therefore
|
|
Packit |
69e8b9 |
Spiffy has actually been made to work with base.pm. You can say:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
package Something;
|
|
Packit |
69e8b9 |
use base 'Spiffy::Module';
|
|
Packit |
69e8b9 |
use base 'NonSpiffy::Module';
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
C<use base> is also very useful when your class is not an actual module (a
|
|
Packit |
69e8b9 |
separate file) but just a package in some file that has already been loaded.
|
|
Packit |
69e8b9 |
C<base> will work whether the class is a module or not, while the C<-base>
|
|
Packit |
69e8b9 |
syntax cannot work that way, since C<use> always tries to load a module.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head2 base.pm Caveats
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
To make Spiffy work with base.pm, a dirty trick was played. Spiffy swaps
|
|
Packit |
69e8b9 |
C<base::import> with its own version. If the base modules are not Spiffy,
|
|
Packit |
69e8b9 |
Spiffy calls the original base::import. If the base modules are Spiffy, then
|
|
Packit |
69e8b9 |
Spiffy does its own thing.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
There are two caveats.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=over
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item Spiffy must be loaded first.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
If Spiffy is not loaded and C<use base> is invoked on a Spiffy module, Spiffy
|
|
Packit |
69e8b9 |
will die with a useful message telling the author to read this documentation.
|
|
Packit |
69e8b9 |
That's because Spiffy needed to do the import swap beforehand.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
If you get this error, simply put a statement like this up front in your code:
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
use Spiffy ();
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=item No Mixing
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
C<base.pm> can take multiple arguments. And this works with Spiffy as long as
|
|
Packit |
69e8b9 |
all the base classes are Spiffy, or they are all non-Spiffy. If they are
|
|
Packit |
69e8b9 |
mixed, Spiffy will die. In this case just use separate C<use base> statements.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=back
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 SPIFFY TODO LIST
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Spiffy is a wonderful way to do OO programming in Perl, but it is still a work
|
|
Packit |
69e8b9 |
in progress. New things will be added, and things that don't work well, might
|
|
Packit |
69e8b9 |
be removed.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 AUTHOR
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Ingy döt Net <ingy@cpan.org>
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=head1 COPYRIGHT AND LICENSE
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
Copyright 2004-2014. Ingy döt Net.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
This program is free software; you can redistribute it and/or modify it under
|
|
Packit |
69e8b9 |
the same terms as Perl itself.
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
See L<http://www.perl.com/perl/misc/Artistic.html>
|
|
Packit |
69e8b9 |
|
|
Packit |
69e8b9 |
=cut
|