The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

MooseX::OmniTrigger -- Provide Moose attributes with recursion-proof triggers that fire on any init, set, or clear operation.

VERSION

Version 0.01

SYNOPSIS

    { package MyClass;

        use Moose;
        use MooseX::OmniTrigger;

        has foo => (is => 'rw', isa => 'Str', default => 'FRELL',                  omnitrigger => \&_callback);
        has bar => (is => 'rw', isa => 'Str',                     lazy_build => 1, omnitrigger => \&_callback);

        has baz => (is => 'rw', isa => 'Str', omnitrigger => sub { $_[0]->baz("$_[2][0]!!!") });

        sub _callback {

            my ($self, $attr_name, $new, $old) = (shift, @_);

            warn("attribute $attr_name has been ", @$new ? 'set' : 'cleared');

            warn('   oldval: ', @$old ? $old->[0] // 'UNDEF' : 'NOVAL');
            warn('   newval: ', @$new ? $new->[0] // 'UNDEF' : 'NOVAL');
        }

        sub _build_bar { 'DREN' }
    }

    my $obj = MyClass->new;

    # attribute 'foo' has been set
    #    oldval: NOVAL
    #    newval: FRELL

    say $obj->bar; # DREN

    # attribute 'bar' has been set
    #    oldval: NOVAL
    #    newval: DREN

    $obj->clear_bar;

    # attribute 'bar' has been cleared
    #    oldval: DREN
    #    newval: NOVAL

    $obj->baz('YOTZ');

    say $obj->baz; # YOTZ!!!

DESCRIPTION

Sometimes you want to know when your attributes' values change. No matter when! No matter how!

MooseX::OmniTrigger is an effort to provide Moose attributes with triggers that may to some folks behave more DWIMmily than standard Moose triggers, working around the documented feature/bug/caveat, "Triggers will only fire when you assign to the attribute, either in the constructor, or using the writer. Default and built values will not cause the trigger to be fired."

An omnitrigger fires any time its attribute's value is initialized, set, or cleared. This includes initialization with default and built values, lazy or no, and sets via native type accessors.

The callback is given as a subref, and receives four arguments: the object, the attribute name, the new value, and the old value. The new and old values are given as array refs. An empty array indicates *no* value -- the slot is uninitialized or has been cleared. Otherwise, the value will be the first (and only) array element.

Omnitriggers are recursion-proof. Firings beyond the first of a particular omnitrigger in the same call stack are quietly prevented.

CAVEATS

For application to roles, this module won't work as synopsized for any Moose older than version 1.9900, owing to the fact that roles back then didn't have an attribute metaclass. If you want to use omnitriggers in role attributes for an old Moose, supply the attribute trait explicitly:

{ package MyRole;

    use Moose::Role;
    use MooseX::OmniTrigger;

    has foo => (traits => [qw(OmniTrigger)], is => 'rw', isa => 'Str', omnitrigger => sub { ... });
}

AUTHOR

Todd Lorenz <trlorenz@hotmail.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by Todd Lorenz.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.