AnyEvent-Callback

 view release on metacpan or  search on metacpan

lib/AnyEvent/Callback.pm  view on Meta::CPAN

    } => __PACKAGE__;

    $self;
}

sub CBS {
    return AnyEvent::Callback::Stack->new;
}


=head2 error

Calls error callback. If the object has no registered error callbacks,
parent object's error callback will be called.

    $cb->error('WTF?');

=cut

sub error {
    my ($self, @error) = @_;

    $self->{ecalled}++;
    carp "Repeated error callback calling: $self->{ecalled}"
        if $self->{ecalled} > 1;
    carp "Calling error callback after result callback"
        if $self->{called};

    if ($self->{ecb}) {
        $self->{ecb}( @error );
        delete $self->{ecb};
        delete $self->{cb};
        delete $self->{parent};
        return;
    }

    delete $self->{ecb};
    delete $self->{cb};
    my $parent = delete $self->{parent};

    unless($parent) {
        carp "Uncaught error: @error";
        return;
    }

    $parent->error( @error );
    return;
}


sub DESTROY {
    my ($self) = @_;
    return if $self->{called} or $self->{ecalled};
    $self->error("no one touched registered callback");
    delete $self->{cb};
    delete $self->{ecb};
}


package AnyEvent::Callback::Stack;
use Scalar::Util 'weaken';
use Carp;

sub new {
    my ($class) = @_;
    return bless { stack => [], done => 0 } => ref($class) || $class;
}

sub cb {
    my ($self) = @_;
    my $idx = @{ $self->{stack} };
    my $cb = AnyEvent::Callback::CB
        sub {
            $self->{stack}[$idx] = AnyEvent::Callback::Stack::Result->new(@_);
            $self->{done}++;
            $self->_check_if_done;
        },
        sub {
            $self->{stack}[$idx] = AnyEvent::Callback::Stack::Result->err(@_);
            $self->{done}++;
            $self->_check_if_done;
        }
    ;
    push @{ $self->{stack} } => $cb;
    weaken $self->{stack}[$idx];
    return $self->{stack}[$idx];
}


sub _check_if_done {
    my ($self) = @_;
    return unless $self->{waiter};
    return unless $self->{done} >= @{ $self->{stack} };
    my $cb = delete $self->{waiter};
    $cb->(@{ $self->{stack} });
    $self->{stack} = [];
    $self->{done} = 0;
}

sub wait :method {
    my ($self, $cb) = @_;
    croak 'Usage: $cbs->wait(sub { ... })' unless 'CODE' eq ref $cb;
    croak 'You have already initiated wait process' if $self->{waiter};
    $self->{waiter} = $cb;
    $self->_check_if_done;
}

package AnyEvent::Callback::Stack::Result;

sub new {
    my ($class, @res) = @_;
    return bless { res => \@res } => ref($class) || $class;
}

sub err {
    my ($class, @res) = @_;
    return bless { err => \@res, res => [] } => ref($class) || $class;
}

sub is_error {
    my ($self) = @_;
    return exists $self->{err};
}

sub results {
    my ($self) = @_;
    return $self->{res} unless wantarray;
    return @{ $self->{res} };
}

sub errors {
    my ($self) = @_;
    return unless $self->is_error;
    return $self->{err} unless wantarray;
    return @{ $self->{err} };
}

sub errstr {
    my ($self) = @_;
    return join ' ' => $self->errors;
}

=head1 COPYRIGHT AND LICENCE

 Copyright (C) 2012 by Dmitry E. Oboukhov



( run in 2.947 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )