Aion-Emitter

 view release on metacpan or  search on metacpan

lib/Aion/Emitter.pm  view on Meta::CPAN


my $event_isa = HashRef[ArrayRef[Dict[act => StrMatch[qr/^[\w:]+#\w+$/a], line => Option[Nat], nice => Option[Num], remark => Option[Str]]]];

use Aion::Env::Etc INI => (isa => Str, default => 'etc/annotation/listen.ann', key => 'aion.emitter.ini');
use Aion::Env::Etc EVENT => (isa => $event_isa, default => {}, key => 'aion.emitter.event');

# Путь к собранным из аннотаций методам
has ini => (is => 'ro', isa => Str, default => INI);

# Список слушателей
has event => (is => 'ro?!', isa => $event_isa, default => sub {
	my ($self) = @_;
	my %event = %{EVENT()};
	
	if(defined $self->ini and -e $self->ini) {
		open my $f, "<:encoding(UTF-8)", $self->ini or die "Not open ${\$self->ini}";
		while(<$f>) {
			do { close $f; die "${\$self->ini}:$. corrupt!" } unless /^([\w:]+)#(\w*),(\d+)=(?:(-?\d+(?:\.\d+)?)\s+)?([a-z][\w:]*(?:#[\w.:-]+)?)(?:\s+(.*?))??\s*$/ia;
			my ($pkg, $sub, $line, $nice, $evt, $remark) = ($1, $2, $3, $4, $5, $6);
			$sub //= 'listen';
			push @{$event{$evt}}, {
				act => "$pkg#$sub",
				line => $line,
				$nice? (nice => $nice): (),
				$remark ne ''? (remark => $remark): (),
			};
		}
		close $f;
	}

	for my $listens (values %event) {
		@$listens = sort { $a->{nice} <=> $b->{nice} or $a->{act} cmp $b->{act} } @$listens;
	}
	
	\%event
});

# Плерома
has pleroma => (is => 'ro', isa => 'Aion::Pleroma', eon => 1);

# Излучить
sub emit {
	my ($self, $event, $key) = @_;
	
	my $listeners = $self->event->{defined($key)? "${\ref $event}#$key": ref $event};
	return $self unless $listeners;
	
	for my $listener_bag (@$listeners) {
		my ($pkg, $sub) = split /#/, $listener_bag->{act}, 2;
		my $listener = $self->pleroma->get($pkg) // $self->pleroma->autoware($pkg)->resolve($pkg);
		$listener->$sub($event);
	}
	
	$self
}

1;

__END__

=encoding utf-8

=head1 NAME

Aion::Emitter - event dispatcher

=head1 VERSION

0.1.2

=head1 SYNOPSIS

File lib/Event/BallEvent.pm:

	package Event::BallEvent;
	
	use Aion;
	
	has radius => (is => 'rw', isa => Num);
	has weight => (is => 'rw', isa => Num);
	
	1;

File lib/Listener/RadiusListener.pm:

	package Listener::RadiusListener;
	
	use Aion;
	
	#@listen Event::BallEvent
	sub listen {
		my ($self, $event) = @_;
		
		$event->radius(10);
	}
	
	1;

File lib/Listener/WeightListener.pm:

	package Listener::WeightListener;
	
	use Aion;
	
	#@listen Event::BallEvent
	sub listen {
		my ($self, $event) = @_;
		
		$event->weight(12);
	}
	
	#@listen Event::BallEvent#mini „Minimize version”
	sub minimize {
		my ($self, $event) = @_;
		
		$event->weight(3);
	}
	
	1;

File etc/annotation/listen.ann:



( run in 1.194 second using v1.01-cache-2.11-cpan-1191d43216d )