NAME
Mite::Manual::Attributes - options for defining attributes with Mite
SYNOPSIS
has myattr => (
alias => [ 'my_attr' ],
is => 'bare', # or ro/rw/rwp/lazy
init_arg => 'myattr',
required => true,
reader => 'get_myattr',
writer => 'set_myattr',
accessor => 'access_myattr',
clearer => 'clear_myattr',
predicate => 'has_myattr',
lvalue => 'myattr',
local_writer => 'locally_set_myattr',
# default => sub { shift->_build_myattr },
builder => '_build_myattr',
lazy => false,
isa => 'Object',
coerce => false,
clone => false,
locked => false,
handles => { quux => 'quuux' },
handles_via => [ 'Blessed' ],
trigger => '_trigger_myattr',
);
Shortcut for a lazy builder:
has myattr => sub { ... };
Shortcut for a simple default:
has myattr => "some value";
MANUAL
Like has
in Moose, this declares an attribute.
Multiple attributes can be defined using an arrayref.
# Defines get_foo, get_bar, set_foo, and set_bar.
#
has [ 'foo', 'bar' ] => (
isa => 'Str',
reader => 1,
writer => 1,
);
Extending attributes
Like in Moose, you can use a plus sign to modify an attribute definition from a role or parent class:
has '+foo' => (
default => sub { 'new default' },
);
When modifying an attribute, you cannot use the is
option.
Attribute storage
Mite objects are always blessed hashrefs, and the name of the attribute is the hash key used to store the attribute.
It is the maintainer of Mite's opinion that it is acceptable for an object method to directly access its own attributes this way, but not attributes defined in roles, parent classes, etc. Bypassing accessors will cause type checks, lazy defaults, triggers, etc to be ignored, so should be done with caution.
Attribute options
The following options are supported. (Expected types for the value of each option are also provided. A MethodName is any valid Perl sub name; a MethodNameTemplate may also contain "%s" as a placeholder; One means the literal string "1". Other type constraints are self-explanatory.)
is
Enum[ "ro", "rw", "bare", "rwp", "lazy", "locked" ]
These are all just shortcuts for defining other options.
Supported values for is
include "ro", "rw", and "bare" like Moose, but also "rwp" and "lazy" like Moo. Lastly "locked" is an alias for "ro", but also sets the locked
option to true.
The default is is => 'bare'
.
reader
MethodNameTemplate | One | Undef
The name of the attribute reader method to generate. If set to "1", will generate a reader called "get_foo" if your attribute is called "foo" and "_get__foo" if your attribute is called "_foo".
If your attribute is defined as is => "ro"
, is => "rwp"
, is => "lazy"
, or is => "locked"
, then reader
defaults to $name
.
If your reader contains "%s" this will be replaced by the name of the attribute. This allows:
# readers called "fetch_foo" and "fetch_bar"
has [ 'foo', 'bar' ] => (
required => true,
reader => 'fetch_%s',
);
writer
MethodNameTemplate | One | Undef
The name of the attribute writer method to generate. If set to "1", will generate a writer called "set_foo" if your attribute is called "foo" and "_set__foo" if your attribute is called "_foo".
If your attribute is defined as is => "rwp"
, then writer
defaults to "_set_$name"
.
If your writer contains "%s" this will be replaced by the name of the attribute.
Mite provides a similar feature to MooseX::Attribute::Chained, so writer methods return $self
, allowing them to be chained:
$object->set_bar( 42 )->set_baz( 99 );
accessor
MethodNameTemplate | One | Undef
The name of the dual-purpose attribute reader/writer method to generate. If set to "1", will generate a reader called "foo" if your attribute is called "foo" and "_foo" if your attribute is called "_foo".
If your attribute is defined as is => "rw"
, then accessor
defaults to $name
.
If your accessor contains "%s" this will be replaced by the name of the attribute.
Mite provides a similar feature to MooseX::Attribute::Chained, so accessor methods called as writers return $self
, allowing them to be chained:
$object->bar( 42 )->baz( 99 );
clearer
MethodNameTemplate | One | Undef
The name of the attribute clearer method to generate. If set to "1", will generate a clearer called "clear_foo" if your attribute is called "foo" and "_clear__foo" if your attribute is called "_foo".
If your clearer contains "%s" this will be replaced by the name of the attribute.
Mite provides a similar feature to MooseX::Attribute::Chained, so clearer methods return $self
, allowing them to be chained:
$object->clear_foo->clear_bar->clear_baz;
predicate
MethodNameTemplate | One | Undef
The name of the attribute predicate method to generate. If set to "1", will generate a predicate called "has_foo" if your attribute is called "foo" and "_has__foo" if your attribute is called "_foo".
If your predicate contains "%s" this will be replaced by the name of the attribute.
lvalue
MethodNameTemplate | One | Undef
The name of the dual-purpose lvalue reader/writer method to generate. If set to "1", will generate a reader called "foo" if your attribute is called "foo" and "_foo" if your attribute is called "_foo".
If your accessor contains "%s" this will be replaced by the name of the attribute.
lvalue accessors are used like this:
my $object = MyClass->new( myattr => 99 );
say $object->myattr; # ==> 99
$object->myattr = 66; # set new value
say $object->myattr; # ==> 66
An attribute cannot have an lvalue accessor if it has a lazy builder/default, uses a type contraint or coercions, has a trigger, or uses weak_ref.
This is roughly (but not exactly) the same functionality as MooseX::LvalueAttribute.
local_writer
MethodNameTemplate | One | Undef
The name of the dynamically scoped writer method to generate. These work like this:
my $object = Your::Project::SomeClass->new( foo => 99 );
say $object->foo; # ==> 99
do {
my $guard = $object->locally_set_foo( 66 );
say $object->foo; # ==> 66
};
say $object->foo; # ==> 99
When the $guard
goes out of scope, the old value will be restored. The $guard
object also has three methods: restore
to restore the old value immediately, dismiss
to dismiss the old value and keep the new value, and peek
to peek at the old value.
If the local writer is called with no parameter, it acts as a local clearer.
If set to "1", will generate a local writer called "locally_set_foo" if your attribute is called "foo" and "_locally_set__foo" if your attribute is called "_foo".
If your local writer contains "%s" this will be replaced by the name of the attribute.
This is vaguely inspired by MooseX::LocalAttribute.
skip_argc_check
Bool
Mite includes sanity checks on the number of arguments passed to accessors. For example, if you call a reader and pass it a value as if it were a writer, it will die with a message explaining the problem.
You can set skip_argc_check
to true to skip these checks for an attribute's accessors, making it run a little faster. If Class::XSAccessor is installed and being used, these checks will still be done in XS mode, so skip_argc_check
shouldn't be used as a way to allow the wrong number of arguments to be passed to a function, just as an optimization.
handles
Map[ MethodNameTemplate, MethodName ] | Int
Delegated methods. Currying and native traits are not supported.
If your handles hashref keys contain "%s", they will be replaced by the name of the attribute.
# $this->user_agent_get is a shortcut for $this->user_agent->get
#
has user_agent => (
required => true,
isa => 'Object',
handles => {
'%s_get' => 'get',
'%s_post' => 'post',
},
);
If the attribute's type constraint is an enumeration, then the shortcuts handles => 1
and handles => 2
are also supported. These are inspired by MooseX::Enumeration and MooX::Enumeration.
In this example, Mite creates methods is_alive
and is_dead
for you:
has status => (
enum => [ 'alive', 'dead' ],
handles => 1,
default => 'alive',
writer => '_set_status',
);
sub kill {
my $self = shift;
croak "Already dead!" if $self->is_dead;
$self->_set_status( 'dead' );
}
In this example, Mite creates size_is_small
, size_is_medium
, and size_is_large
for you.
has size => (
is => 'rw',
isa => 'Enum[ "small", "medium", "large" ]',
handles => 2,
);
Note that if handles
had been 1, then the methods would have just been called is_small
, is_medium
, and is_large
, without the size_
prefix at the start.
handles_via
ArrayRef[Str] | Str
If handles_via
is set, then Mite will use Sub::HandlesVia for dealing with the handles
option instead of trying to deal with it internally. This allows a rich set of delegations to native Perl types like arrayrefs and hashrefs.
has monkeys => (
is => 'bare',
isa => 'ArrayRef[Object]',
handles_via => 'Array',
handles => {
'%s' => 'all',
monkey_count => 'count',
add_monkey => 'push...',
find_monkeys => 'grep',
clear_monkeys => 'clear...',
},
);
...
$zoo->clear_monkeys();
$zoo->add_monkey( $bobo );
$zoo->add_monkey( $momo );
if ( $zoo->monkey_count == 0 ) {
say "No monkeys!";
}
for my $monkey ( $zoo->monkeys ) {
say $monkey->name;
}
Most Sub::HandlesVia features should be supported.
init_arg
NonEmptyStr | Undef
The parameter expected to be passed to the constructor to initialize this attribute. May be undef if the attribute should not be intitialized in the constructor.
Defaults to the attribute's name.
If your init_arg contains "%s" this will be replaced by the name of the attribute.
required
Bool
Indicates whether the attribute is required in the constructor. If the attribute has a non-lazy default, this is ignored.
alias
ArrayRef[ MethodNameTemplate ]
A list of aliases for the attibutes. If the attribute has an init_arg (including a default one), this provides alternative initialization arguments. If the attribute is => "rw"
, then these aliases are aliases for the accessor; otherwise they are aliases for the reader.
The strings can contain "%s" which will be replaced by the attribute name, allowing this to work:
has [ 'foo', 'bar' ] => (
is => 'ro',
alias => [ 'get_%s' ],
);
If you try to create aliases but don't have a reader or accessor, then as a last resort the alias will be an alias for the writer.
# foo can be set using `set_foo` or `whatever`
#
has foo => (
is => 'bare',
writer => 1,
alias => 'whatever', # Mite will implicitly do Str -> ArrayRef here
);
Aliases are not natively supported by Moose, but this feature is analagous to MooseX::Aliases.
isa
Str | Ref
A string type name from Types::Standard, Types::Common::String, or Types::Common::Numeric, or a blessed Type::Tiny object. Alternatively, any reference which to_TypeTiny
from Types::TypeTiny is able to coerce to a blessed Type::Tiny object, or any blessed object that provides a to_TypeTiny
method which returns a Type::Tiny object. If using a blessed object, you'll be introducing a dependency for your project on whatever type constraint library you're using, so prefer string type contraint names.
Any string supported by Type::Utils dwim_type
is supported, so things like "Int | Enum['small', 'medium', 'large']"
should work!
If you need custom types, you can add something like this to your .mite/config:
types: Your::Project::Types
The module Your::Project::Types
would be a type library constructed with Type::Library. It should just contain type constraints and coercions which can be inlined, and none of your classes should load it directly (just rely on Mite to load it). This way you can use custom types in your project and your project will not have a dependency on Type::Library.
Type::Library::Compiler is an alternative way to create a zero-dependency type library which Mite is able to use.
does
Str | Ref
Same as isa
, but if the type name is unrecognized, assumes it was a role name instead of assuming it was a class name.
enum
ArrayRef[ NonEmptyStr ]
Shortcut for isa => 'Enum["foo","bar","baz"]'
.
This feature is inspired by MooseX::Enumeration and MooX::Enumeration.
coerce
Bool
Indicates that the attribute should attempt to coerce values to fit the type constraint.
trigger
MethodNameTemplate | One | CodeRef
If set to a string, is the name of a method to call whenever a new attribute value is set. This is not called when an attribute is defaulted. (However, see the default_does_trigger
option.) If set to "1", will assume a trigger called "_trigger_foo" if your attribute is called "foo" and "_trigger__foo" if your attribute is called "_foo".
If set to a coderef, acts like it was set to "1" but installs the coderef into your class with that name.
If your trigger method name contains "%s" this will be replaced by the name of the attribute.
weak_ref
Bool
Indicates that the attribute should weaken its reference to the attribute value.
locked
Bool
If an attribute is locked and its value is set to an unblessed arrayref or hashref, then the array or hash will be marked as read-only. This means that if you've defined an attribute like this:
has numbers => (
is => ro,
isa => 'ArrayRef',
locked => true,
default => [],
);
People will not be able to do push( @{ $object->numbers }, 1 )
, and it will throw an exception!
To allow people to push to the array:
has numbers => (
is => ro,
isa => 'ArrayRef',
locked => true,
default => [],
handles_via => 'Array',
handles => { add_number => 'push', remove_number => 'pop' },
);
Then they can use $object->add_number( 1 )
.
Defaults to false, unless is => "locked"
.
clone
MethodNameTemplate | One | CodeRef | Undef
Stolen from MooseX::Extended. Set to "1" to make a deep clone of the attribute value using Storable whenever the attribute is read or written. If set to a method name or coderef, then the method will be called as $self->$method( $attrname, $value )
and is expected to return a clone of the value.
has start_date => (
is => ro,
isa => 'InstanceOf["DateTime"]',
required => true,
clone => sub {
my ( $self, $attrname, $value ) = @_;
return $value->clone;
},
);
This option can be fine-tuned by setting the clone_on_read
and clone_on_write
boolean options. By default, attributes which have a clone method set will clone both incoming and outgoing references.
has start_date => (
is => ro,
isa => 'InstanceOf["DateTime"]',
required => true,
clone => sub {
my ( $self, $attrname, $value ) = @_;
return $value->clone;
},
clone_on_write => true,
clone_on_read => false,
);
default
CodeRef | ScalarRef | Str | Undef | Dict[] | Tuple[]
A default value for the attribute, or a coderef called as a method to generate that default value.
Unlike Moose, you can alternatively include an inline string of Perl code as a ScalarRef:
has list => (
is => 'ro',
isa => 'ArrayRef',
default => \ '[]',
);
This has performance benefits over using a coderef as it avoids the overhead of a sub call.
An empty arrayref or empty hashref is also allowed as a default.
builder
MethodNameTemplate | One | CodeRef
If set to a string, is the name of a method to call to build the default attribute value. If set to "1", will assume a builder called "_build_foo" if your attribute is called "foo" and "_build__foo" if your attribute is called "_foo".
If you used is => "lazy"
, this will default to "1".
If set to a coderef, acts like it was set to "1" but installs the coderef into your class with that name.
If your builder method name contains "%s" this will be replaced by the name of the attribute.
lazy
Bool
Indicates that the default should be set lazily. Defaults to false unless you used is => "lazy"
.
An eager (non-lazy) default or builder is applied by the constructor when the object is constructed. A lazy default or builder is applied by the reader/accessor if and when the attribute is accessed.
default_is_trusted
Bool
Defaults to false (which is how Moose and Moo work), but if set to true, Mite will skip type checks and coercions when the attribute is set by the default or builder. If you trust that the default is always going to be a valid value, then it may make sense to only do type checks and coercions when a value is passed in by your caller. This may make your accessors and constructor a little faster.
default_does_trigger
Bool
Defaults to false (which is how Moose and Moo work), but if set to true, Mite will also call your trigger if the attribute's default is used. Normally triggers are only called when an attribute is set explicitly.
documentation
Any
This option is ignored, but you can set it to a documentation string for your attribute.
has name => (
is => 'rwp',
isa => 'Str',
documentation => 'First name and surname',
);
How to...
is => 'wo'
(write-only attributes)
There are use cases for write-only attributes. For example:
package Your::Project::ApiClient;
use Your::Project::Mite;
has user_agent => (
is => 'wo',
isa => 'Object',
handles => [ 'get', 'post' ],
builder => sub { require HTTP::Tiny; HTTP::Tiny->new },
);
...
$client->user_agent( HTTP::Tiny::WithLogging->new );
$client->post( ... );
$client->user_agent(); # dies, because it's a writer
However, Mite doesn't support is => 'wo'
. (Neither do Moose, Mouse, or Moo!) So how can this be accomplished?
This will provide a writer method called user_agent
:
has user_agent => (
writer => '%s',
isa => 'Object',
handles => [ 'get', 'post' ],
builder => sub { require HTTP::Tiny; HTTP::Tiny->new },
);
Alternatively, this will provide a writer method called set_user_agent
:
has user_agent => (
writer => 1,
isa => 'Object',
handles => [ 'get', 'post' ],
builder => sub { require HTTP::Tiny; HTTP::Tiny->new },
);
BUGS
Please report any bugs to https://github.com/tobyink/p5-mite/issues.
AUTHOR
Michael G Schwern <mschwern@cpan.org>.
Toby Inkster <tobyink@cpan.org>.
COPYRIGHT AND LICENCE
This software is copyright (c) 2011-2014 by Michael G Schwern.
This software is copyright (c) 2022 by Toby Inkster.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.