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