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,
    handles       => { quux => 'quuux' },
    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" ]

Supported values for is include "ro", "rw", and "bare" like Moose, but also "rwp" and "lazy" like Moo. These are all just shortcuts for defining other options.

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", or is => "lazy" 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.

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.