Re: MooseX::OmniTrigger

[email protected] ("Todd Lorenz")
Newsgroups perl.moose
Message-ID <[email protected]>
Hello, Jason, thanks for the feedback!

Omnitrigger.pm is intended as an alternative to standard Moose triggers, 
providing trigger functionality more in line with (what I suspect are) most 
folk's expectations.

Aside from the order and type of arguments provided to the callback, 
omnitriggers and standard triggers have the same interface:

    has foo => (is => 'rw', isa => 'Str', trigger => sub { die('POW!') });

    has bar => (is => 'rw', isa => 'Str', omnitrigger => sub { 
die('POW!') });

Unlike standard triggers, omnitriggers will fire on any initialization, 
setting, or clearing of the attribute value, and they're protected from 
recursion. (And they eliminate a couple of very esoteric bugs I found with 
standard triggers.)

I'd come across Observable in my searches, but missed Listenable; though it 
seems the two are fairly similar. They're both roles implementing the 
observer pattern -- they're both intended to detect calls to methods in the 
consuming class in a generic way. What they're not intended to do is detect 
*any* change of an *attribute's* value -- they can't, because attributes' 
values aren't always changed directly via methods in the consuming class, 
particularly during construction, cloning, rebless fixup, and lazy 
population, and in inlined stuff.

Omnitriggers, on the other hand, like standard triggers, do their 
"listening" deeper in the bowels of things to intercept attribute changes as 
close to the Instance interface as possible, in as few places as possible. A 
(contrived) example may help:

#===================================================================================================

{ package OmniTrigClass;

    use Moose;
    use MooseX::OmniTrigger;

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

    has baz => (is => 'rw', isa => 'Str', accessor => 'access_baz', reader 
=> 'read_baz', writer => 'write_baz', clearer => 'clear_baz', omnitrigger => 
sub {

        my ($self) = shift;

        $self->_callback(@_);

        $self->write_baz('RECURSE, DAMN YOU');
    });

    sub _callback { say("OMNITRIGGERED FOR $_[1]") }
}

my $omnitriggered = OmniTrigClass->new;
# OMNITRIGGERED FOR foo -- default got set

$omnitriggered->bar;
# OMNITRIGGERED FOR bar -- lazy default got set

$omnitriggered->meta->get_attribute('foo')->set_value($omnitriggered, 
'FOO!!!');
# OMNITRIGGERED FOR foo -- set through the attribute interface

$omnitriggered->write_baz('BAZ???');
# OMNITRIGGERED FOR baz

say $omnitriggered->read_baz;
# RECURSE, DAMN YOU

#===================================================================================================

{ package ObservableClass;

    use Moose;

    has foo => (is => 'rw', isa => 'Str', default => 'FOO');
    has bar => (is => 'rw', isa => 'Str', default => 'BAR', lazy => 1);

    has baz => (is => 'rw', isa => 'Str', accessor => 'access_baz', reader 
=> 'read_baz', writer => 'write_baz', clearer => 'clear_baz');

    # WE HAVE TO BE EXPLICIT ABOUT WHAT WE'RE OBSERVING. THIS LIST COULD GET 
BIG.
    with 'MooseX::Observer::Role::Observable' => {notify_after => [qw(

        foo
        bar
        access_baz
        read_baz
        write_baz
        clear_baz
    )]};
}

{ package ObserverClass;

    use Moose;
        with 'MooseX::Observer::Role::Observer';

    sub update {

        say("OBSERVED $_[3]");

        # WE HAVE TO MAINTAIN OUR OWN "DISPATCHER" HERE.
        $_[1]->write_baz('RECURSE, DAMN YOU') if $_[3] =~ 
/^(?:access_baz|read_baz|write_baz|clear_baz)$/;
    }
}

my $observable = ObservableClass->new;
# <NOTHING>

$observable->add_observer(ObserverClass->new);

$observable->bar;
# <NOTHING>

$observable->meta->get_attribute('foo')->set_value($observable, 'FOO!!!');
# <NOTHING>

$observable->write_baz('BAZ???');
# OBSERVED write_baz
# OBSERVED write_baz
# OBSERVED write_baz
# ...INIFINITE RECURSION

#===================================================================================================







-----Original Message----- 
From: Jason Galea
Sent: Sunday, December 18, 2011 9:36 PM
To: Todd Lorenz
Cc: [email protected]
Subject: Re: MooseX::OmniTrigger

On Mon, Dec 19, 2011 at 2:02 PM, Todd Lorenz <[email protected]> wrote:

>
> So far as I’ve been able to find, there currently aren’t any other modules
> like this one, so I’d like to make it available on the CPAN. But first I’d
> like your feedback, if you’ve got the time to give it.
>
> https://github.com/trlorenz/MooseX-OmniTrigger
>

Hi Todd,

have you seen these?

https://metacpan.org/search?q=moose+observable

MooseX::Observer::Role::Observable
MooseX::Role::Listenable

Observable looks like it might be close, it's brand new too..

are they similar? or what are the differences? (alway good to explain in
your docs)

cheers,

J



-- 

Jason Galea
Web Developer

Ph 07 40556926
Mob 04 12345 534
www.eightdegrees.com.au

-----Original Message----- 
From: Jason Galea
Sent: Sunday, December 18, 2011 9:36 PM
To: Todd Lorenz
Cc: [email protected]
Subject: Re: MooseX::OmniTrigger

On Mon, Dec 19, 2011 at 2:02 PM, Todd Lorenz <[email protected]> wrote:

>
> So far as I’ve been able to find, there currently aren’t any other modules
> like this one, so I’d like to make it available on the CPAN. But first I’d
> like your feedback, if you’ve got the time to give it.
>
> https://github.com/trlorenz/MooseX-OmniTrigger
>

Hi Todd,

have you seen these?

https://metacpan.org/search?q=moose+observable

MooseX::Observer::Role::Observable
MooseX::Role::Listenable

Observable looks like it might be close, it's brand new too..

are they similar? or what are the differences? (alway good to explain in
your docs)

cheers,

J



-- 

Jason Galea
Web Developer

Ph 07 40556926
Mob 04 12345 534
www.eightdegrees.com.au
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.