NAME
Sub::Go - DWIM sub blocks for smart matching
VERSION
version 0.01
SYNOPSIS
use Sub::Go;
[ 1, 2, 3 ] ~~ go { say $_ };
# 1
# 2
# 3
# hashes with $a and $b
%h ~~ go { say "key $a, value $b" };
undef ~~ go {
# never gets called...
};
'' ~~ go {
# ...but this does
};
# in-place modify
my @rs = ( { name=>'jack', age=>20 }, { name=>'joe', age=>45 } );
@rs ~~ go { $_->{name} = 'sue' };
# filehandles
open my $fh, '<', 'file.txt';
$fh ~~ go {
my $line = shift;
say ; # line by line
};
# chaining
@arr ~~ go { s/$/one/ } go { s/$/two/ };
# combine with signatures, or Method::Signatures
# for improved sweetness
use Method::Signatures;
%h ~~ go func($x,$y) {
say $x * $y;
};
DESCRIPTION
In case you don't know, smart matching (~~
) data against a code block will run the block once (for scalars) or, distributively, many times for arrays and hashes:
[1..10] ~~ sub { say shift };
@arr ~~ sub { say shift };
%h ~~ sub { ... };
The motivation behind this module is to improve the experience of using a code block with the smart match operator.
This module imports a sub called go
into your package. This sub returns an object that overloads the smart match operator.
Benefits
proper handling of hashes, with $a and $b for keys and values
Smart matching sends only the keys, which may be useless if your hash is anonymous.
{ foo=>1, bar=>2 } ~~ go {
say "key=$a, value=$b";
};
context variables
Load $_
with the current value for arrays and scalars. Look for $a
and $b
for hash values.
in-place modification of original values
But only in the first go
block of a chain (although this may change soon).
my @arr = qw/a b c/;
@arr ~~ go { s{$}{x} };
# now @arr is qw/ax bx cx/
prevent the block from running on undef values
We're tired of checking if defined is defined in loops.
undef ~~ go { say "never runs" };
undef ~~ sub { say "but we do" };
chaining of sub blocks
So you can bind several blocks, one after the other, in the opposite direction of map
, grep
and friends.
$arr ~~ go { } go { } go { };
no warnings on the useless use of smart match operator in void context
Annoying warning for funky syntax overloading modules like this one or IO::All. Perl should have better way around this warning.
Pitfalls
A smart match (and most overloaded operators) can only return scalar values. So you can only expect to get a scalar (value or arrayref) from your block chaining.
FEATURES
chaining
You can chain go
statements together, in the reverse direction as you would with map
or grep
.
say 10 ~~ go { return $_[0] * 2 }
go { return $_[0] + 1 };
# 21
The next go
block in the chain gets the return value from the previous block.
[1..3] ~~ go { say "uno " . $_[0]; 100 + $_[0] }
go { say "due " . shift };
# uno 1
# uno 2
# uno 3
# due 101
# due 102
# due 103
To interleave two go
blocks use the yield
statement.
[1..3] ~~ go { say "uno " . $_[0]; yield 100 + $_[0] } go { say "due " . shift };
# uno 1
# due 101
# uno 2
# due 102
# uno 3
# due 103
You can interrupt a go
block with an special return statement: return skip
.
[1..1000] ~~ go {
# after 100 this block won't execute anymore
return skip if $_[0] > 100;
} go {
# but this one will keep going up to the 1000th
};
Or break the whole chain at a given point:
[1..1000] ~~ go {
# after 100 this block won't execute anymore
return stop if $_[0] > 100;
} go {
# this one will run 100 times too
};
return values
Scalar is the only return value from a smart match expression, and the same applies to go
. You can only return scalars, no arrays and hashes. So we return an arrayref if your go chain returns more than one value.
# scalar
my $value = 'hello' ~~ go { "$_[0] world" } # hello world
# arrayref
my $arr = [10..19] go { shift }; # @arr == 1, $arr[0] == 10
Just use map
in this case, which is syntactically more sound anyway.
So, there's an alternative implementation for returning values, by chaining a reference to a variable, as such:
my @squares;
@input ~~ go { $_ ** 2 } \@squares;
my %hash = ( uno=>11, due=>22 );
my %out;
%hash ~~ go { "xxx$_[0]" => $_[1] } \%out;
# %out = ( xxxuno => 11, xxxdue => 22 )
Now you have a map
like interface the other way around.
next iterators
If you send the block an object which implements a method called next
, the method will be automatically called and the return value fed to the block.
# DBIx::Class resultset
$resultset->search({ age=>100 }) ~~ go {
$_->name . " is centenary!";
};
IMPORTS
go CODE
The main function here. Don't forget the semicolon at the end of the block.
yield VALUE
Iterate over into the next block in the chain.
[qw/sue mike/] ~~ go { yield "world, $_" } go { say "hello " . shift };
skip
Tell the iterator to stop executing the current block and go to the next, if any.
return skip;
stop
Tell the iterator to stop executing all blocks.
return stop;
BUGS
This is pre-alfa, out in the CPAN for a test-drive. There are still inconsistencies in the syntax that need some more thought, so expect things to change badly.
PadWalker, a dependency, may segfault in perl 5.14.1.
SEE ALSO
autobox::Core - has an each
method that can be chained together