STATUS

DESCRIPTION

Moops is sugar for declaring and using roles and classes in Perl.

The syntax is inspired by MooseX::Declare, and Stevan Little's p5-mop-redux project (which is in turn partly inspired by Perl 6).

Moops has fewer than half of the dependencies as MooseX::Declare, loads in about 25% of the time, and the classes built with it run significantly faster. Moops does not use Devel::Declare, instead using Perl's pluggable keyword API; this requires Perl 5.14 or above.

Moops uses Moo to build classes and roles by default, but allows you to use Moose if you desire. (And Mouse experimentally.)

Classes

The class keyword declares a class:

class Foo {
# ...
}

A version number can be provided:

class Foo 1.2 {
# ...
}

If no version is provided, your class' $VERSION variable is set to the empty string; this helps the package be seen by Class::Load.

If your class extends an existing class through inheritance, or consumes one or more roles, these can also be provided when declaring the class.

class Foo::Bar 1.2 extends Foo 1.1 with Magic::Monkeys {
# ...
}

If you use Moops within a package other than main, then package names used within the declaration are "qualified" by that outer package, unless they contain "::". So for example:

If you wish to use Moose or Mouse instead of Moo; include that in the declaration:

class Foo using Moose {
# ...
}

It's also possible to create classes using Tiny (Class::Tiny), but there's probably little point in it, because Moops uses Moo internally, so the more capable Moo is already loaded and in memory.

(The using option is exempt from the package qualification rules mentioned earlier.)

Moops uses MooseX::MungeHas in your classes so that the has keyword supports some Moo-specific features, even when you're using Moose or Mouse. Specifically, it supports is => 'rwp', is => 'lazy', builder => 1, clearer => 1, predicate => 1, and trigger => 1. If you're using Moo, the MooX::late extension is enabled too, which allows Moose-isms in Moo too. With the combination of these features, there should be very little difference between Moo, Mouse and Moose has keywords.

Moops uses Lexical::Accessor to provide you with private (lexical) attributes - that is, attributes accessed via a coderef method in a lexical variable.

Roles

Roles can be declared similarly to classes, but using the role keyword.

role Stringable
using Moose # we know you meant Moose::Role
{
# ...
}

Roles do not support the extends option.

Roles can be declared to be using Moo, Moose, Mouse or Tiny. (Note that if you're mixing and matching role frameworks, there are limitations to which class builders can consume which roles. Mouse is generally the least compatible; Moo and Moose classes should be able to consume each others' roles; Moo can also consume Role::Tiny roles.)

Namespaces

Attribute::Handlers-style attributes are supported for namespaces, but most of the built-in attributes make any sense without class/role semantics. (:assertions does.) Traits written as Moops extensions may support namespaces.

Functions and Methods

Moops uses Kavorka to declare functions and methods within classes and roles. Kavorka provides the fun and method keywords.

Multi Methods

Type Constraints

The Types::Standard type constraints are exported to each package declared using Moops. This allows the standard type constraints to be used as barewords.

Type constraints can be used in attribute definitions (isa) and method signatures. Because Types::Standard is based on Type::Tiny, the same type constraints may be used whether you build your classes and roles with Moo, Moose our Mouse.

Constants

The useful constants true and false are imported into all declared packages. (Within classes and roles, namespace::sweep will later remove them from the symbol table, so they don't form part of your package's API.) These constants can help make attribute declarations more readable.

has name => (is => 'ro', isa => Str, required => true);

Further constants can be declared using the define keyword (see PerlX::Define):

namespace Maths {
define PI = 3.2;
}

Constants declared this way will not be swept away by namespace::sweep, and are considered part of your package's API.

Assertions

Declared packages can contain assertions (see PerlX::Assert). These are normally optimized away at compile time, but you can force them to be checked using the :assertions attribute.

More Sugar

strict and FATAL warnings are imported into all declared packages. However the uninitialized, void, once and numeric warning categories are explicitly excluded, as are any warnings categories added to Perl after version 5.14.

Perl 5.14 features, including the state and say keywords, and sane Unicode string handling are imported into all declared packages.

Extending Moops via parser traits

For more complex needs, you can create a trait which will be applied to Moops::Parser.

Parser traits might want to override:

The keywords class method, which returns the list of keywords the parser can handle.

The class_for_keyword object method, which returns the name of a subclass of Moops::Keyword which will be used for translating the result of parsing the keyword into a string using Perl's built-in syntax.

Hopefully you'll be able to avoid overriding the parse method itself, as it has a slightly messy API.

Your class_for_keyword subclass can either be a direct subclass of Moops::Keyword, or of Moops::Keyword::Class or Moops::Keyword::Role.

The keyword subclass might want to override:

The known_relationships class method, which returns a list of valid inter-package relationships such as extends and using for the current keyword.

The qualify_relationship class method, which, when given the name of an inter-package relationship, indicates whether it should be subjected to package qualification rules (like extends and with are, but using is not).

The version_relationship class method, which, when given the name of an inter-package relationship, indicates whether it should accept a version number.

The generate_package_setup object method which returns a list of strings to inject into the package.

The arguments_for_function_parameters object method which is used by the default generate_package_setup method to set up the arguments to be passed to Function::Parameters.

The check_prerequisites method which performs certain pre-flight checks and may throw an exception.

Hopefully you'll be able to avoid overriding the generate_code method.