Moxie

 view release on metacpan or  search on metacpan

lib/Moxie.pm  view on Meta::CPAN


            # TODO - i18n the error message
            $args{required} = 'A value for `'.$name.'` is required'
                if exists $args{required}
                && $args{required} =~ /^1$/;

            my $initializer = MOP::Slot::Initializer->new(
                within_package => $meta->name,
                %args
            );

            $meta->add_slot( $name, $initializer );
            return;
        }
    );

    BEGIN::Lift::install(
        ($caller, 'extends') => sub (@isa) {
            Module::Runtime::use_package_optimistically( $_ ) foreach @isa;
            ($meta->isa('MOP::Class')
                ? $meta
                : do {
                    # FIXME:
                    # This is gross ... - SL
                    Internals::SvREADONLY( $$meta, 0 );
                    bless $meta => 'MOP::Class'; # cast into class
                    Internals::SvREADONLY( $$meta, 1 );
                    $meta;
                }
            )->set_superclasses( @isa );
            return;
        }
    );

    BEGIN::Lift::install(
        ($caller, 'with') => sub (@does) {
            Module::Runtime::use_package_optimistically( $_ ) foreach @does;
            $meta->set_roles( @does );
            return;
        }
    );

    # setup the base traits,
    my @traits = Moxie::Traits::Provider::list_providers();
    # and anything we were asked to load ...
    if ( exists $opts->{'traits'} ) {
        foreach my $trait ( $opts->{'traits'}->@* ) {
            if ( $trait eq ':experimental' ) {
                push @traits => Moxie::Traits::Provider::list_experimental_providers();;
            }
            else {
                push @traits => $trait;
            }
        }
    }

    # then schedule the trait collection ...
    Method::Traits->import_into( $meta->name, @traits );

    # install our class finalizer
    MOP::Util::defer_until_UNITCHECK(sub {

        # pre-populate the cache for all the slots (if it is a class)
        MOP::Util::inherit_slots( $meta );

        # apply roles ...
        MOP::Util::compose_roles( $meta );

        # TODO:
        # Consider locking the %HAS hash now, this will
        # prevent anyone from adding new fields after
        # compile time.
        # - SL

    });
}

1;

__END__

=pod

=head1 NAME

Moxie - Not Another Moose Clone

=head1 VERSION

version 0.07

=head1 SYNOPSIS

    package Point {
        use Moxie;

        extends 'Moxie::Object';

        has x => ( default => sub { 0 } );
        has y => ( default => sub { 0 } );

        sub x : ro;
        sub y : ro;

        sub clear ($self) {
            $self->@{ 'x', 'y' } = (0, 0);
        }
    }

    package Point3D {
        use Moxie;

        extends 'Point';

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

        sub z : ro;

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

lib/Moxie.pm  view on Meta::CPAN

protocol – but to do it in a more straightforward and resource
efficient way that requires lower cognative overhead.

The key tenents of L<Moxie> are as follows:

=head2 Aims to be ultra-modern

L<Moose> was a post-modern object system, so what is after post
modernism? Post, post modernism? Who knows, it is 2017 and instead
of flying cars we are careening towards a dystopian timeline and
a future that none of us can forsee. So given that, B<ultra> seemed
to work as well as anything else.

This tenent means that we will not shy away from new Perl features
and we have core a commitment to helping to push the language forward.

=head2 Better distinction between public & private

The clean sepeartion of the public and private interfaces of your
class is key to maintaining good encapsulation. This is one of the key
features required for writing robust and reusable software that can
resist the abuses of fellow programmers and still retain it's
usefulness over time.

=head2 Re-use existing Perl features

Perl is a large language with many features, some of which are useful
and some – I believe – people just haven't found a good use for I<yet>.
L<Moxie> aims to use as many existing B<native> features in Perl when
possible. This can be seen as just another facet of the commitment to
modernity mentioned above, ... it is not old, it is B<retro>!

=head2 Reduce cognative burdon of the MOP

The Meta-Object protocol that powered all the L<Moose> features was
large, complex and difficult to understand unless you were willing to
put in the cognative investment. Because the MOP was the primary means
of extension for L<Moose>, this meant it was not optional if you wanted
to extend L<Moose>. L<Moxie> instead turns the tables, such that it has
multiple means of extension, most (but not all) of which are empowered
by the L<MOP>. This means that an understanding of the L<MOP> is no
longer required to extend L<Moxie>, but when needed the full power of
a L<MOP> is available.

=head2 Better resource usage

L<Moose> is famous for it's high startup overhead and heavy memory
usage. These were consequences of the way in which L<Moose> was
implemented. With L<Moxie> we instead try to do the least amount of
work possible so as to introduce the least amount of overhead.

=head1 KEYWORDS

L<Moxie> exports a few keywords using the L<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 L<UNIVERSAL::Object> and L<MOP>
modules.

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

=over 4

=item C<extends @superclasses>

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

If this is called, L<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 C<@ISA> variable in the current package.

=item C<with @roles>

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

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

This will populate the C<@DOES> variable in the current package.

=item C<< has $name => sub { $default_value } >>

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

This will populate the C<%HAS> variable in the current package.

=back

=head1 METHOD TRAITS

It is possible to have L<Moxie> load your L<Method::Traits> providers,
this is done when C<use>ing L<Moxie> like this:

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

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

Some traits below are listed as experimental, in order to enable those
traits the string C<:experimental> (with the leading colon) must appear
in your traits list.

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

=head3 B<A word about slot names and method trait syntax>

The way C<perl> parses C<CODE> attributes is that everything within the
C<()> 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.

=head2 CONSTRUCTOR TRAITS

=over 4

=item C<< strict( arg_key => slot_name, ... ) >>

This is a trait that is exclusively applied to the C<BUILDARGS>
method. This is a means for generating a strict interface for the
C<BUILDARGS> method that will map a set of constructor parameters
to a set of given slots, 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 : strict( foo => _bar );

All other parameters will be rejected and an exception thrown. If
you wish to have an optional parameter, simply follow the parameter



( run in 1.685 second using v1.01-cache-2.11-cpan-524268b4103 )