coroutine0

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

coroutine0.pm
Makefile.PL
MANIFEST
README
t/1.t

Makefile.PL  view on Meta::CPAN

use 5.000;
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
    'NAME'		=> 'coroutine0',
    'VERSION_FROM'	=> 'coroutine0.pm', # finds $VERSION
    'PREREQ_PM'		=> {}, # e.g., Module::Name => 1.1
    ($] >= 5.005 ?    ## Add these new keywords supported since 5.005
      (ABSTRACT_FROM => 'coroutine0.pm', # retrieve abstract from module
       AUTHOR     => 'david <david@localdomain>') : ()),
);

README  view on Meta::CPAN

coroutine0 version 0.02
=======================

For the purposes of this module, a coroutine is considered to be a subroutine that
maintains its state and execution position between calls to it.  To return from
a coroutine but start up where you left off, use C<YIELD> instead of C<return> to
send a result back to the caller.

The coroutine declaration syntax leaves much to be desired.  The 0 is suffixed to
the module name so the coroutine module, when it finally appears, will not have
to support this clunky code-in-string-paired-with-BODY-keyword syntax.


INSTALLATION

To install this module type the following:

   perl Makefile.PL
   make
   make test

coroutine0.pm  view on Meta::CPAN

package coroutine0;

use 5.000;
use strict;
use vars qw($VERSION @ISA %bodystrings);
@ISA = qw();

$VERSION = '0.02';

#my %bodystrings;
my $labname = 'corolab';

use Carp;

sub rewrite($){
	my $l = $labname++;
	<<EOF;
	\$LABEL='$l';
	return $_[0];
	$l:
EOF

coroutine0.pm  view on Meta::CPAN


sub DESTROY{
	delete $bodystrings{$_[0]};
};

1;
__END__

=head1 NAME

coroutine0 - a working but ugly coroutine generator

=head1 SYNOPSIS

  use coroutine0;
  sub one_to_N($);
  *one_to_N = new coroutine0
	VARS => [qw/$i/],
	BODY => <<'END_OF_BODY',  # single-quotes for q{} not qq{}
		$i = 1;
		while ($i < 11){
			YIELD $i++;
		};
  END_OF_BODY
	PROTO => '($)',   # gets pasted in whole: parens are required
	TIDY => 0;

  # these have their own sequences:
  *another_one_to_ten = copy {\&one_to_N} ;  #indirect
  *yet_another_one_to_ten = (\&one_to_N)->copy(); #direct

  # this one shares one_to_N's sequence:
  *same_sequence = \&one_to_N;
		

=head1 ABSTRACT

  coroutines using closures to provide lexical persistence

=head1 DESCRIPTION

C<new> takes a list and returns a blessed coderef. The defined
argument keys include C<VARS> and C<BODY>. Lexicals meant
to persist between calls to a routine are listed in C<VARS>.

The C<new> function works by rewriting each instance
of /\bYIELD\b.*;/ within the body to a labeled exit/entry point
and wrapping the rewritten body in an anonymous subroutine generator.

Define C<TIDY> to a true value to suppress caching the extended
coroutine source code. This breaks C<copy>.

You can make another coroutine with its own pad by calling
the C<copy> method, which evals the wrapped body again.

define a C<PRE> argument to include some code to run every time
the coro is called, before going to the entry point.

define a C<DIE> argument to have C<new> tell you all about it as soon
as the body is rewritten.

When the execution falls out of the bottom of the body, an C<undef>
is returned and the execution point is reset to the begining of the
body.  Variables are not cleared and will keep values from previous
times through the routine.

=head1 CAVEATS

coroutine0.pm  view on Meta::CPAN

like to come back in to somewhere other than directly following your exit point.

No analysis of string literals is performed, so putting YIELD in quotes
within the body may cause problems if you didn't do it just to see the
YIELD get expanded and printed out.

We can see package variables from the calling environment but not lexicals.

=head1 FUTURE DIRECTIONS

future coroutines modules might handle recursion more gracefully, might
have a better declaration and definition syntax, might be a capability
of a more object-oriented dispatch system rather than a clumsy hack.

=head1 HISTORY

=over 8

=item 0.02

VARS is now optional

=item 0.01

Original version; created by h2xs 1.22 with options
  -A -C -X -b5.0.0 -ncoroutine0 --skip-exporter

=back



=head1 SHOUT_OUTS

Damian Conway suggested the problem

Paul Kulchenko suggested this approach when I presented a much more

t/1.t  view on Meta::CPAN

# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl 1.t'

#########################

# change 'tests => 1' to 'tests => last_test_to_print';

use Test;
BEGIN { plan tests => 16, todo => [] };
use coroutine0;
ok(1); # If we made it this far, we're ok. #'

$coderef = new coroutine0
	# DIE => 1,
	VARS => [qw{$number $another}],
	# PRE => 'print "$number\n";',
	BODY => <<'EOF',
		$number = 1;
		YIELD ($_[0] + $number++);
		YIELD $_[0] + $number++;
		YIELD ($_[0] + $number++);
EOF
	PROTO => '($)';

t/1.t  view on Meta::CPAN


# addn and another should be using the same pad
ok(addn 22 , 24); # test 9

# but $coderef has its own pad
ok(&$coderef(23), 24); 
ok(&$another(21), 24);

# we expect \&addn to be blessed
$crefname = ref(\&addn);
ok($crefname,'coroutine0');
$cref = \&addn;
eval {
  # $another_copy = copy $cref;
  $another_copy = copy {\&addn};
  *yet_another_copy = (\&addn)->copy();
};
ok(!$@);
ok(&$another_copy(23), 24);
ok(yet_another_copy(23), 24);
ok(&$another_copy(23), 25); # separate pad.



( run in 0.577 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )