The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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 of 1

            has field '_name' => (
                    predicate => -public
            );
    
            # ... becomes:
            has '_name' => (
                    ...
                    predicate => 'has_name'
            );
    
    
            has field 'name' => (
                    predicate => -hidden
            );
    
            # ... becomes:
            has 'name' => (
                    ...
                    predicate => '_has_name'
            );
  • builder and trigger 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 are ro and rw (as in base Moose). The author considers rw 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 what rwp does.

lazy => 1 shortcut does more or less what lazy 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

MooseX::Extended
MooseX::AttributeShortcuts

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.