…
my $signal = new EV::SignalSlot;
…
$signal->connect($another_signal);
$signal->connect(\&some_sub);
$signal->connect($object, 'method_name');
…
$signal->emit(@args);
…
my $timer = EV::timer_ns(0, 0, \&some_sub);
$timer->data(\@args);
$timer->feed_event(EV::TIMER);
…
sub some_sub {
my ($watcher, $revents) = @_;
my $arr_ref = $watcher->data();
do_something(@{ $arr_ref });
…
}
package EV::SignalSlot;
use strict;
use warnings;
use EV;
use Scalar::Util;
#------------------------------------------------------------------------------#
sub new {
my $class = shift;
return bless([] => $class);
}
#------------------------------------------------------------------------------#
sub connect {
my $self = shift;
my ($slot, $tag);
if (@_ == 1 && ref $_[0] eq 'EV::SignalSlot') {
my $signal = shift;
$slot = sub {
my $args = $_[0]->data();
$signal->emit(@{ $args });
return;
};
$tag = "$signal";
}
elsif (@_ == 1 && ref $_[0] eq 'CODE') {
my $coderef = shift;
$slot = sub {
my $args = $_[0]->data();
$coderef->(@{ $args });
return;
};
$tag = "$coderef";
}
elsif (@_ == 2) {
my ($object, $method_name) = @_;
if (Scalar::Util::blessed($object) && (my $method = $object->can($method_name))) {
$slot = sub {
my $args = $_[0]->data();
$method->($object, @{ $args });
return;
};
$tag = "$object:$method_name";
}
else {
return;
}
}
else {
return;
}
unshift @{ $self }, { $tag => EV::timer_ns(0, 0, $slot) };
return;
}
#------------------------------------------------------------------------------#
sub disconnect {
my $self = shift;
my $tag = join ':', @_;
@{ $self } = grep { my ($k, $v) = %{ $_ }; $k ne $tag } @{ $self };
return;
}
#------------------------------------------------------------------------------#
sub emit {
my $self = shift;
foreach my $connected (@{ $self }) {
my (undef, $slot) = %{ $connected };
$slot->data(\@_);
$slot->feed_event(EV::TIMER);
}
}
#------------------------------------------------------------------------------#
sub DESTROY { }
#------------------------------------------------------------------------------#
1;
__END__
#!/usr/bin/perl
$| = 1;
use strict;
use warnings;
use EV;
use EV::SignalSlot;
#------------------------------------------------------------------------------#
package MyCounter;
sub new {
my $class = shift;
my $self = {
changed => new EV::SignalSlot,
val => shift || 0,
};
return bless($self => $class);
}
sub incr {
my $self = shift;
my $val = shift || 1;
$self->{val} += $val;
$self->{changed}->emit($val);
}
sub decr {
my $self = shift;
my $val = shift || 1;
$self->{val} -= $val;
$self->{changed}->emit($val);
}
sub get_val {
return $_[0]->{val};
}
sub get_signal {
return $_[0]->{changed};
}
#------------------------------------------------------------------------------#
package main;
my $counterA = new MyCounter;
my $counterB = new MyCounter;
my $counterC = new MyCounter;
my $counterD = new MyCounter;
$counterA->get_signal()->connect($counterB->get_signal());
$counterA->get_signal()->connect($counterC, 'decr');
$counterB->get_signal()->connect($counterD, 'decr');
$counterC->get_signal()->connect(\&dump);
my $timer1 = EV::timer(1, 0.5, sub{ $counterA->incr(10) });
my $timer2 = EV::timer(3, 0, \&swap);
my $timer3 = EV::timer(7, 0, sub{ EV::break() });
EV::run();
#------------------------------------------------------------------------------#
sub swap {
$counterA->get_signal()->disconnect($counterC, 'decr');
$counterB->get_signal()->disconnect($counterD, 'decr');
$counterA->get_signal()->connect($counterC, 'incr');
}
sub dump {
print "A=", $counterA->get_val(), "\t",
"B=", $counterB->get_val(), "\t",
"C=", $counterC->get_val(), "\t",
"D=", $counterD->get_val(), "\t[iteration=", EV::loop_count(), "]\n";
}
$ ./test_ss.pl
A=10 B=0 C=-10 D=-10 [iteration=1]
A=20 B=0 C=-20 D=-20 [iteration=2]
A=30 B=0 C=-30 D=-30 [iteration=3]
A=40 B=0 C=-40 D=-40 [iteration=4]
A=50 B=0 C=-50 D=-50 [iteration=5]
A=60 B=0 C=-40 D=-50 [iteration=6]
A=70 B=0 C=-30 D=-50 [iteration=7]
A=80 B=0 C=-20 D=-50 [iteration=8]
A=90 B=0 C=-10 D=-50 [iteration=9]
A=100 B=0 C=0 D=-50 [iteration=10]
A=110 B=0 C=10 D=-50 [iteration=11]
A=120 B=0 C=20 D=-50 [iteration=12]
A=130 B=0 C=30 D=-50 [iteration=13]
Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.
комментарии (3)