https://github.com/ovid/moosex-extended
Build a better Moose.
https://github.com/ovid/moosex-extended
oop perl
Last synced: 4 months ago
JSON representation
Build a better Moose.
- Host: GitHub
- URL: https://github.com/ovid/moosex-extended
- Owner: Ovid
- License: other
- Created: 2022-05-18T09:58:33.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2023-06-06T04:43:07.000Z (over 2 years ago)
- Last Synced: 2023-08-09T12:16:25.066Z (about 2 years ago)
- Topics: oop, perl
- Language: Perl
- Homepage: https://metacpan.org/pod/MooseX::Extended
- Size: 474 KB
- Stars: 4
- Watchers: 4
- Forks: 5
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: Changes
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# NAME
MooseX::Extended - Extend Moose with safe defaults and useful features
# VERSION
version 0.35
# SYNOPSIS
```perl
package My::Names {
use MooseX::Extended types => [qw(compile Num NonEmptyStr Str PositiveInt ArrayRef)];
use List::Util 'sum';# the distinction between `param` and `field` makes it easier to
# see which are available to `new`
param _name => ( isa => NonEmptyStr, init_arg => 'name' );
param title => ( isa => Str, required => 0 );# forbidden in the constructor
field created => ( isa => PositiveInt, default => sub {time} );sub name ($self) {
my $title = $self->title;
my $name = $self->_name;
return $title ? "$title $name" : $name;
}sub add ( $self, $args ) {
state $check = compile( ArrayRef [ Num, 1 ] ); # at least one number
($args) = $check->($args);
return sum( $args->@* );
}sub warnit ($self) {
carp("this is a warning");
}
}
```# DESCRIPTION
This module is **BETA** code. It's feature-complete for release and has no
known bugs. We believe it's ready for production, but make no promises.This is a quick overview. See [MooseX::Extended::Manual::Tutorial](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3ATutorial) for more
information.This class attempts to create a safer version of Moose that defaults to
read-only attributes and is easier to read and write.It tries to bring some of the lessons learned from [the Corinna
project](https://github.com/Ovid/Cor), while acknowledging that you can't
always get what you want (such as true encapsulation and true methods).This:
```perl
package My::Class {
use MooseX::Extended;... your code here
}
```Is sort of the equivalent to:
```perl
package My::Class {
use v5.20.0;
use Moose;
use MooseX::StrictConstructor;
use feature qw( signatures postderef postderef_qq );
no warnings qw( experimental::signatures experimental::postderef );
use namespace::autoclean;
use Carp;
use mro 'c3';... your code here
__PACKAGE__->meta->make_immutable;
}
1;
```It also exports two functions which are similar to Moose `has`: `param` and
`field`.A `param` is a required parameter (defaults may be used). A `field` is not
intended to be passed to the constructor.**Note**: the `has` function is still available, even if it's not needed.
Unlike `param` and `field`, it still requires an `is` option.Also, while your author likes the postfix block syntax, it's not required. You
can even safely inline multiple packages in the same file:```perl
package My::Point;
use MooseX::Extended types => 'Num';param [ 'x', 'y' ] => ( isa => Num );
package My::Point::Mutable;
use MooseX::Extended;
extends 'My::Point';param [ '+x', '+y' ] => ( writer => 1, clearer => 1, default => 0 );
sub invert ($self) {
my ( $x, $y ) = ( $self->x, $self->y );
$self->set_x($y);
$self->set_y($x);
}# MooseX::Extended will cause this to return true, even if we try to return
# false
0;
```# CONFIGURATION
You may pass an import list to [MooseX::Extended](https://metacpan.org/pod/MooseX%3A%3AExtended).
```perl
use MooseX::Extended
excludes => [qw/StrictConstructor carp/], # I don't want these features
types => [qw/compile PositiveInt HashRef/]; # I want these type tools
```## `types`
Allows you to import any types provided by [MooseX::Extended::Types](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3ATypes).
This:
```perl
use MooseX::Extended::Role types => [qw/compile PositiveInt HashRef/];
```Is identical to this:
```perl
use MooseX::Extended::Role;
use MooseX::Extended::Types qw( compile PositiveInt HashRef );
```## `excludes`
You may find some features to be annoying, or even cause potential bugs (e.g.,
if you have a `croak` method, our importing of `Carp::croak` will be a
problem.A single argument to `excludes` can be a string. Multiple `excludes` require
an array reference:```perl
use MooseX::Extended excludes => [qw/StrictConstructor autoclean/];
```You can exclude the following:
- `StrictConstructor`
```perl
use MooseX::Extended excludes => 'StrictConstructor';
```Excluding this will no longer import `MooseX::StrictConstructor`.
- `autoclean`
```perl
use MooseX::Extended excludes => 'autoclean';
```Excluding this will no longer import `namespace::autoclean`.
- `c3`
```perl
use MooseX::Extended excludes => 'c3';
```Excluding this will no longer apply the C3 mro.
- `carp`
```perl
use MooseX::Extended excludes => 'carp';
```Excluding this will no longer import `Carp::croak` and `Carp::carp`.
- `immutable`
```perl
use MooseX::Extended excludes => 'immutable';
```Excluding this will no longer make your class immutable.
- `true`
```perl
use MooseX::Extended excludes => 'true';
```Excluding this will require your module to end in a true value.
- `param`
```perl
use MooseX::Extended excludes => 'param';
```Excluding this will make the `param` function unavailable.
- `field`
```perl
use MooseX::Extended excludes => 'field';
```Excluding this will make the `field` function unavailable.
## `includes`
Several _optional_ features of [MooseX::Extended](https://metacpan.org/pod/MooseX%3A%3AExtended) make this module much more
powerful. For example, to include try/catch and a `method` keyword:```perl
use MooseX::Extended includes => [ 'method', 'try' ];
```A single argument to `includes` can be a string. Multiple `includes` require
an array reference:```perl
use MooseX::Extended includes => [qw/method try/];
```See [MooseX::Extended::Manual::Includes](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3AIncludes) for more information.
# REDUCING BOILERPLATE
Let's say you've settled on the following feature set:
```perl
use MooseX::Extended
excludes => [qw/StrictConstructor carp/],
includes => 'method',
types => ':Standard';
```And you keep typing that over and over. We've removed a lot of boilerplate,
but we've added different boilerplate. Instead, just create
`My::Custom::Moose` and `use My::Custom::Moose;`. See
[MooseX::Extended::Custom](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3ACustom) for details.# IMMUTABILITY
## Making Your Class Immutable
You no longer need to end your Moose classes with:
```
__PACKAGE__->meta->make_immutable;
```That prevents further changes to the class and provides some optimizations to
make the code run much faster. However, it's somewhat annoying to type. We do
this for you, via [B::Hooks::AtRuntime](https://metacpan.org/pod/B%3A%3AHooks%3A%3AAtRuntime). You no longer need to do this yourself.## Making Your Instance Immutable
By default, attributes defined via `param` and `field` are read-only.
However, if they contain a reference, you can fetch the reference, mutate it,
and now everyone with a copy of that reference has mutated state.To handle that, we offer a new `clone => $clone_type` pair for attributes.
See the [MooseX::Extended::Manual::Cloning](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3ACloning) documentation.
# OBJECT CONSTRUCTION
Object construction for [MooseX::Extended](https://metacpan.org/pod/MooseX%3A%3AExtended) is identical to Moose because
MooseX::Extended _is_ Moose, so no changes are needed. However, in addition
to `has`, we also provide `param` and `field` attributes, both of which are
`is => 'ro'` by default.The `param` is _required_, whether by passing it to the constructor, or using
`default` or `builder`.The `field` is _forbidden_ in the constructor and is lazy if it has a
builder, because that builder is often dependent on attributes set in the
constructor (and why call it if it's not used?).Here's a short example:
```perl
package Class::Name {
use MooseX::Extended types => [qw(compile Num NonEmptyStr Str)];# these default to 'ro' (but you can override that) and are required
param _name => ( isa => NonEmptyStr, init_arg => 'name' );
param title => ( isa => Str, required => 0 );# fields must never be passed to the constructor
# note that ->title and ->name are guaranteed to be set before
# this because fields are lazy by default
field name => (
isa => NonEmptyStr,
default => sub ($self) {
my $title = $self->title;
my $name = $self->_name;
return $title ? "$title $name" : $name;
},
);
}
```See [MooseX::Extended::Manual::Construction](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3AConstruction) for a full explanation.
# ATTRIBUTE SHORTCUTS
When using `field` or `param`, we have some attribute shortcuts:
```perl
param name => (
isa => NonEmptyStr,
writer => 1, # set_name
reader => 1, # get_name
predicate => 1, # has_name
clearer => 1, # clear_name
builder => 1, # _build_name
);sub _build_name ($self) {
...
}
```You can also do this:
```perl
param name ( isa => NonEmptyStr, builder => sub {...} );
```That's the same as:
```perl
param name ( isa => NonEmptyStr, builder => '_build_name' );sub _build_name {...}
```See [MooseX::Extended::Manual::Shortcuts](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3AShortcuts) for a full explanation.
# INVALID ATTRIBUTE DEFINITIONS
The following [Moose](https://metacpan.org/pod/Moose) code will print `WhoAmI`. However, the second attribute
name is clearly invalid.```perl
package Some::Class {
use Moose;has name => ( is => 'ro' );
has '-bad' => ( is => 'ro' );
}my $object = Some::Class->new( name => 'WhoAmI' );
say $object->name;
````MooseX::Extended` will throw a
[Moose::Exception::InvalidAttributeDefinition](https://metacpan.org/pod/Moose%3A%3AException%3A%3AInvalidAttributeDefinition) exception if it encounters an
illegal method name for an attribute.This also applies to various attributes which allow method names, such as
`clone`, `builder`, `clearer`, `writer`, `reader`, and `predicate`.Trying to pass a defined `init_arg` to `field` will also throw this
exception, unless the init\_arg begins with an underscore. (It is sometimes
useful to be able to define an `init_arg` for unit testing.)# BUGS AND LIMITATIONS
None known at this time.
# MANUAL
- [MooseX::Extended::Manual::Tutorial](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3ATutorial)
- [MooseX::Extended::Manual::Overview](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3AOverview)
- [MooseX::Extended::Manual::Construction](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3AConstruction)
- [MooseX::Extended::Manual::Includes](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3AIncludes)
- [MooseX::Extended::Manual::Shortcuts](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3AShortcuts)
- [MooseX::Extended::Manual::Cloning](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3AManual%3A%3ACloning)# RELATED MODULES
- [MooseX::Extended::Types](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3ATypes) is included in the distribution.
This provides core types for you.
- [MooseX::Extended::Role](https://metacpan.org/pod/MooseX%3A%3AExtended%3A%3ARole) is included in the distribution.
`MooseX::Extended`, but for roles.
# TODO
Some of this may just be wishful thinking. Some of this would be interesting if
others would like to collaborate.## Configurable Types
We provide `MooseX::Extended::Types` for convenience, along with the `declare`
function. We should write up (and test) examples of extending it.## `BEGIN::Lift`
This idea maybe belongs in `MooseX::Extended::OverKill`, but ...
Quite often you see things like this:
```
BEGIN { extends 'Some::Parent' }
```Or this:
```perl
sub serial_number; # required by a role, must be compile-time
has serial_number => ( ... );
```In fact, there are a variety of Moose functions which would work better if
they ran at compile-time instead of runtime, making them look a touch more
like native functions. My various attempts at solving this have failed, but I
confess I didn't try too hard.# NOTES
There are a few things you might be interested to know about this module when
evaluating it.Most of this is written with bog-standard [Moose](https://metacpan.org/pod/Moose), so there's nothing
terribly weird inside, but you may wish to note that we use
[B::Hooks::AtRuntime](https://metacpan.org/pod/B%3A%3AHooks%3A%3AAtRuntime) and [true](https://metacpan.org/pod/true). They seem sane, but _caveat emptor_.# SEE ALSO
- [Corinna](https://github.com/Ovid/Cor)
The RFC of the new version of OOP planned for the Perl core.
- [MooseX::Modern](https://metacpan.org/pod/MooseX::Modern)
MooseX::Modern - Precision classes for Modern Perl
- [Zydeco](https://metacpan.org/pod/Zydeco)
Zydeco - Jazz up your Perl
- [Dios](https://metacpan.org/pod/Dios)
Dios - Declarative Inside-Out Syntax
- [MooseX::AttributeShortcuts](https://metacpan.org/pod/MooseX::AttributeShortcuts)
MooseX::AttributeShortcuts - Shorthand for common attribute options
# AUTHOR
Curtis "Ovid" Poe
# COPYRIGHT AND LICENSE
This software is Copyright (c) 2022 by Curtis "Ovid" Poe.
This is free software, licensed under:
```
The Artistic License 2.0 (GPL Compatible)
```