package Zing::Logic;
use 5.014;
use strict;
use warnings;
use registry 'Zing::Types';
use routines;
use Data::Object::Class;
use Data::Object::ClassHas;
use Zing::Flow;
our $VERSION = '0.27'; # VERSION
# ATTRIBUTES
has 'debug' => (
is => 'ro',
isa => 'Bool',
def => 0,
);
has 'interupt' => (
is => 'rw',
isa => 'Interupt',
opt => 1
);
has 'on_perform' => (
is => 'ro',
isa => 'CodeRef',
new => 1,
);
fun new_on_perform($self) {
$self->can('handle_perform_event')
}
has 'on_receive' => (
is => 'ro',
isa => 'CodeRef',
new => 1,
);
fun new_on_receive($self) {
$self->can('handle_receive_event')
}
has 'on_register' => (
is => 'ro',
isa => 'CodeRef',
new => 1,
);
fun new_on_register($self) {
$self->can('handle_register_event')
}
has 'on_reset' => (
is => 'ro',
isa => 'CodeRef',
new => 1,
);
fun new_on_reset($self) {
$self->can('handle_reset_event')
}
has 'on_suicide' => (
is => 'ro',
isa => 'CodeRef',
new => 1,
);
fun new_on_suicide($self) {
$self->can('handle_suicide_event')
}
has 'process' => (
is => 'ro',
isa => 'Process',
req => 1,
);
# SHIMS
sub _kill {
CORE::kill(shift, shift)
}
sub _repr {
"$_[0]" =~ s/^((?:[\w:]+=*)\w+)\((\w+)\)/($1)/r
}
sub _words {
(map {ref() ? _repr($_) : m/\s+/ ? qq("$_") : $_} @_)
}
# METHODS
method flow() {
my $step_0 = Zing::Flow->new(
name => 'on_register',
code => fun($step, $loop) { $self->trace('on_register')->($self) }
);
my $step_1 = $step_0->next(Zing::Flow->new(
name => 'on_perform',
code => fun($step, $loop) { $self->trace('on_perform')->($self) }
));
my $step_2 = $step_1->next(Zing::Flow->new(
name => 'on_receive',
code => fun($step, $loop) { $self->trace('on_receive')->($self) }
));
my $step_3 = $step_2->next(Zing::Flow->new(
name => 'on_reset',
code => fun($step, $loop) { $self->trace('on_reset')->($self) }
));
my $step_4 = $step_3->next(Zing::Flow->new(
name => 'on_suicide',
code => fun($step, $loop) { $self->trace('on_suicide')->($self) }
));
$step_0
}
method note(Any @data) {
if ($self->debug) {
$self->process->log->debug(
join ' ', sprintf('in %s, %s', _words($self, $self->process)), @data
);
}
return $self;
}
method handle_perform_event() {
my $process = $self->process;
return $self if !$process->can('perform');
$process->perform();
return $self;
}
method handle_receive_event() {
my $process = $self->process;
return $self if !$process->can('mailbox');
return $self if !$process->can('receive');
my $data = $process->mailbox->recv or return;
$process->receive($data->{from}, $data->{data});
return $self;
}
method handle_register_event() {
my $process = $self->process;
return $self if $self->{registered};
$self->{registered} = $process->meta->send($process->metadata);
return $self;
}
method handle_reset_event() {
my $process = $self->process;
if ($process->journal && $process->log->count && $process->env->debug) {
$process->journal->send({
from => $process->name,
data => {
logs => $process->log->serialize,
tag => $process->tag
}
});
}
$process->log->reset;
return $self;
}
method handle_suicide_event() {
my $process = $self->process;
return $self if !$process->parent;
# children who don't known their parents kill themeselves :)
$process->winddown unless $process->ping($process->parent->pid);
return $self;
}
method signals() {
my $trapped = {};
$trapped->{INT} = sub {
$self->trace('interupt', 'INT');
$self->process->winddown;
};
$trapped->{QUIT} = sub {
$self->trace('interupt', 'QUIT');
$self->process->winddown;
};
$trapped->{TERM} = sub {
$self->trace('interupt', 'TERM');
$self->process->winddown;
};
return $trapped;
}
method trace(Str $method, Any @args) {
my @with = (@args ? (join ', ', 'with', _words(@args)) : ());
return $self->note(qq(invokes "$method"), @with)->$method(@args);
}
1;
=encoding utf8
=head1 NAME
Zing::Logic - Process Logic
=cut
=head1 ABSTRACT
Process Logic Chain
=cut
=head1 SYNOPSIS
use Zing::Logic;
use Zing::Process;
my $process = Zing::Process->new;
my $logic = Zing::Logic->new(process => $process);
=cut
=head1 DESCRIPTION
This package provides the logic (or logic chain) to be executed by the process
event-loop.
=cut
=head1 LIBRARIES
This package uses type constraints from:
L<Zing::Types>
=cut
=head1 ATTRIBUTES
This package has the following attributes:
=cut
=head2 interupt
interupt(Interupt)
This attribute is read-only, accepts C<(Interupt)> values, and is optional.
=cut
=head2 on_perform
on_perform(CodeRef)
This attribute is read-only, accepts C<(CodeRef)> values, and is optional.
=cut
=head2 on_receive
on_receive(CodeRef)
This attribute is read-only, accepts C<(CodeRef)> values, and is optional.
=cut
=head2 on_register
on_register(CodeRef)
This attribute is read-only, accepts C<(CodeRef)> values, and is optional.
=cut
=head2 on_reset
on_reset(CodeRef)
This attribute is read-only, accepts C<(CodeRef)> values, and is optional.
=cut
=head2 on_suicide
on_suicide(CodeRef)
This attribute is read-only, accepts C<(CodeRef)> values, and is optional.
=cut
=head2 process
process(Process)
This attribute is read-only, accepts C<(Process)> values, and is required.
=cut
=head1 METHODS
This package implements the following methods:
=cut
=head2 flow
flow() : Flow
The flow method builds and returns the logic flow for the process event-loop.
=over 4
=item flow example #1
# given: synopsis
my $flow = $logic->flow;
=back
=cut
=head2 signals
signals() : HashRef
The signals method builds and returns the process signal handlers.
=over 4
=item signals example #1
# given: synopsis
my $signals = $logic->signals;
=back
=cut
=head1 AUTHOR
Al Newkirk, C<awncorp@cpan.org>
=head1 LICENSE
Copyright (C) 2011-2019, Al Newkirk, et al.
This is free software; you can redistribute it and/or modify it under the terms
of the The Apache License, Version 2.0, as elucidated in the L<"license
file"|https://github.com/cpanery/zing/blob/master/LICENSE>.
=head1 PROJECT
L<Wiki|https://github.com/cpanery/zing/wiki>
L<Project|https://github.com/cpanery/zing>
L<Initiatives|https://github.com/cpanery/zing/projects>
L<Milestones|https://github.com/cpanery/zing/milestones>
L<Contributing|https://github.com/cpanery/zing/blob/master/CONTRIBUTE.md>
L<Issues|https://github.com/cpanery/zing/issues>
=cut