Skip to content

Instantly share code, notes, and snippets.

Created April 28, 2012 21:02
Show Gist options
  • Save anonymous/2521990 to your computer and use it in GitHub Desktop.
Save anonymous/2521990 to your computer and use it in GitHub Desktop.
use v6;
role Signal {
has @.slots; # a nice list of callbacks (that are methods)
multi method connect(Any:D $sender, Any:D $rcpt, Method $method){
@.slots.push([$sender, self, $rcpt, $method]);
}
multi method connect(Any:D $rcpt, Method $method){
@.slots.push([Mu, self, $rcpt, $method]);
}
multi method connect(Any:D $sender, Method $signal, Routine $slot){
@.slots.push([$sender, $signal, Mu, $slot]);
}
multi method connect(Routine $r){
@.slots.push([Mu, self, Mu, $r]);
}
method disconnect(Mu $sender, Mu $rcpt, Routine $method){
my $offset = 0;
for @.slots -> $slot {
@.slots.splice($offset, 1) if $slot == [$sender, self, $rcpt, $method];
$offset++;
}
}
}
multi trait_mod:<is>(Routine $_signal, :$signal!){
$_signal does Signal;
$_signal.slots; # WORKAROUND RT112666
$_signal.wrap(sub (*@args) {
for $_signal.slots -> [$sender, $signal, $receiver, $slot] {
@args.shift;
if $slot ~~ Method {
@args.unshift($receiver);
}
$slot(|@args);
}
});
}
#multi trait_mod:<is>(Method $_signal: $signal!){
# $_signal does Signal;
#
# $_signal.slots; # WORKAROUNG RT112666
#
# $_signal.warp(sub (*@args) {
# for $_signal.slots -> [$sender, $signal, $receiver, $slot] {
# $receiver.$slot(|@args);
# }
# });
#}
multi sub connect(Any:D $sender, Method $signal, Any:D $rcpt, Method $slot){
$signal.connect($sender, $rcpt, $slot);
}
multi sub connect(Signal $signal, Any:D $rcpt, Method $slot){
$signal.connect($rcpt, $slot);
}
multi sub connect(Any:D $sender, Method $signal, Routine $slot){
$signal.connect($sender, $signal, $slot);
}
multi sub connect(Routine $signal, Routine $slot){
$signal.connect($slot);
}
multi disconnect(Any:D $sender, Method $signal, Any:D $receiver, Method $slot){
$signal.disconnect($sender, $receiver, $slot);
}
multi disconnect(Signal $signal, Any:D $receiver, Method $slot){
$signal.disconnect(Mu, $receiver, $slot);
}
multi disconnect(Any:D $sender, Method $signal, Routine $slot){
$signal.disconnect($sender, Mu, $slot);
}
multi disconnect(Routine $signal, Routine $slot){
$signal.disconnect(Mu, Mu, $slot);
}
class Btn {
our method sig_pressed is signal { warn "signal fired without slots" }
our method sig_released is signal { warn "signal fired without slots" }
}
class App {
our method exit { say "App::exit called" }
}
my Btn $btn_exit .= new;
my App $app .= new;
connect($btn_exit, &Btn::sig_pressed, $app, &App::exit);
$btn_exit.sig_pressed; # one slot connected
sub bare_signal_exit is signal {}
connect(&bare_signal_exit, $app, &App::exit);
bare_signal_exit;
sub bare_slot_exit { say "bare_slot_exit called" };
connect(&bare_signal_exit, &bare_slot_exit);
connect($btn_exit, &Btn::sig_released, &bare_slot_exit);
bare_signal_exit;
$btn_exit.sig_released;
say "disconnecting";
disconnect($btn_exit, &Btn::sig_pressed, $app, &App::exit);
disconnect(&bare_signal_exit, $app, &App::exit);
disconnect(&bare_signal_exit, &bare_slot_exit);
disconnect($btn_exit, &Btn::sig_released, &bare_slot_exit);
$btn_exit.sig_pressed;
$btn_exit.sig_released;
bare_signal_exit;
# simple example
class Input {
has Str $.text is rw;
our method sig_changed(Str $s) is signal {};
our method sig_keyup is signal {};
method fake_event_handler() {
$.text = (1..10).pick(5).join;
$.sig_changed($.text);
}
}
class Button {
has Str $.text is rw;
our method sig_pressed is signal {};
our method sig_lowered is signal {};
our method sig_raised is signal {};
method fake_event_handler() { self.sig_pressed }
}
class Person {
has Str $.name is rw;
has Int $.age is rw;
has Int $.sexiness is rw;
our method set_name($name){ $.name = $name }
our method set_age($age){ $.age = $age.Int }
our method set_sexiness($sexiness) { $.sexiness = $sexiness.Int }
our method foo(){};
}
class PersonDialog {
has Person $.person;
has Input $.name;
has Input $.age;
has Input $.sexiness;
has Button $.ok;
method new(){
my Person $person .= new,
my Input $name .= new,
my Input $age .= new,
my Input $sexiness .= new,
my Button $ok .= new(:text('OK'));
my $self = self.bless(*, person => $person, name => $name, age => $age, sexiness => $sexiness, ok => $ok);
connect($name, &Input::sig_changed, $person, &Person::set_name);
connect($age, &Input::sig_changed, $person, &Person::set_age);
connect($sexiness, &Input::sig_changed, $person, &Person::set_sexiness);
connect($ok, &Button::sig_pressed, $self, &PersonDialog::finished);
return $self;
}
our method finished() {
die "ohh no!" unless $.person.name && $.person.age && $.person.sexiness;
say "Person name: {$.person.name}, age: {$.person.age}, sexiness: {$.person.sexiness}";
}
}
my PersonDialog $pd .= new;
.fake_event_handler for $pd.name, $pd.age, $pd.sexiness, $pd.ok;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment