The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Moxie - Not Another Moose Clone

VERSION

version 0.04

SYNOPSIS

    package Point {
        use Moxie;

        extends 'Moxie::Object';

        has _x => ( default => sub { 0 } );
        has _y => ( default => sub { 0 } );

        sub new : BUILDARGS(
            x? => _x,
            y? => _y,
        );

        sub x : ro( _x );
        sub y : ro( _y );

        sub clear ($self) { (_x, _y) = (0, 0) }
    }

    package Point3D {
        use Moxie;

        extends 'Point';

        has _z => ( default => sub { 0 } );

        sub new : BUILDARGS(
            x? => super(x),
            y? => super(y),
            z? => _z
        );

        sub z : ro( _z );

        sub clear ($self) {
            $self->next::method;
            _z = 0;
        }
    }

DESCRIPTION

Moxie is a reference implementation for an object system built on top of a set of modules.

UNIVERSAL::Object

This is the suggested base class (through Moxie::Object) for all Moxie classes.

MOP

This provides an API to Classes, Roles, Methods and Slots, which is used by many elements within this module.

BEGIN::Lift

This module is used to create three new keywords; extends, with and has. These keywords are executed during compile time and just make calls to the MOP to affect the class being built.

Method::Traits

This module is used to handle the method traits which are used mostly for method generation (accessors, predicates, etc.).

KEYWORDS

Moxie exports a few keywords using the BEGIN::Lift module described above. These keywords are responsible for setting the correct state in the current package such that it conforms to the expectations of the UNIVERSAL::Object and MOP modules.

All of these keywords are executed during the BEGIN phase, and the keywords themselves are removed in the UNITCHECK phase. This prevents them from being mistaken as methods by both perl and the MOP.

extends @superclasses

This creates an inheritance relationship between the current class and the classes listed in @superclasses.

If this is called, Moxie will assume you are a building a class, otherwise it will assume you are building a role. For the most part, you don't need to care about the difference.

This will populate the @ISA variable in the current package.

with @roles

This sets up a role relationship between the current class or role and the roles listed in @roles.

This will cause Moxie to compose the @roles into the current class or role during the next UNITCHECK phase.

This will populate the @DOES variable in the current package.

has $name => sub { $default_value }

This creates a new slot in the current class or role, with $name being the name of the slot and a subroutine which, when called, returns the $default_value for that slot.

This will populate the %HAS variable in the current package.

METHOD TRAITS

It is possible to have Moxie load your Method::Traits providers, this is done when useing Moxie like this:

    use Moxie traits => [ 'My::Trait::Provider', ... ];

By default Moxie will enable the Moxie::Traits::Provider module to supply this set of traits for use in Moxie classes.

A word about slot names and method trait syntax

The way perl parses CODE attributes is that everything within the () is just passed onto your code for parsing. This means that it is not neccesary to quote slot names within the argument list of a trait, and all examples (eventually) will confrom to this syntax. This is a matter of choice, do as you prefer, but I promise you there is no additional safety or certainty you get from quoting slot names in trait arguments.

init_args( arg_key => slot_name, ... )

This is a trait that is exclusively applied to the BUILDARGS method. This is simply a shortcut to generate a BUILDARGS method that can map a given constructor parameter to a given slot, this is useful for maintaining encapsulation for things like a private slot with a different public name.

    # declare a slot with a private name
    has _bar => sub {};

    # map the `foo` key to the `_bar` slot
    sub BUILDARGS : init_arg( foo => _bar );

All other parameters will be rejected and an exception thrown. If you wish to have an optional parameter, simply follow the parameter name with a question mark, like so:

    # declare a slot with a private name
    has _bar => sub {};

    # the `foo` key is optional, but if
    # given, will store in the `_bar` slot
    sub BUILDARGS : init_arg( foo? => _bar );

If you wish to accept parameters for your superclass's constructor but do not want to specify storage location because of encapsulation concerns, simply use the super designator, like so:

    # map the `foo` key to the local `_bar` slot
    # with the `bar` key, let the superclass decide ...
    sub BUILDARGS : init_arg(
        foo => _bar,
        bar => super(bar)
    );

If you wish to have a constructor that accepts no parameters at all, then simply do this.

    sub BUILDARGS : init_arg;

And the constructor will throw an exception if any arguments at all are passed in.

ro( ?$slot_name )

This will generate a simple read-only accessor for a slot. The $slot_name can optionally be specified, otherwise it will use the name of the method that the trait is being applied to.

    sub foo : ro;
    sub foo : ro(_foo);

If the method name is prefixed with get_, then this trait will infer that the slot name intended is the remainder of the method's name, minus the get_ prefix, such that this:

    sub get_foo : ro;

Is the equivalent of writing this:

    sub get_foo : ro(foo);
rw( ?$slot_name )

This will generate a simple read-write accessor for a slot. The $slot_name can optionally be specified, otherwise it will use the name of the method that the trait is being applied to.

    sub foo : rw;
    sub foo : rw(_foo);

If the method name is prefixed with set_, then this trait will infer that the slot name intended is the remainder of the method's name, minus the set_ prefix, such that this:

    sub set_foo : ro;

Is the equivalent of writing this:

    sub set_foo : ro(foo);
wo( ?$slot_name )

This will generate a simple write-only accessor for a slot. The $slot_name can optionally be specified, otherwise it will use the name of the method that the trait is being applied to.

    sub foo : wo;
    sub foo : wo(_foo);

If the method name is prefixed with set_, then this trait will infer that the slot name intended is the remainder of the method's name, minus the set_ prefix, such that this:

    sub set_foo : ro;

Is the equivalent of writing this:

    sub set_foo : ro(foo);
predicate( ?$slot_name )

This will generate a simple predicate method for a slot. The $slot_name can optionally be specified, otherwise it will use the name of the method that the trait is being applied to.

    sub foo : predicate;
    sub foo : predicate(_foo);

If the method name is prefixed with has_, then this trait will infer that the slot name intended is the remainder of the method's name, minus the has_ prefix, such that this:

    sub has_foo : ro;

Is the equivalent of writing this:

    sub has_foo : ro(foo);
clearer( ?$slot_name )

This will generate a simple clearing method for a slot. The $slot_name can optionally be specified, otherwise it will use the name of the method that the trait is being applied to.

    sub foo : clearer;
    sub foo : clearer(_foo);

If the method name is prefixed with clear_, then this trait will infer that the slot name intended is the remainder of the method's name, minus the clear_ prefix, such that this:

    sub clear_foo : ro;

Is the equivalent of writing this:

    sub clear_foo : ro(foo);
handles( $slot_name->$delegate_method )

This will generate a simple delegate method for a slot. The $slot_name and $delegate_method, seperated by an arrow (->), must be specified or an exception is thrown.

    sub foobar : handles(foo->bar);

No attempt will be made to verify that the value stored in $slot_name is an object, or that it responds to the $delegate_method specified, this is the responsibility of the writer of the class.

FEATURES ENABLED

This module enabled a number of features in Perl which are currently considered experimental, see the experimental module for more information.

signatures
postderef
postderef_qq
current_sub
lexical_subs
say
state
refaliasing

PRAGMAS ENABLED

We enabled both the strict and warnings pragmas, but we disable the reserved warning so that we can use lowercase CODE attributes with Method::Traits.

strict
warnings

AUTHOR

Stevan Little <stevan@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2017 by Stevan Little.

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