Last active
October 20, 2015 18:08
-
-
Save jhthorsen/832e745639341ce60815 to your computer and use it in GitHub Desktop.
Mojo::Cursor - General purpose async iterator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use Mojo::Base -strict; | |
use Mojo::Cursor; | |
use Mojo::IOLoop::While; | |
use File::Basename 'dirname'; | |
use Test::More; | |
my @items = (42, 24); | |
my $iterator = Mojo::Cursor->new(sub { return '', shift @items }); | |
my @res; | |
$iterator->next(sub { shift; push @res, @_; }); | |
$iterator->next(sub { shift; push @res, @_; }); | |
$iterator->next(sub { shift; push @res, @_; Mojo::IOLoop->stop; }); | |
Mojo::IOLoop->start; | |
is_deeply \@res, ['', 42, '', 24, '', undef], 'new(sub {...})'; | |
@res = (); | |
Mojo::IOLoop::While->new( | |
Mojo::Cursor->new_from_dir(dirname(__FILE__), sub { /\.t$/ ? {file => $_} : undef }), | |
sub { | |
my ($delay, $err, $item) = @_; | |
return unless $item; | |
$delay->redo; | |
push @res, $item; | |
}, | |
); | |
Mojo::IOLoop->start; | |
like $res[0]{file}, qr{\.t$}, 'got files'; | |
@res = (); | |
$iterator = Mojo::Cursor->new_from_dir('no_such_directory', sub {$_}); | |
$iterator->next(sub { shift; push @res, @_; Mojo::IOLoop->stop unless pop; }); | |
Mojo::IOLoop->start; | |
ok $res[0], 'new_from_dir(no_such_directory) error'; | |
is $res[1], undef, 'new_from_dir(no_such_directory) undef'; | |
done_testing; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package Mojo::Cursor; | |
=head1 NAME | |
Mojo::Cursor - General purpose async iterator | |
=head1 DESCRIPTION | |
L<Mojo::Cursor> is a class for instantiating an iterator object. | |
=head1 SYNOPSIS | |
use Mojo::Cursor; | |
my $iterator = Mojo::Cursor->new(sub { return $err, $item; }); | |
my $iterator = Mojo::Cursor->new(sub { return '', shift @items }); | |
my $iterator = Mojo::Cursor->new_from_dir($path, sub { /^\w/ }); | |
# async | |
$iterator->next(sub { | |
my ($iterator, $err, $item) = @_; | |
die $err if $err; | |
}); | |
# sync | |
$item = $iterator->next; | |
=cut | |
use Mojo::Base -base; | |
use Mojo::IOLoop; | |
=head1 METHODS | |
=head2 next | |
See L</SYNOPSIS>. | |
=cut | |
sub next { | |
my ($self, $cb) = @_; | |
my $iterator = $self->{iterator}; | |
return $iterator->($self) unless $cb; | |
Mojo::IOLoop->next_tick( | |
sub { | |
$cb->($self, $@, undef) unless eval { $cb->($self, $iterator->($self)) }; | |
} | |
); | |
return $self; | |
} | |
=head2 new | |
$self = Mojo::Cursor->new(sub { ... }); | |
See L</SYNOPSIS>. | |
=cut | |
sub new { | |
my ($class, $cb) = (shift, shift); | |
my $self = $class->SUPER::new(@_); | |
$self->{iterator} = $cb; | |
$self; | |
} | |
=head2 new_from_dir | |
$self = Mojo::Cursor->new_from_dir($path, $filter); | |
Creates a L</new> iterator object from a C<$path>. Each of the files | |
returned will need to pass the C<$filter> function. | |
=cut | |
sub new_from_dir { | |
my ($class, $path, $filter) = (shift, shift, shift); | |
my $self = $class->SUPER::new(@_); | |
if (opendir(my $DH, $path)) { | |
return $self->new( | |
sub { | |
local ($!, $_, $@); | |
while (readdir $DH) { | |
my $item = eval { $filter->($_) }; | |
return $@, undef if $@; | |
return '', $item if defined $item; | |
} | |
return $!, undef; | |
} | |
); | |
} | |
else { | |
my $err = $!; | |
return $self->new(sub { return $err, undef; }, @_); | |
} | |
} | |
=head1 COPYRIGHT AND LICENSE | |
Copyright (C) 2014, Jan Henning Thorsen | |
This program is free software, you can redistribute it and/or modify it under | |
the terms of the Artistic License version 2.0. | |
=head1 AUTHOR | |
Jan Henning Thorsen - C<[email protected]> | |
=cut | |
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package Convos::IOLoop::While; | |
=head1 NAME | |
Convos::IOLoop::While - Go loopy of Mojo::IOLoop::Delay | |
=head1 DESCRIPTION | |
L<Convos::IOLoop::While> is a subclass of L<Mojo::IOLoop::Delay> which | |
can loop L<Mojo::IOLoop::Delay/remaining>. | |
=head1 SYNOPSIS | |
use Convos::IOLoop::While; | |
Convos::IOLoop::While->new( | |
$cursor_obj, | |
sub { | |
my ($delay, $err, $item) = @_; | |
die $err if $err; # $cursor_obj->next reported $err | |
return unless $item; # last item from $cursor_obj | |
$delay->redo; # get next() item from $cursor_obj | |
# do stuff with $item | |
}, | |
); | |
=cut | |
use Mojo::Base 'Mojo::IOLoop::Delay'; | |
=head1 ATTRIBUTES | |
=head1 METHODS | |
=head2 new | |
$self = Convos::IOLoop::While->new($cursor, @steps); | |
$self = Convos::IOLoop::While->new($cursor, sub {...}, ...); | |
Creates a new L<Convos::IOLoop::While> object. | |
=cut | |
sub new { | |
my ($class, @steps) = @_; | |
if (ref $steps[0] ne 'CODE') { | |
my $cursor = shift @steps; | |
unshift @steps, sub { $cursor->next(shift->begin) }; | |
} | |
return $class->SUPER::new(steps => [@steps])->steps(@steps); | |
} | |
=head2 remaining | |
See L<Mojo::IOLoop::Delay/remaining>. | |
=cut | |
sub remaining { | |
my $self = shift; | |
return $self->SUPER::remaining unless @_; | |
delete $self->{steps} unless @{$_[0]}; | |
$self->SUPER::remaining(@_); | |
} | |
=head2 redo | |
$self->redo; | |
Get the next item from the cursor and do all the | |
L<steps|Mojo::IOLoop::Delay/steps> again. | |
=cut | |
sub redo { | |
my $self = shift; | |
$self->remaining([@{$self->{steps}}]); | |
} | |
=head1 COPYRIGHT AND LICENSE | |
Copyright (C) 2014, Jan Henning Thorsen | |
This program is free software, you can redistribute it and/or modify it under | |
the terms of the Artistic License version 2.0. | |
=head1 AUTHOR | |
Jan Henning Thorsen - C<[email protected]> | |
=cut | |
1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment