NAME
Mooish::AttributeBuilder - build Mooish attribute definitions with less boilerplate
SYNOPSIS
use Moo; # or Moose or Mouse or ...
use Mooish::AttributeBuilder;
# this attribute is required in the constructor
has param 'param_name';
has param 'param_name' => (
...
);
# this attribute is optional in the constructor
has option 'option_name';
has option 'option_name' => (
...
);
# this attribute is not available in the constructor
has field 'field_name';
has field 'field_name' => (
...
);
# this extends parent attribute, much like: has '+name_to_extend'
has extended 'name_to_extend' => (
...
);
DESCRIPTION
This module implements shortcuts and helpers for has
keyword in Moose family of modules.
The shortcuts provided are similar to those in MooseX::Extended or MooX::Keyword::Field, but they don't depend on specific OO system. Instead, those shortcuts are just modifying option lists which are then passed to has
. This way you can use the module with any OO system which supports the Moose set of has
parameters.
EXPORTED FUNCTIONS
All functions are exported by default.
field
has field $field_name => %more_options;
This function produces a property that cannot be passed to the constructor:
has $field_name => (
is => 'ro',
init_arg => undef,
%more_options
);
param
has param $param_name => %more_options;
This function produces a property that is required in the constructor:
has $param_name => (
is => 'ro',
required => 1,
%more_options
);
option
has option $option_name => %more_options;
This function produces a property that is optional in the constructor and has a predicate:
has $option_name => (
is => 'ro',
required => 0,
predicate => "has_${option_name}",
%more_options
);
extended
has extended $name_to_extend => %more_options;
This function does not introduce any extra hash keys, but adds a plus sign before the name:
has "+${name_to_extend}" => (
%more_options
);
SHORTCUTS
The %more_options
hash can contain some shortcuts that will be expanded by "option", "param", "field" or "extended" functions.
method name shortcuts
The following values:
1
-public
-hidden
... can be passed to the following options, producing standard method names with given prefixes:
reader: get_
writer: set_
predicate: has_
clearer: clear_
builder: _build_
trigger: _trigger_
The naming rules are as follows:
Properties starting with an underscore produce hidden methods when passed
1
(starting with underscore as well)has field '_name' => ( reader => 1 ); # ... becomes: has '_name' => ( ... reader => '_get_name' );
Properties not starting with an underscore produce public methods when passed
1
(not starting with underscore)has field 'name' => ( writer => 1 ); # ... becomes: has 'name' => ( ... writer => 'set_name' );
Visibility can be forced by passing
-public
or-hidden
instead of1
has field '_name' => ( predicate => -public ); # ... becomes: has '_name' => ( ... predicate => 'has_name' ); has field 'name' => ( predicate => -hidden ); # ... becomes: has 'name' => ( ... predicate => '_has_name' );
builder
andtrigger
are hidden by default. The only way to have them not start with an underscore (other than passing the name explicitly) is to pass-public
.These two options also don't change the name based on the leading underscore in property's name. Builders for
property
and_property
will by default both be_build_property
.
lazy + default
lazy => sub { return 'default value' }
... will be expanded to:
lazy => 1,
default => sub { return 'default value' }
Note: this only works for anonymous subroutines. Will not be expanded if explicit default / builder was passed (but does not take superclass default / builder into account).
lazy + builder
lazy => 'builder_name'
... will be expanded to:
lazy => 1,
builder => 'builder_name'
Note: passing 1
will work as described in "method name shortcuts". Will not be expanded if explicit default / builder was passed (but does not take superclass default / builder into account).
isa + coerce
coerce => Types::Standard::Int
... will be expanded to:
isa => Types::Standard::Int,
coerce => 1
As long as it is a blessed reference (object).
builder / default + required
Having a builder
or a default
will automatically remove required
from the option list.
# will no longer be required in the constructor
has param 'optional' => (
default => undef,
);
init_arg
init_arg
can use the same shortcuts as described in "method name shortcuts".
This can be useful to turn _name
into name
in the constructor with the help of -public
:
# no underscore in the constructor
has param '_name' => (
init_arg => -public,
);
trigger
In addition to shortcuts described in "method name shortcuts", trigger
can now be passed both as a anon sub (like default
) or as a package sub name (like builder
).
use parameter value without expanding
In case you want to fall back to default behavior of some has
parameters, you can prepend their names with a hyphen:
# 'builder' will be expanded, but 'writer' won't
has field 'auto' => (
builder => 1,
-writer => 1,
);
CUSTOM SHORTCUTS
It is possible to introduce custom shortcuts by calling add_shortcut
:
use Mooish::AttributeBuilder;
use Data::Dumper;
Mooish::AttributeBuilder::add_shortcut(sub {
my ($name, %args) = @_;
print Dumper(\%args);
return %args;
});
Each new option filter must be an anonymous subroutine that accepts ($name, %args)
and returns new value for %args
. $name
will contain full name of the attribute (which can be an array reference), while %args
are attribute options plus a "_type"
key, which is the name of the helper, e.g. "param"
.
Custom shortcuts are called before built in shortcuts described in "SHORTCUTS", in order of declaration. Make sure not to call add_shortcut
repeatedly with the same sub, as the module will not run any checks to prevent duplication.
Example, making fields rw
by default:
Mooish::AttributeBuilder::add_shortcut(sub {
my ($name, %args) = @_;
if ($args{_type} eq 'field') {
$args{is} = 'rw';
}
return %args;
});
For module authors
If you want to use Mooish::AttributeBuilder in your module, these custom filters are undesirable. You want to be sure your module works regardless of environment. In CPAN modules the module should be imported with the -standard
flag, which will disable all custom behavior.
use Mooish::AttributeBuilder -standard;
This flag was added in Mooish::AttributeBuilder version 1.001
.
CAVEATS
- Partial support for multiple attributes per 'has'
-
The module lets you write for example:
has field ['f1', 'f2'] => %params; has extended ['f3', 'f4'] => %params;
These constructions work, but since we operate on a single
has
here,%params
can't contain shortcuts which produces method names - that would lead to multiple fields using same methods. The module will die with a helpful error message if it encounters something that it can't handle properly.If you encounter this problem, you might want to "use parameter value without expanding" to fall back to regular shortcut modules (like MooseX::AttributeShortcuts). This module will not automatically change its behavior to do so, so it does not surprise you.
- All attributes produced are 'ro' by default
-
Since the module does not depend on specific OO implementation, the only common
is =>
options arero
andrw
(as in base Moose). The author considersrw
to be a bad idea most of the time. Having one method for reading and writing can lead to bugs that are hard to spot.Other than that:
writer => -hidden
shortcut does more or less whatrwp
does.lazy => 1
shortcut does more or less whatlazy
does. - Partial MooseX::AttributeShortcuts compatibility
-
The module implements many of the shortcuts from MooseX::AttributeShortcuts, but does not aim to have 100% compatibility. Some details in overlapping functionality may differ.
SEE ALSO
AUTHOR
Bartosz Jarzyna <bbrtj.pro@gmail.com>
COPYRIGHT AND LICENSE
Copyright (C) 2022 by Bartosz Jarzyna
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.