File Coverage

blib/lib/Syntax/Operator/Zip.pm
Criterion Covered Total %
statement 37 39 94.8
branch 11 12 91.6
condition 2 3 66.6
subroutine 10 11 90.9
pod 1 4 25.0
total 61 69 88.4


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2021-2024 -- leonerd@leonerd.org.uk
5              
6             package Syntax::Operator::Zip 0.10;
7              
8 5     5   1475600 use v5.14;
  5         23  
9 5     5   44 use warnings;
  5         11  
  5         317  
10              
11 5     5   41 use Carp;
  5         10  
  5         386  
12              
13 5     5   3084 use meta 0.004;
  5         6451  
  5         249  
14 5     5   64 no warnings 'meta::experimental';
  5         11  
  5         2916  
15              
16             require XSLoader;
17             XSLoader::load( __PACKAGE__, our $VERSION );
18              
19             =head1 NAME
20              
21             C - infix operator to compose two lists together
22              
23             =head1 SYNOPSIS
24              
25             On Perl v5.38 or later:
26              
27             use Syntax::Operator::Zip;
28              
29             foreach (@xvals Z @yvals) {
30             my ($x, $y) = @$_;
31             say "Value $x is associated with value $y";
32             }
33              
34             Or on Perl v5.14 or later:
35              
36             use v5.14;
37             use Syntax::Operator::Zip qw( zip );
38              
39             foreach (zip \@xvals, \@yvals) {
40             my ($x, $y) = @$_;
41             say "Value $x is associated with value $y";
42             }
43              
44             =head1 DESCRIPTION
45              
46             This module provides infix operators that compose lists of elements by
47             associating successive elements from each of the input lists, forming a new
48             list.
49              
50             Support for custom infix operators was added in the Perl 5.37.x development
51             cycle and is available from development release v5.37.7 onwards, and therefore
52             in Perl v5.38 onwards. The documentation of L
53             describes the situation in more detail.
54              
55             While Perl versions before this do not support custom infix operators, they
56             can still be used via C and hence L.
57             Custom keywords which attempt to parse operator syntax may be able to use
58             these.
59              
60             Additionally, earlier versions of perl can still use the function-like
61             wrapper versions of these operators. Even though the syntax appears like a
62             regular function call, the code is compiled internally into the same more
63             efficient operator internally, so will run without the function-call overhead
64             of a regular function.
65              
66             =cut
67              
68             sub import
69             {
70 4     4   1913 my $pkg = shift;
71 4         17 my $caller = caller;
72              
73 4         19 $pkg->import_into( $caller, @_ );
74             }
75              
76             sub unimport
77             {
78 2     2   543 my $pkg = shift;
79 2         7 my $caller = caller;
80              
81 2         28 $pkg->unimport_into( $caller, @_ );
82             }
83              
84 4     4 0 17 sub import_into { shift->apply( 1, @_ ) }
85 2     2 0 8 sub unimport_into { shift->apply( 0, @_ ) }
86              
87             sub apply
88             {
89 6     6 0 12 my $pkg = shift;
90 6         22 my ( $on, $caller, @syms ) = @_;
91              
92 6 100       33 @syms or @syms = qw( Z M );
93              
94 6         14 my %syms = map { $_ => 1 } @syms;
  10         50  
95 6         18 foreach (qw( Z M )) {
96 12 100       42 next unless delete $syms{$_};
97              
98             $on ? $^H{"Syntax::Operator::Zip/$_"}++
99 6 100       43 : delete $^H{"Syntax::Operator::Zip/$_"};
100             }
101              
102 6         12 my $callerpkg;
103              
104 6         13 foreach (qw( zip mesh )) {
105 12 100       52 next unless delete $syms{$_};
106              
107 4   66     118 $callerpkg //= meta::package->get( $caller );
108              
109 4 100       20 $on ? $callerpkg->add_symbol( '&'.$_ => \&{$_} )
  3         24  
110             : $callerpkg->remove_symbol( '&'.$_ );
111             }
112              
113 6 50       7506 croak "Unrecognised import symbols @{[ keys %syms ]}" if keys %syms;
  0            
114             }
115              
116             =head1 OPERATORS
117              
118             =head2 Z
119              
120             my @result = @lhs Z @rhs;
121              
122             # returns [$lhs[0], $rhs[0]], [$lhs[1], $rhs[1]], ...
123              
124             Yields a list of array references, each containing a pair of items from the
125             two operand lists. If one of the operand lists is shorter than the other, the
126             missing elements will be filled in with C so that every array reference
127             in the result contains exactly two items.
128              
129             my @result = @alphas Z @betas Z @gammas Z ...
130              
131             # returns [$alphas[0], $betas[0], $gammas[0], ...], ...
132              
133             I this module supports list-associative combinations of
134             more than two input lists at once. The result will be composed of parallel
135             items from each of the given input lists.
136              
137             =head2 M
138              
139             my @result = @lhs M @rhs;
140              
141             # returns $lhs[0], $rhs[0], $lhs[1], $rhs[1], ...
142              
143             Yields a list of the values from its operand lists, rearranged into pairs and
144             flattened. If one of the operand lists is shorter than the other, the missing
145             elements will be filled in with C so that the result is correctly lined
146             up.
147              
148             my @result = @alphas M @betas M @gammas M ...
149              
150             # returns $alphas[0], $betas[0], $gammas[0], ..., $alphas[1], ...
151              
152             I this module supports list-associative combinations of
153             more than two input lists at once. The result will be composed of parallel
154             items from each of the given input lists.
155              
156             The result of this operator is useful for constructing hashes from two lists
157             containing keys and values
158              
159             my %hash = @keys M @values;
160              
161             This is also useful combined with the multiple variable C syntax of
162             Perl 5.36 and above:
163              
164             foreach my ( $alpha, $beta, $gamma ) ( @alphas M @betas M @gammas ) {
165             ...
166             }
167              
168             =cut
169              
170             =head1 FUNCTIONS
171              
172             As a convenience, the following functions may be imported which implement the
173             same behaviour as the infix operators, though are accessed via regular
174             function call syntax. The lists for these functions to operate on must be
175             passed as references to arrays (either named variables, or anonymously
176             constructed by C<[...]>).
177              
178             =head2 zip
179              
180             my @result = zip( \@lhs, \@rhs, ... );
181              
182             A function version of the L operator.
183              
184             See also L.
185              
186             =head2 mesh
187              
188             my @result = mesh( \@lhs, \@rhs, ... );
189              
190             A function version of the L operator.
191              
192             See also L.
193              
194             =cut
195              
196             =head1 AUTHOR
197              
198             Paul Evans
199              
200             =cut
201              
202             0x55AA;