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: moose@perl.org
Subject: Re: MooseX::OmniTrigger
On Mon, Dec 19, 2011 at 2:02 PM, Todd Lorenz <trlor...@hotmail.com> 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: moose@perl.org
Subject: Re: MooseX::OmniTrigger
On Mon, Dec 19, 2011 at 2:02 PM, Todd Lorenz <trlor...@hotmail.com> 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