NAME
    Spiffy - Spiffy Perl Interface Framework For You

SYNOPSIS
        use Spiffy '-base';
   
DESCRIPTION
    "Spiffy" is a Perl module interface methodology and framework. It is a
    base class for implementing other Perl modules using my favorite tricks.

    Spiffy is different from other Perl object oriented base classes, in
    that it has the ability to export functions. If you create a subclass of
    Spiffy, all the functions that Spiffy exports will automatically be
    exported by your subclass, in addition to any functions that you want to
    export. And if someone creates a subclass of your subclass, all of those
    functions will be exported automatically, and so on.

    Spiffy has an interesting function that it exports called
    "spiffy_constructor()". This function will generate a function that will
    call the class's "new()" constructor. It is smart enough to know which
    class to use. All the arguments you pass to the generated function, get
    passed on to the constructor. In addition, all the arguments you passed
    in the use statement for that class, also get passed to the constructor.

    Spiffy has an interesting way of parsing arguments that you pass to
    "spiffy_constructor" generated functions, and also to "use" statements.
    You declare which arguments are boolean (singletons) and which ones are
    paired, with two special functions called "boolean_arguments" and
    "paired_arguments".

    Spiffy also exports a function called "attribute" that you can use to
    declare the attributes of your class. The "attribute" function will
    generate accessors for you. These attributes can be given defaults
    values as well.

    Perhaps this is all best described through an example. (These are meant
    to be three separate files):

        use Something qw(-cool);
        foo;
        bar;
        my $thing = thing(-name => 'Jimmy');
        $thing->size(11);
    
        package Something;
        use Thing '-base';
        attribute size => 0;
        @EXPORT = qw(foo);
        sub foo { ... }
        sub paired_arguments {
            my $self = shift;
            ('-name', $self->SUPER::paired_arguments)
        }
        1;
   
        package Thing;
        use Spiffy '-base';
        @EXPORT = qw(bar thing);
        sub bar { ... }
        spiffy_constructor 'thing';
        sub boolean_arguments {
            my $self = shift;
            ('-cool', $self->SUPER::boolean_arguments)
        }
        1;

    The top level program uses a module called "Something". "Something"
    exports 3 functions: "foo", "bar" and "thing". The "thing" function
    returns a new "Something" object. The "new()" method for the "Something"
    class is called with the arguments "<-name =" 'Jimmy'>>, and also with
    the arguments "<-cool =" 1>>.

    "Something" is a subclass of "Thing" and "Thing" is a subclass of
    "Spiffy". This is accomplished by importing the base classes with the
    special parameter "-base". This is similar to using the "base.pm" module
    except that it does all the extra Spiffy magic.

    That's Spiffy!

Spiffy FUNCTIONS
    Spiffy defines a few functions that make it Spiffy.

    * attribute
        Defines accessor methods for an attribute of your class:

            package Example;
            use Spiffy '-base';
    
            attribute 'foo';
            attribute 'bar' => 42;

        The first parameter is the name of the attribute. The second
        optional argument is the default value.

        The "attribute" function is only exported if you use the '-base'
        option.

    * spiffy_constructor
        This function generates a function that calls the "new()" method for
        your class. It passes all its arguments on to "new", as well as any
        arguments passed to the "use" statement of your class.

            package Example;
            use Spiffy '-base';
            @EXPORT = qw(foo);
    
            spiffy_constructor 'foo';

        The "spiffy_constructor" function is only exported if you use the '-
        base' option.

Spiffy METHODS
    The following subroutines are all methods rather than functions and
    should be called as such. For example:

        $self->parse_arguments(@arguments);

    * is_spiffy
        Returns true if an object is Spiffy. This method is UNIVERSAL so it
        can be called on all objects.

    * 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, $pairs will contain:

            {
                -name => 'Ingy',
                -has_spots => 1,
                -size => 'large',
                -is_yummy => 0,
            }

        and $others will contain 'red', 'white', and 'black'.

    * boolean_arguments
        Returns the list of arguments that are recognized as being boolean.
        Override this method to define your own list.

    * paired_arguments
        Returns the list of arguments that are recognized as being paired.
        Override this method to define your own list.

    * super
        This function is called without any arguments. It will call the same
        method that it is in, one level higher in the ISA tree, passing it
        all the same arguments.

            sub foo {
                my self = shift;
                super;             # Same as $self->SUPER::foo(@_);
                $self->bar(42);
            }

    * base
        This function will call Spiffy::import at runtime, basically making
        the calling package a subclass of whatever object or class base()
        was called on.

            package XXX;
            BEGIN { require YYY; YYY->base }

        is the same as:

            package XXX;
            use YYY '-base';

    * XXX
        The "XXX" method will die with a YAML Dump of all the arguments
        passed to it. Used for debugging.

Spiffy ARGUMENTS
    When you "use" the Spiffy module or a subclass of it, you can pass it a
    list of arguments. These arguments are parsed using the
    "parse_arguments" method described above. Any arguments that are pairs
    are passed on to calls to a spiffy_constructor generated function. The
    special argument "-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.

USING Spiffy WITH base.pm
    The proper way to use a Spiffy module as a base class is with the
    <-base> parameter to the "use" statement. This differs from typical
    modules where you would want to "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';

  base.pm Caveats
    To make Spiffy work with base.pm a dirty trick was played. Spiffy swaps
    <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.

    * Spiffy must be loaded first.
        If Spiffy is not loaded and "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 ();

    * No Mixing
        "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
        "use base" statements.

AUTHOR
    Brian Ingerson <INGY@cpan.org>

COPYRIGHT
    Copyright (c) 2004. Brian Ingerson. All rights reserved.

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

    See <http://www.perl.com/perl/misc/Artistic.html>

