line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
114
|
|
|
114
|
|
69781
|
use 5.006; |
|
114
|
|
|
|
|
402
|
|
2
|
114
|
|
|
114
|
|
603
|
use strict; |
|
114
|
|
|
|
|
201
|
|
|
114
|
|
|
|
|
2382
|
|
3
|
114
|
|
|
114
|
|
517
|
use warnings; |
|
114
|
|
|
|
|
234
|
|
|
114
|
|
|
|
|
6153
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package LINQ::Collection; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:TOBYINK'; |
8
|
|
|
|
|
|
|
our $VERSION = '0.001'; |
9
|
|
|
|
|
|
|
|
10
|
114
|
|
|
114
|
|
685
|
use Role::Tiny; |
|
114
|
|
|
|
|
261
|
|
|
114
|
|
|
|
|
663
|
|
11
|
114
|
|
|
114
|
|
44295
|
use LINQ::Util::Internal (); |
|
114
|
|
|
|
|
285
|
|
|
114
|
|
|
|
|
559032
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
requires qw( to_list ); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my $_coerce = sub { |
16
|
|
|
|
|
|
|
my ( $thing ) = @_; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
require Scalar::Util; |
19
|
|
|
|
|
|
|
if ( Scalar::Util::blessed( $thing ) and $thing->DOES( __PACKAGE__ ) ) { |
20
|
|
|
|
|
|
|
return $thing; |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
if ( ref( $thing ) eq 'ARRAY' ) { |
24
|
|
|
|
|
|
|
require LINQ::Array; |
25
|
|
|
|
|
|
|
return LINQ::Array::->new( $thing ); |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
LINQ::Util::Internal::throw( |
29
|
|
|
|
|
|
|
"CallerError", |
30
|
|
|
|
|
|
|
message => "Expected a LINQ collection; got '$thing'" |
31
|
|
|
|
|
|
|
); |
32
|
|
|
|
|
|
|
}; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub select { |
35
|
72
|
|
|
72
|
1
|
251
|
my $self = shift; |
36
|
72
|
|
|
|
|
220
|
my $map = LINQ::Util::Internal::assert_code( @_ ); |
37
|
|
|
|
|
|
|
|
38
|
72
|
|
|
|
|
190
|
my $iter = $self->to_iterator; |
39
|
72
|
|
|
|
|
150
|
my $stopped; |
40
|
|
|
|
|
|
|
|
41
|
72
|
|
|
|
|
365
|
require LINQ; |
42
|
|
|
|
|
|
|
LINQ::LINQ( |
43
|
|
|
|
|
|
|
sub { |
44
|
|
|
|
|
|
|
# uncoverable branch true |
45
|
394
|
50
|
|
394
|
|
689
|
return LINQ::END() if $stopped; |
46
|
394
|
|
|
|
|
632
|
my @got = $iter->(); |
47
|
394
|
100
|
|
|
|
920
|
if ( @got ) { |
48
|
322
|
|
|
|
|
493
|
local $_; |
49
|
322
|
|
|
|
|
1137
|
return scalar $map->( $_ = $got[0] ); |
50
|
|
|
|
|
|
|
} |
51
|
72
|
|
|
|
|
148
|
++$stopped; |
52
|
72
|
|
|
|
|
261
|
return LINQ::END(); |
53
|
|
|
|
|
|
|
} |
54
|
72
|
|
|
|
|
376
|
); |
55
|
|
|
|
|
|
|
} #/ sub select |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub where { |
58
|
159
|
|
|
159
|
1
|
524
|
my $self = shift; |
59
|
159
|
|
|
|
|
433
|
my $filter = LINQ::Util::Internal::assert_code( @_ ); |
60
|
|
|
|
|
|
|
|
61
|
159
|
|
|
|
|
433
|
my $iter = $self->to_iterator; |
62
|
159
|
|
|
|
|
271
|
my $stopped; |
63
|
|
|
|
|
|
|
|
64
|
159
|
|
|
|
|
764
|
require LINQ; |
65
|
|
|
|
|
|
|
LINQ::LINQ( |
66
|
|
|
|
|
|
|
sub { |
67
|
|
|
|
|
|
|
GETVAL: { |
68
|
418
|
100
|
|
418
|
|
588
|
return LINQ::END() if $stopped; |
|
1145
|
|
|
|
|
1869
|
|
69
|
1143
|
|
|
|
|
1846
|
my @got = $iter->(); |
70
|
1143
|
100
|
|
|
|
2159
|
if ( @got ) { |
71
|
1017
|
|
|
|
|
1359
|
local $_; |
72
|
1017
|
|
|
|
|
2898
|
my $pass = $filter->( $_ = $got[0] ); |
73
|
1004
|
100
|
|
|
|
11374
|
return $got[0] if $pass; |
74
|
727
|
|
|
|
|
1229
|
redo GETVAL; |
75
|
|
|
|
|
|
|
} |
76
|
126
|
|
|
|
|
259
|
++$stopped; |
77
|
126
|
|
|
|
|
451
|
return LINQ::END(); |
78
|
|
|
|
|
|
|
} #/ GETVAL: |
79
|
|
|
|
|
|
|
} |
80
|
159
|
|
|
|
|
894
|
); |
81
|
|
|
|
|
|
|
} #/ sub where |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub select_many { |
84
|
4
|
|
|
4
|
1
|
27
|
my $self = shift; |
85
|
4
|
|
|
|
|
14
|
my $map = LINQ::Util::Internal::assert_code( @_ ); |
86
|
|
|
|
|
|
|
|
87
|
4
|
|
|
|
|
13
|
my $outer = $self->to_iterator; |
88
|
4
|
|
|
|
|
8
|
my $inner; |
89
|
|
|
|
|
|
|
my $end; |
90
|
|
|
|
|
|
|
|
91
|
4
|
|
|
|
|
33
|
require LINQ; |
92
|
|
|
|
|
|
|
LINQ::LINQ( |
93
|
|
|
|
|
|
|
sub { |
94
|
|
|
|
|
|
|
BODY: { |
95
|
28
|
100
|
|
28
|
|
32
|
return LINQ::END() if $end; |
|
56
|
|
|
|
|
100
|
|
96
|
52
|
100
|
|
|
|
83
|
if ( not $inner ) { |
97
|
28
|
|
|
|
|
77
|
$inner = $outer->(); |
98
|
28
|
100
|
|
|
|
53
|
if ( defined $inner ) { |
99
|
24
|
|
|
|
|
39
|
local $_; |
100
|
24
|
|
|
|
|
58
|
$inner = $map->( $_ = $inner )->$_coerce->to_iterator; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
else { |
103
|
4
|
|
|
|
|
9
|
$end = 1; |
104
|
4
|
|
|
|
|
5
|
redo BODY; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
} #/ if ( not $inner ) |
107
|
48
|
|
|
|
|
98
|
my @got = $inner->(); |
108
|
48
|
100
|
|
|
|
88
|
if ( not @got ) { |
109
|
24
|
|
|
|
|
70
|
undef $inner; |
110
|
24
|
|
|
|
|
40
|
redo BODY; |
111
|
|
|
|
|
|
|
} |
112
|
24
|
|
|
|
|
57
|
return @got; |
113
|
|
|
|
|
|
|
} #/ BODY: |
114
|
|
|
|
|
|
|
} |
115
|
4
|
|
|
|
|
39
|
); |
116
|
|
|
|
|
|
|
} #/ sub select_many |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub min { |
119
|
6
|
|
|
6
|
1
|
10
|
my $self = shift; |
120
|
6
|
100
|
|
|
|
18
|
return $self->select( @_ )->min if @_; |
121
|
4
|
|
|
|
|
21
|
require List::Util; |
122
|
4
|
|
|
|
|
10
|
&List::Util::min( $self->to_list ); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub max { |
126
|
6
|
|
|
6
|
1
|
11
|
my $self = shift; |
127
|
6
|
100
|
|
|
|
22
|
return $self->select( @_ )->max if @_; |
128
|
4
|
|
|
|
|
27
|
require List::Util; |
129
|
4
|
|
|
|
|
13
|
&List::Util::max( $self->to_list ); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub sum { |
133
|
12
|
|
|
12
|
1
|
23
|
my $self = shift; |
134
|
12
|
100
|
|
|
|
41
|
return $self->select( @_ )->sum if @_; |
135
|
8
|
|
|
|
|
57
|
require List::Util; |
136
|
8
|
|
|
|
|
26
|
&List::Util::sum( $self->to_list ); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub average { |
140
|
4
|
|
|
4
|
1
|
8
|
my $self = shift; |
141
|
4
|
|
|
|
|
13
|
$self->sum( @_ ) / $self->count(); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub aggregate { |
145
|
5
|
|
|
5
|
1
|
12
|
my $self = shift; |
146
|
5
|
|
|
|
|
11
|
my $code = LINQ::Util::Internal::assert_code( shift ); |
147
|
5
|
|
|
11
|
|
14
|
my $wrapper = sub { $code->( $a, $b ) }; |
|
11
|
|
|
|
|
52
|
|
148
|
5
|
|
|
|
|
24
|
require List::Util; |
149
|
5
|
|
|
|
|
13
|
&List::Util::reduce( $wrapper, @_, $self->to_list ); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
my $_prepare_join = sub { |
153
|
|
|
|
|
|
|
my $x = shift; |
154
|
|
|
|
|
|
|
my $y = shift; |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
my $hint = ref( $_[0] ) ? -inner : shift( @_ ); |
157
|
|
|
|
|
|
|
my $x_keys = LINQ::Util::Internal::assert_code( shift ); |
158
|
|
|
|
|
|
|
my $y_keys = LINQ::Util::Internal::assert_code( shift ); |
159
|
|
|
|
|
|
|
my $joiner = LINQ::Util::Internal::assert_code( @_ ); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
$hint =~ /\A-(inner|left|right|outer)\z/ |
162
|
|
|
|
|
|
|
or LINQ::Util::Internal::throw( |
163
|
|
|
|
|
|
|
"CallerError", |
164
|
|
|
|
|
|
|
message => "Expected a recognized join type; got '$hint'" |
165
|
|
|
|
|
|
|
); |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
my @x_mapped = |
168
|
|
|
|
|
|
|
$x->select( sub { [ scalar( $x_keys->( $_[0] ) ), $_[0] ] } )->to_list; |
169
|
|
|
|
|
|
|
my @y_mapped = |
170
|
|
|
|
|
|
|
$y->select( sub { [ scalar( $y_keys->( $_[0] ) ), $_[0] ] } )->to_list; |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
return ( \@x_mapped, \@y_mapped, $hint, $joiner ); |
173
|
|
|
|
|
|
|
}; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub join { |
176
|
9
|
|
|
9
|
1
|
33
|
my ( $x_mapped, $y_mapped, $hint, $joiner ) = $_prepare_join->( @_ ); |
177
|
|
|
|
|
|
|
|
178
|
9
|
|
|
|
|
15
|
my @joined; |
179
|
9
|
|
|
|
|
16
|
my ( @found_x, @found_y ); |
180
|
|
|
|
|
|
|
|
181
|
9
|
|
|
|
|
25
|
for my $Xi ( 0 .. $#$x_mapped ) { |
182
|
43
|
|
|
|
|
66
|
my $X = $x_mapped->[$Xi]; |
183
|
|
|
|
|
|
|
|
184
|
43
|
|
|
|
|
69
|
for my $Yi ( 0 .. $#$y_mapped ) { |
185
|
249
|
|
|
|
|
2238
|
my $Y = $y_mapped->[$Yi]; |
186
|
|
|
|
|
|
|
|
187
|
249
|
100
|
|
|
|
506
|
if ( $X->[0] eq $Y->[0] ) { |
188
|
43
|
|
|
|
|
51
|
my $a = $X->[1]; |
189
|
43
|
|
|
|
|
48
|
my $b = $Y->[1]; |
190
|
43
|
|
|
|
|
52
|
$found_x[$Xi]++; |
191
|
43
|
|
|
|
|
64
|
$found_y[$Yi]++; |
192
|
|
|
|
|
|
|
|
193
|
43
|
|
|
|
|
82
|
push @joined, scalar $joiner->( $a, $b ); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
} #/ for my $Yi ( 0 .. $#$y_mapped) |
196
|
|
|
|
|
|
|
} #/ for my $Xi ( 0 .. $#$x_mapped) |
197
|
|
|
|
|
|
|
|
198
|
9
|
100
|
100
|
|
|
49
|
if ( $hint eq -left or $hint eq -outer ) { |
199
|
4
|
|
|
|
|
11
|
for my $Xi ( 0 .. $#$x_mapped ) { |
200
|
20
|
100
|
|
|
|
200
|
next if $found_x[$Xi]; |
201
|
8
|
|
|
|
|
12
|
my $a = $x_mapped->[$Xi][1]; |
202
|
8
|
|
|
|
|
11
|
my $b = undef; |
203
|
8
|
|
|
|
|
16
|
push @joined, scalar $joiner->( $a ); |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
9
|
100
|
100
|
|
|
34
|
if ( $hint eq -right or $hint eq -outer ) { |
208
|
4
|
|
|
|
|
9
|
for my $Yi ( 0 .. $#$y_mapped ) { |
209
|
24
|
100
|
|
|
|
40
|
next if $found_y[$Yi]; |
210
|
4
|
|
|
|
|
5
|
my $a = undef; |
211
|
4
|
|
|
|
|
6
|
my $b = $y_mapped->[$Yi][1]; |
212
|
4
|
|
|
|
|
10
|
push @joined, scalar $joiner->( undef, $b ); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
9
|
|
|
|
|
153
|
LINQ::Util::Internal::create_linq( \@joined ); |
217
|
|
|
|
|
|
|
} #/ sub join |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub group_join { |
220
|
9
|
|
|
9
|
1
|
51
|
my ( $x_mapped, $y_mapped, $hint, $joiner ) = $_prepare_join->( @_ ); |
221
|
|
|
|
|
|
|
|
222
|
9
|
100
|
|
|
|
60
|
$hint =~ /\A-(left|inner)\z/ or LINQ::Util::Internal::throw( |
223
|
|
|
|
|
|
|
"CallerError", |
224
|
|
|
|
|
|
|
message => "Join type '$hint' not supported for group_join", |
225
|
|
|
|
|
|
|
); |
226
|
|
|
|
|
|
|
|
227
|
5
|
|
|
|
|
10
|
my @joined; |
228
|
5
|
|
|
|
|
7
|
my ( @found_x, @found_y ); |
229
|
|
|
|
|
|
|
|
230
|
5
|
|
|
|
|
31
|
for my $Xi ( 0 .. $#$x_mapped ) { |
231
|
23
|
|
|
|
|
157
|
my $X = $x_mapped->[$Xi]; |
232
|
23
|
|
|
|
|
130
|
my @group = map $_->[1], grep $X->[0] eq $_->[0], @$y_mapped; |
233
|
|
|
|
|
|
|
|
234
|
23
|
100
|
100
|
|
|
69
|
if ( @group or $hint eq -left ) { |
235
|
19
|
|
|
|
|
24
|
my $a = $X->[1]; |
236
|
19
|
|
|
|
|
45
|
my $b = LINQ::Util::Internal::create_linq( \@group ); |
237
|
19
|
|
|
|
|
42
|
push @joined, scalar $joiner->( $a, $b ); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
} #/ for my $Xi ( 0 .. $#$x_mapped) |
240
|
|
|
|
|
|
|
|
241
|
5
|
|
|
|
|
46
|
LINQ::Util::Internal::create_linq( \@joined ); |
242
|
|
|
|
|
|
|
} #/ sub group_join |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
sub take { |
245
|
13
|
|
|
13
|
1
|
42
|
my $self = shift; |
246
|
13
|
|
|
|
|
25
|
my ( $n ) = @_; |
247
|
13
|
|
|
66
|
|
68
|
$self->take_while( sub { $n-- > 0 } ); |
|
66
|
|
|
|
|
212
|
|
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub take_while { |
251
|
21
|
|
|
21
|
1
|
56
|
my $self = shift; |
252
|
21
|
|
|
|
|
61
|
my $filter = LINQ::Util::Internal::assert_code( @_ ); |
253
|
21
|
|
|
|
|
37
|
my $stopped = 0; |
254
|
21
|
|
|
|
|
53
|
my $iter = $self->to_iterator; |
255
|
|
|
|
|
|
|
|
256
|
21
|
|
|
|
|
117
|
require LINQ; |
257
|
|
|
|
|
|
|
LINQ::LINQ( |
258
|
|
|
|
|
|
|
sub { |
259
|
|
|
|
|
|
|
# uncoverable branch true |
260
|
100
|
50
|
|
100
|
|
187
|
return LINQ::END() if $stopped; |
261
|
100
|
|
|
|
|
167
|
my @got = $iter->(); |
262
|
98
|
100
|
100
|
|
|
325
|
if ( !@got or !$filter->( $_ = $got[0] ) ) { |
263
|
19
|
|
|
|
|
61
|
$stopped++; |
264
|
19
|
|
|
|
|
55
|
return LINQ::END(); |
265
|
|
|
|
|
|
|
} |
266
|
79
|
|
|
|
|
654
|
return $got[0]; |
267
|
|
|
|
|
|
|
} |
268
|
21
|
|
|
|
|
141
|
); |
269
|
|
|
|
|
|
|
} #/ sub take_while |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub skip { |
272
|
8
|
|
|
8
|
1
|
24
|
my $self = shift; |
273
|
8
|
|
|
|
|
15
|
my ( $n ) = @_; |
274
|
8
|
|
|
24
|
|
48
|
$self->skip_while( sub { $n-- > 0 } ); |
|
24
|
|
|
|
|
62
|
|
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
sub skip_while { |
278
|
14
|
|
|
14
|
1
|
40
|
my $self = shift; |
279
|
14
|
|
|
|
|
42
|
my $filter = LINQ::Util::Internal::assert_code( @_ ); |
280
|
14
|
|
|
|
|
23
|
my $stopped = 0; |
281
|
14
|
|
|
|
|
22
|
my $started = 0; |
282
|
14
|
|
|
|
|
32
|
my $iter = $self->to_iterator; |
283
|
|
|
|
|
|
|
|
284
|
14
|
|
|
|
|
76
|
require LINQ; |
285
|
|
|
|
|
|
|
LINQ::LINQ( |
286
|
|
|
|
|
|
|
sub { |
287
|
|
|
|
|
|
|
SKIPPING: { |
288
|
76
|
100
|
|
76
|
|
127
|
return LINQ::END() if $stopped; |
|
118
|
|
|
|
|
215
|
|
289
|
104
|
|
|
|
|
190
|
my @got = $iter->(); |
290
|
104
|
100
|
|
|
|
188
|
if ( !@got ) { |
291
|
14
|
|
|
|
|
33
|
$stopped++; |
292
|
14
|
|
|
|
|
29
|
redo SKIPPING; |
293
|
|
|
|
|
|
|
} |
294
|
90
|
100
|
|
|
|
213
|
return $got[0] if $started; |
295
|
40
|
100
|
|
|
|
79
|
if ( $filter->( $_ = $got[0] ) ) { |
296
|
28
|
|
|
|
|
70
|
redo SKIPPING; |
297
|
|
|
|
|
|
|
} |
298
|
12
|
|
|
|
|
43
|
++$started; |
299
|
12
|
|
|
|
|
41
|
return $got[0]; |
300
|
|
|
|
|
|
|
} #/ SKIPPING: |
301
|
|
|
|
|
|
|
} |
302
|
14
|
|
|
|
|
88
|
); |
303
|
|
|
|
|
|
|
} #/ sub skip_while |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub concat { |
306
|
12
|
|
|
12
|
1
|
45
|
my @collections = map $_->to_iterator, @_; |
307
|
12
|
|
|
|
|
23
|
my $idx = 0; |
308
|
|
|
|
|
|
|
|
309
|
12
|
|
|
|
|
49
|
require LINQ; |
310
|
|
|
|
|
|
|
LINQ::LINQ( |
311
|
|
|
|
|
|
|
sub { |
312
|
|
|
|
|
|
|
FIND_NEXT: { |
313
|
100
|
100
|
|
100
|
|
124
|
return LINQ::END() if not @collections; |
|
121
|
|
|
|
|
245
|
|
314
|
|
|
|
|
|
|
|
315
|
111
|
|
|
|
|
201
|
my @got = $collections[0]->(); |
316
|
111
|
100
|
|
|
|
202
|
if ( not @got ) { |
317
|
21
|
|
|
|
|
30
|
shift @collections; |
318
|
21
|
|
|
|
|
69
|
redo FIND_NEXT; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
90
|
|
|
|
|
221
|
return $got[0]; |
322
|
|
|
|
|
|
|
} #/ FIND_NEXT: |
323
|
|
|
|
|
|
|
} |
324
|
12
|
|
|
|
|
61
|
); |
325
|
|
|
|
|
|
|
} #/ sub concat |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub order_by { |
328
|
44
|
|
|
44
|
1
|
22138
|
my $self = shift; |
329
|
44
|
|
|
|
|
115
|
my ( $hint, $keygen ) = ( -numeric, undef ); |
330
|
44
|
100
|
|
|
|
131
|
if ( @_ ) { |
331
|
42
|
100
|
|
|
|
135
|
$hint = ref( $_[0] ) ? -numeric : shift( @_ ); |
332
|
42
|
100
|
|
|
|
191
|
$keygen = @_ ? LINQ::Util::Internal::assert_code( @_ ) : undef; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
|
335
|
44
|
100
|
|
|
|
120
|
if ( not $keygen ) { |
336
|
12
|
100
|
|
|
|
73
|
if ( $hint eq -string ) { |
|
|
100
|
|
|
|
|
|
337
|
|
|
|
|
|
|
return LINQ::Util::Internal::create_linq( |
338
|
2
|
|
|
|
|
9
|
[ sort { $a cmp $b } $self->to_list ] ); |
|
10
|
|
|
|
|
26
|
|
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
elsif ( $hint eq -numeric ) { |
341
|
|
|
|
|
|
|
return LINQ::Util::Internal::create_linq( |
342
|
8
|
|
|
|
|
31
|
[ sort { $a <=> $b } $self->to_list ] ); |
|
40
|
|
|
|
|
90
|
|
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
} #/ if ( not $keygen ) |
345
|
|
|
|
|
|
|
|
346
|
34
|
100
|
|
|
|
121
|
if ( $hint eq -string ) { |
|
|
100
|
|
|
|
|
|
347
|
|
|
|
|
|
|
return LINQ::Util::Internal::create_linq( |
348
|
|
|
|
|
|
|
[ |
349
|
|
|
|
|
|
|
map $_->[1], |
350
|
18
|
|
|
|
|
79
|
sort { $a->[0] cmp $b->[0] } |
|
118
|
|
|
|
|
488
|
|
351
|
|
|
|
|
|
|
map [ $keygen->( $_ ), $_ ], |
352
|
|
|
|
|
|
|
$self->to_list |
353
|
|
|
|
|
|
|
] |
354
|
|
|
|
|
|
|
); |
355
|
|
|
|
|
|
|
} #/ if ( $hint eq -string ) |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
elsif ( $hint eq -numeric ) { |
358
|
|
|
|
|
|
|
return LINQ::Util::Internal::create_linq( |
359
|
|
|
|
|
|
|
[ |
360
|
|
|
|
|
|
|
map $_->[1], |
361
|
14
|
|
|
|
|
47
|
sort { $a->[0] <=> $b->[0] } |
|
86
|
|
|
|
|
491
|
|
362
|
|
|
|
|
|
|
map [ $keygen->( $_ ), $_ ], |
363
|
|
|
|
|
|
|
$self->to_list |
364
|
|
|
|
|
|
|
] |
365
|
|
|
|
|
|
|
); |
366
|
|
|
|
|
|
|
} #/ elsif ( $hint eq -numeric) |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
LINQ::Util::Internal::throw( |
369
|
2
|
|
|
|
|
20
|
"CallerError", |
370
|
|
|
|
|
|
|
message => "Expected '-numeric' or '-string'; got '$hint'" |
371
|
|
|
|
|
|
|
); |
372
|
|
|
|
|
|
|
} #/ sub order_by |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub then_by { |
375
|
2
|
|
|
2
|
1
|
10
|
LINQ::Util::Internal::throw( "Unimplemented", method => "then_by" ); |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
sub order_by_descending { |
379
|
6
|
|
|
6
|
1
|
31
|
my $self = shift; |
380
|
6
|
|
|
|
|
21
|
$self->order_by( @_ )->reverse; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub then_by_descending { |
384
|
2
|
|
|
2
|
1
|
19
|
LINQ::Util::Internal::throw( "Unimplemented", method => "then_by_descending" ); |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
sub reverse { |
388
|
8
|
|
|
8
|
1
|
24
|
my $self = shift; |
389
|
8
|
|
|
|
|
24
|
LINQ::Util::Internal::create_linq( |
390
|
|
|
|
|
|
|
[ reverse( $self->to_list ) ], |
391
|
|
|
|
|
|
|
); |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub group_by { |
395
|
2
|
|
|
2
|
1
|
15
|
my $self = shift; |
396
|
2
|
|
|
|
|
4
|
my $keygen = LINQ::Util::Internal::assert_code( @_ ); |
397
|
|
|
|
|
|
|
|
398
|
2
|
|
|
|
|
4
|
my @keys; |
399
|
|
|
|
|
|
|
my %values; |
400
|
|
|
|
|
|
|
|
401
|
2
|
|
|
|
|
5
|
for ( $self->to_list ) { |
402
|
20
|
|
|
|
|
30
|
my $key = $keygen->( $_ ); |
403
|
20
|
100
|
|
|
|
60
|
unless ( $values{$key} ) { |
404
|
6
|
|
|
|
|
10
|
push @keys, $key; |
405
|
6
|
|
|
|
|
12
|
$values{$key} = []; |
406
|
|
|
|
|
|
|
} |
407
|
20
|
|
|
|
|
21
|
push @{ $values{$key} }, $_; |
|
20
|
|
|
|
|
30
|
|
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
|
410
|
2
|
|
|
|
|
808
|
require LINQ::Grouping; |
411
|
|
|
|
|
|
|
LINQ::Util::Internal::create_linq( |
412
|
|
|
|
|
|
|
[ |
413
|
|
|
|
|
|
|
map 'LINQ::Grouping'->new( |
414
|
|
|
|
|
|
|
key => $_, |
415
|
2
|
|
|
|
|
11
|
values => LINQ::Util::Internal::create_linq( $values{$_} ), |
416
|
|
|
|
|
|
|
), |
417
|
|
|
|
|
|
|
@keys |
418
|
|
|
|
|
|
|
] |
419
|
|
|
|
|
|
|
); |
420
|
|
|
|
|
|
|
} #/ sub group_by |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
sub distinct { |
423
|
8
|
|
|
8
|
1
|
17
|
my $self = shift; |
424
|
|
|
|
|
|
|
my $compare = |
425
|
8
|
100
|
|
36
|
|
55
|
@_ ? LINQ::Util::Internal::assert_code( @_ ) : sub { $_[0] == $_[1] }; |
|
36
|
|
|
|
|
88
|
|
426
|
|
|
|
|
|
|
|
427
|
8
|
|
|
|
|
14
|
my @already; |
428
|
|
|
|
|
|
|
$self->where( |
429
|
|
|
|
|
|
|
sub { |
430
|
46
|
|
|
46
|
|
58
|
my $maybe = $_[0]; |
431
|
46
|
|
|
|
|
70
|
for my $got ( @already ) { |
432
|
86
|
100
|
|
|
|
245
|
return !!0 if $compare->( $maybe, $got ); |
433
|
|
|
|
|
|
|
} |
434
|
34
|
|
|
|
|
170
|
push @already, $maybe; |
435
|
34
|
|
|
|
|
59
|
return !!1; |
436
|
|
|
|
|
|
|
} |
437
|
8
|
|
|
|
|
32
|
); |
438
|
|
|
|
|
|
|
} #/ sub distinct |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
sub union { |
441
|
4
|
|
|
4
|
1
|
23
|
my $self = shift; |
442
|
4
|
|
|
|
|
9
|
my ( $other, @compare ) = @_; |
443
|
4
|
|
|
|
|
23
|
$self->concat( $other )->distinct( @compare ); |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
sub intersect { |
447
|
4
|
|
|
4
|
1
|
16
|
my $self = shift; |
448
|
4
|
|
|
|
|
6
|
my $other = shift; |
449
|
|
|
|
|
|
|
my @compare = |
450
|
4
|
100
|
|
12
|
|
16
|
@_ ? LINQ::Util::Internal::assert_code( @_ ) : sub { $_[0] == $_[1] }; |
|
12
|
|
|
|
|
22
|
|
451
|
4
|
|
|
10
|
|
22
|
$self->where( sub { $other->contains( $_, @compare ) } ); |
|
10
|
|
|
|
|
30
|
|
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
sub except { |
455
|
4
|
|
|
4
|
1
|
20
|
my $self = shift; |
456
|
4
|
|
|
|
|
6
|
my $other = shift; |
457
|
|
|
|
|
|
|
my @compare = |
458
|
4
|
100
|
|
12
|
|
21
|
@_ ? LINQ::Util::Internal::assert_code( @_ ) : sub { $_[0] == $_[1] }; |
|
12
|
|
|
|
|
22
|
|
459
|
4
|
|
|
10
|
|
35
|
$self->where( sub { not $other->contains( $_, @compare ) } ); |
|
10
|
|
|
|
|
27
|
|
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
sub sequence_equal { |
463
|
18
|
|
|
18
|
1
|
54
|
my $self = shift; |
464
|
18
|
|
|
|
|
34
|
my ( $other, @compare ) = @_; |
465
|
|
|
|
|
|
|
|
466
|
18
|
|
|
|
|
27
|
my $compare; |
467
|
18
|
100
|
|
|
|
44
|
if ( @compare ) { |
468
|
12
|
|
|
|
|
31
|
$compare = LINQ::Util::Internal::assert_code( @compare ); |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
18
|
|
|
|
|
40
|
my $iter1 = $self->to_iterator; |
472
|
18
|
|
|
|
|
36
|
my $iter2 = $other->to_iterator; |
473
|
|
|
|
|
|
|
|
474
|
18
|
|
|
|
|
566
|
while ( 1 ) { |
475
|
114
|
|
|
|
|
329
|
my @got1 = $iter1->(); |
476
|
114
|
|
|
|
|
179
|
my @got2 = $iter2->(); |
477
|
|
|
|
|
|
|
|
478
|
114
|
100
|
|
|
|
218
|
if ( not @got1 ) { |
|
|
100
|
|
|
|
|
|
479
|
10
|
100
|
|
|
|
17
|
if ( @got2 ) { |
480
|
4
|
|
|
|
|
29
|
return !!0; |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
else { |
483
|
6
|
|
|
|
|
50
|
return !!1; |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
elsif ( not @got2 ) { |
487
|
2
|
|
|
|
|
14
|
return !!0; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
102
|
100
|
|
|
|
154
|
if ( $compare ) { |
491
|
60
|
100
|
|
|
|
108
|
return !!0 unless $compare->( $got1[0], $got2[0] ); |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
else { |
494
|
42
|
100
|
|
|
|
95
|
return !!0 unless $got1[0] == $got2[0]; |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
} #/ while ( 1 ) |
497
|
|
|
|
|
|
|
} #/ sub sequence_equal |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
my $_with_default = sub { |
500
|
|
|
|
|
|
|
my $self = shift; |
501
|
|
|
|
|
|
|
my $method = shift; |
502
|
|
|
|
|
|
|
my @args = @_; |
503
|
|
|
|
|
|
|
my $default = pop( @args ); |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
my $return; |
506
|
|
|
|
|
|
|
eval { $return = $self->$method( @args ); 1 } or do { |
507
|
|
|
|
|
|
|
my $e = $@; # catch |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
# Rethrow any non-blessed errors. |
510
|
|
|
|
|
|
|
require Scalar::Util; |
511
|
|
|
|
|
|
|
die( $e ) unless Scalar::Util::blessed( $e ); |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# Rethrow any errors of the wrong class. |
514
|
|
|
|
|
|
|
die( $e ) |
515
|
|
|
|
|
|
|
unless $e->isa( 'LINQ::Exception::NotFound' ) |
516
|
|
|
|
|
|
|
|| $e->isa( 'LINQ::Exception::MultipleFound' ); |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
# Rethrow any errors which resulted from the wrong source. |
519
|
|
|
|
|
|
|
die( $e ) unless $e->collection == $self; |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
return $default; |
522
|
|
|
|
|
|
|
}; |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
return $return; |
525
|
|
|
|
|
|
|
}; |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
sub first { |
528
|
13
|
|
|
13
|
1
|
21
|
my $self = shift; |
529
|
13
|
100
|
|
|
|
46
|
my $found = @_ ? $self->where( @_ ) : $self; |
530
|
13
|
100
|
|
|
|
33
|
return $found->element_at( 0 ) if $found->count > 0; |
531
|
4
|
|
|
|
|
17
|
LINQ::Util::Internal::throw( 'NotFound', collection => $self ); |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
sub first_or_default { |
535
|
6
|
|
|
6
|
1
|
142
|
shift->$_with_default( first => @_ ); |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
sub last { |
539
|
13
|
|
|
13
|
1
|
52
|
my $self = shift; |
540
|
13
|
100
|
|
|
|
63
|
my $found = @_ ? $self->where( @_ ) : $self; |
541
|
13
|
100
|
|
|
|
35
|
return $found->element_at( -1 ) if $found->count > 0; |
542
|
4
|
|
|
|
|
16
|
LINQ::Util::Internal::throw( 'NotFound', collection => $self ); |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
sub last_or_default { |
546
|
6
|
|
|
6
|
1
|
167
|
shift->$_with_default( last => @_ ); |
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
sub single { |
550
|
32
|
|
|
32
|
1
|
339
|
my $self = shift; |
551
|
32
|
100
|
|
|
|
126
|
my $found = @_ ? $self->where( @_ ) : $self; |
552
|
32
|
100
|
|
|
|
94
|
return $found->element_at( 0 ) if $found->count == 1; |
553
|
8
|
100
|
|
|
|
25
|
$found->count == 0 |
554
|
|
|
|
|
|
|
? LINQ::Util::Internal::throw( 'NotFound', collection => $self ) |
555
|
|
|
|
|
|
|
: LINQ::Util::Internal::throw( 'MultipleFound', collection => $self, |
556
|
|
|
|
|
|
|
found => $found ); |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
sub single_or_default { |
560
|
8
|
|
|
8
|
1
|
258
|
shift->$_with_default( single => @_ ); |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
sub element_at { |
564
|
60
|
|
|
60
|
1
|
114
|
my $self = shift; |
565
|
60
|
|
|
|
|
107
|
my ( $i ) = @_; |
566
|
|
|
|
|
|
|
|
567
|
60
|
|
|
|
|
185
|
my @list = $self->to_list; |
568
|
|
|
|
|
|
|
|
569
|
60
|
100
|
|
|
|
172
|
if ( $i > $#list ) { |
570
|
2
|
|
|
|
|
11
|
LINQ::Util::Internal::throw( 'NotFound', collection => $self ); |
571
|
|
|
|
|
|
|
} |
572
|
|
|
|
|
|
|
|
573
|
58
|
100
|
|
|
|
174
|
if ( $i < 0 - @list ) { |
574
|
2
|
|
|
|
|
10
|
LINQ::Util::Internal::throw( 'NotFound', collection => $self ); |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
56
|
|
|
|
|
408
|
$list[$i]; |
578
|
|
|
|
|
|
|
} #/ sub element_at |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
sub element_at_or_default { |
581
|
24
|
|
|
24
|
1
|
52
|
shift->$_with_default( element_at => @_ ); |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
sub any { |
585
|
32
|
|
|
32
|
1
|
60
|
my $self = shift; |
586
|
32
|
100
|
|
|
|
114
|
my $iter = @_ ? $self->where( @_ )->to_iterator : $self->to_iterator; |
587
|
32
|
|
|
|
|
133
|
my @got = $iter->(); |
588
|
32
|
|
|
|
|
363
|
!!scalar @got; |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
sub all { |
592
|
8
|
|
|
8
|
1
|
32
|
my $self = shift; |
593
|
8
|
|
|
|
|
20
|
my $check = LINQ::Util::Internal::assert_code( @_ ); |
594
|
8
|
|
|
15
|
|
27
|
my $iter = $self->where( sub { not $check->( $_ ) } )->to_iterator; |
|
15
|
|
|
|
|
76
|
|
595
|
8
|
|
|
|
|
33
|
my @got = $iter->(); |
596
|
8
|
|
|
|
|
118
|
!scalar @got; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
sub contains { |
600
|
31
|
|
|
31
|
1
|
48
|
my $self = shift; |
601
|
31
|
|
|
|
|
81
|
my ( $x, @args ) = @_; |
602
|
|
|
|
|
|
|
|
603
|
31
|
100
|
|
|
|
67
|
if ( @args ) { |
604
|
24
|
|
|
|
|
51
|
splice( @args, 1, 0, $x ); |
605
|
24
|
|
|
|
|
66
|
return $self->any( LINQ::Util::Internal::assert_code( @args ) ); |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
|
608
|
7
|
|
|
|
|
34
|
my $iter = $self->to_iterator; |
609
|
7
|
|
|
|
|
13
|
while ( 1 ) { |
610
|
187
|
100
|
|
|
|
284
|
my @got = $iter->() or return !!0; |
611
|
184
|
100
|
|
|
|
392
|
return !!1 if $got[0] == $x; |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
} #/ sub contains |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
sub count { |
616
|
98
|
|
|
98
|
1
|
359
|
my $self = shift; |
617
|
98
|
100
|
|
|
|
246
|
return $self->where( @_ )->count if @_; |
618
|
97
|
|
|
|
|
250
|
my @list = $self->to_list; |
619
|
91
|
|
|
|
|
427
|
return scalar( @list ); |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
sub to_array { |
623
|
57
|
|
|
57
|
1
|
17117
|
my $self = shift; |
624
|
57
|
|
|
|
|
130
|
[ $self->to_list ]; |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
sub to_dictionary { |
628
|
4
|
|
|
4
|
1
|
9
|
my $self = shift; |
629
|
4
|
|
|
|
|
11
|
my ( $keygen ) = LINQ::Util::Internal::assert_code( @_ ); |
630
|
4
|
|
|
|
|
14
|
+{ map +( $keygen->( $_ ), $_ ), $self->to_list }; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
sub to_lookup { |
634
|
2
|
|
|
2
|
1
|
4
|
my $self = shift; |
635
|
2
|
|
|
|
|
5
|
$self->to_dictionary( @_ ); |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
sub to_iterator { |
639
|
184
|
|
|
184
|
1
|
289
|
my $self = shift; |
640
|
184
|
|
|
|
|
459
|
my @list = $self->to_list; |
641
|
184
|
100
|
|
1004
|
|
644
|
sub { @list ? shift( @list ) : () }; |
|
1004
|
|
|
|
|
2245
|
|
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
sub cast { |
645
|
6
|
|
|
6
|
1
|
47376
|
my $self = shift; |
646
|
6
|
|
|
|
|
17
|
my ( $type ) = @_; |
647
|
|
|
|
|
|
|
|
648
|
6
|
|
|
|
|
30
|
my $cast = $self->of_type( @_ ); |
649
|
6
|
100
|
|
|
|
24
|
return $cast if $self->count == $cast->count; |
650
|
|
|
|
|
|
|
|
651
|
4
|
|
|
|
|
19
|
LINQ::Util::Internal::throw( "Cast", collection => $self, type => $type ); |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
sub of_type { |
655
|
22
|
|
|
22
|
1
|
5920
|
my $self = shift; |
656
|
22
|
|
|
|
|
43
|
my ( $type ) = @_; |
657
|
|
|
|
|
|
|
|
658
|
22
|
|
|
|
|
133
|
require Scalar::Util; |
659
|
|
|
|
|
|
|
|
660
|
22
|
100
|
100
|
|
|
193
|
unless ( Scalar::Util::blessed( $type ) and $type->can( 'check' ) ) { |
661
|
8
|
|
|
|
|
39
|
LINQ::Util::Internal::throw( |
662
|
|
|
|
|
|
|
"CallerError", |
663
|
|
|
|
|
|
|
message => "Expected type constraint; got '$type'", |
664
|
|
|
|
|
|
|
); |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
|
667
|
14
|
100
|
|
|
|
266
|
if ( $type->isa( 'Type::Tiny' ) ) { |
668
|
10
|
|
|
|
|
137
|
my $check = $type->compiled_check; |
669
|
|
|
|
|
|
|
|
670
|
10
|
100
|
|
|
|
206
|
if ( $type->has_coercion ) { |
671
|
6
|
|
|
|
|
77
|
my $coercion = $type->coercion->compiled_coercion; |
672
|
6
|
|
|
|
|
5868
|
return $self->select( $coercion )->where( $check ); |
673
|
|
|
|
|
|
|
} |
674
|
|
|
|
|
|
|
|
675
|
4
|
|
|
|
|
191
|
return $self->where( $check ); |
676
|
|
|
|
|
|
|
} #/ if ( $type->isa( 'Type::Tiny'...)) |
677
|
|
|
|
|
|
|
|
678
|
4
|
50
|
33
|
|
|
35
|
if ( $type->can( 'has_coercion' ) and $type->has_coercion ) { |
679
|
|
|
|
|
|
|
return $self |
680
|
0
|
|
|
0
|
|
0
|
->select( sub { $type->coerce( $_ ) } ) |
681
|
0
|
|
|
0
|
|
0
|
->where( sub { $type->check( $_ ) } ); |
|
0
|
|
|
|
|
0
|
|
682
|
|
|
|
|
|
|
} |
683
|
|
|
|
|
|
|
|
684
|
4
|
|
|
36
|
|
18
|
return $self->where( sub { $type->check( $_ ) } ); |
|
36
|
|
|
|
|
67
|
|
685
|
|
|
|
|
|
|
} #/ sub of_type |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
sub zip { |
688
|
4
|
|
|
4
|
1
|
24
|
my $self = shift; |
689
|
4
|
|
|
|
|
6
|
my $other = shift; |
690
|
4
|
|
|
|
|
12
|
my $map = LINQ::Util::Internal::assert_code( @_ ); |
691
|
|
|
|
|
|
|
|
692
|
4
|
|
|
|
|
13
|
my $iter1 = $self->to_iterator; |
693
|
4
|
|
|
|
|
10
|
my $iter2 = $other->to_iterator; |
694
|
4
|
|
|
|
|
10
|
my @results; |
695
|
|
|
|
|
|
|
|
696
|
4
|
|
|
|
|
17
|
require LINQ; |
697
|
|
|
|
|
|
|
LINQ::LINQ( |
698
|
|
|
|
|
|
|
sub { |
699
|
44
|
|
|
44
|
|
80
|
my @r1 = $iter1->(); |
700
|
44
|
|
|
|
|
68
|
my @r2 = $iter2->(); |
701
|
44
|
100
|
100
|
|
|
134
|
return LINQ::END() unless @r1 && @r2; |
702
|
40
|
|
|
|
|
81
|
$map->( $r1[0], $r2[0] ); |
703
|
|
|
|
|
|
|
} |
704
|
4
|
|
|
|
|
34
|
); |
705
|
|
|
|
|
|
|
} #/ sub zip |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
sub default_if_empty { |
708
|
4
|
|
|
4
|
1
|
21
|
my $self = shift; |
709
|
4
|
|
|
|
|
8
|
my $item = shift; |
710
|
|
|
|
|
|
|
|
711
|
4
|
100
|
|
|
|
10
|
if ( $self->count == 0 ) { |
712
|
2
|
|
|
|
|
11
|
return LINQ::Util::Internal::create_linq( [$item] ); |
713
|
|
|
|
|
|
|
} |
714
|
|
|
|
|
|
|
|
715
|
2
|
|
|
|
|
8
|
return $self; |
716
|
|
|
|
|
|
|
} #/ sub default_if_empty |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
sub foreach { |
719
|
9
|
|
|
9
|
1
|
5141
|
my $self = shift; |
720
|
9
|
|
|
|
|
35
|
my $code = LINQ::Util::Internal::assert_code( @_ ); |
721
|
|
|
|
|
|
|
|
722
|
9
|
|
|
|
|
20
|
my $ok = eval { |
723
|
9
|
|
|
|
|
17
|
local $LINQ::IN_LOOP = 1; |
724
|
9
|
|
|
234
|
|
40
|
$self->where( sub { $code->( $_ ); 0 } )->to_list; |
|
234
|
|
|
|
|
445
|
|
|
227
|
|
|
|
|
587
|
|
725
|
2
|
|
|
|
|
19
|
1; |
726
|
|
|
|
|
|
|
}; |
727
|
9
|
100
|
|
|
|
134
|
if ( not $ok ) { |
728
|
7
|
|
|
|
|
14
|
my $e = $@; |
729
|
7
|
|
|
|
|
37
|
require Scalar::Util; |
730
|
7
|
100
|
|
|
|
42
|
die( $e ) unless Scalar::Util::blessed( $e ); |
731
|
5
|
100
|
|
|
|
66
|
die( $e ) unless $e->isa( 'LINQ::LAST' ); |
732
|
|
|
|
|
|
|
} |
733
|
5
|
|
|
|
|
13
|
return; |
734
|
|
|
|
|
|
|
} #/ sub foreach |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
1; |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
__END__ |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
=pod |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=encoding utf-8 |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
=head1 NAME |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
LINQ - the interface which all LINQ collections share |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=head1 SYNOPSIS |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
use feature 'say'; |
751
|
|
|
|
|
|
|
use LINQ 'LINQ'; |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
my $double_even_numbers = |
754
|
|
|
|
|
|
|
LINQ( [1..100] ) |
755
|
|
|
|
|
|
|
->where( sub { $_ % 2 == 0 } ) |
756
|
|
|
|
|
|
|
->select( sub { $_ * 2 } ); |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
if ( not $double_even_numbers->DOES( 'LINQ::Collection' ) ) { |
759
|
|
|
|
|
|
|
die "What? But you said they all do it!"; |
760
|
|
|
|
|
|
|
} |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
for my $n ( $double_even_numbers->to_list ) { |
763
|
|
|
|
|
|
|
say $n; |
764
|
|
|
|
|
|
|
} |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
=head1 DESCRIPTION |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
Objects returned by the C<< LINQ() >>, C<< LINQ::Repeat() >>, and |
769
|
|
|
|
|
|
|
C<< LINQ::Range() >> functions all provide the LINQ::Collection interface. |
770
|
|
|
|
|
|
|
Many of the methods in this interface also return new objects which provide |
771
|
|
|
|
|
|
|
this interface. |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=head1 METHODS |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
Many methods take a parameter "CALLABLE". This means they can accept a |
776
|
|
|
|
|
|
|
coderef, an object overloading C<< &{} >>, or an arrayref where the first |
777
|
|
|
|
|
|
|
item is one of the previous two things and the remainder are treated as |
778
|
|
|
|
|
|
|
arguments to curry to the first argument. A quoted regexp C<< qr/.../ >> can |
779
|
|
|
|
|
|
|
also be used as a callable. |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
If using an arrayref, it is generally permissable to flatten it into a |
782
|
|
|
|
|
|
|
list, unless otherwise noted. An example of this can be seen in the |
783
|
|
|
|
|
|
|
documentation for C<select>. |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
=over |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
=item C<< select( CALLABLE ) >> |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
LINQ's version of C<map>, except that the code given is always called in |
790
|
|
|
|
|
|
|
scalar context, being expected to return exactly one result. |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
Returns a LINQ::Collection of the results. |
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
my $people = LINQ( [ |
795
|
|
|
|
|
|
|
{ name => "Alice", age => 32 }, |
796
|
|
|
|
|
|
|
{ name => "Bob", age => 31 }, |
797
|
|
|
|
|
|
|
{ name => "Carol", age => 34 }, |
798
|
|
|
|
|
|
|
] ); |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
my $names = $people->select( sub { |
801
|
|
|
|
|
|
|
return $_->{name}; |
802
|
|
|
|
|
|
|
} ); |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
for my $name ( $names->to_list ) { |
805
|
|
|
|
|
|
|
print "$name\n"; |
806
|
|
|
|
|
|
|
} |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
Another way of doing the same thing, using currying: |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
my $people = LINQ( [ |
811
|
|
|
|
|
|
|
{ name => "Alice", age => 32 }, |
812
|
|
|
|
|
|
|
{ name => "Bob", age => 31 }, |
813
|
|
|
|
|
|
|
{ name => "Carol", age => 34 }, |
814
|
|
|
|
|
|
|
] ); |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
my $BY_HASH_KEY = sub { |
817
|
|
|
|
|
|
|
my ($key) = @_; |
818
|
|
|
|
|
|
|
return $_->{$key}; |
819
|
|
|
|
|
|
|
}; |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
my $names = $people->select( $BY_HASH_KEY, 'name' ); |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
for my $name ( $names->to_list ) { |
824
|
|
|
|
|
|
|
print "$name\n"; |
825
|
|
|
|
|
|
|
} |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
=item C<< select_many( CALLABLE ) >> |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
If you wanted C<select> to be able to return a list like C<map> does, then |
830
|
|
|
|
|
|
|
C<select_many> is what you want. However, rather than returning a Perl list, |
831
|
|
|
|
|
|
|
your callable should return a LINQ::Collection or an arrayref. |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
=item C<< where( CALLABLE ) >> |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
LINQ's version of C<grep>. Returns a LINQ::Collection of the filtered results. |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
my $people = LINQ( [ |
838
|
|
|
|
|
|
|
{ name => "Alice", age => 32 }, |
839
|
|
|
|
|
|
|
{ name => "Bob", age => 31 }, |
840
|
|
|
|
|
|
|
{ name => "Carol", age => 34 }, |
841
|
|
|
|
|
|
|
] ); |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
my $young_people = $people->where( sub { |
844
|
|
|
|
|
|
|
return $_->{age} < 33; |
845
|
|
|
|
|
|
|
} ); |
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
=item C<< min( CALLABLE? ) >> |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
Returns the numerically lowest value in the collection. |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
my $lowest = LINQ( [ 5, 1, 2, 3 ] )->min; # ==> 1 |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
If a callable is provided, then C<select> will be called and the minimum of the |
854
|
|
|
|
|
|
|
result will be returned. |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
my $people = LINQ( [ |
857
|
|
|
|
|
|
|
{ name => "Alice", age => 32 }, |
858
|
|
|
|
|
|
|
{ name => "Bob", age => 31 }, |
859
|
|
|
|
|
|
|
{ name => "Carol", age => 34 }, |
860
|
|
|
|
|
|
|
] ); |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
my $lowest_age = $people->min( sub { $_->{age} } ); # ==> 31 |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
If you need more flexible comparison (e.g. non-numeric comparison), use |
865
|
|
|
|
|
|
|
C<order_by> followed by C<first>. |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
=item C<< max( CALLABLE? ) >> |
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
Like C<min>, but returns the numerically highest value. |
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
=item C<< sum( CALLABLE? ) >> |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
Like C<min>, but returns the sum of all values in the collection. |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
=item C<< average( CALLABLE? ) >> |
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
Takes C<sum>, and divides by the count of items in the collection. |
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
my $people = LINQ( [ |
880
|
|
|
|
|
|
|
{ name => "Alice", age => 32 }, |
881
|
|
|
|
|
|
|
{ name => "Bob", age => 31 }, |
882
|
|
|
|
|
|
|
{ name => "Carol", age => 34 }, |
883
|
|
|
|
|
|
|
] ); |
884
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
my $average_age = $people->average( sub { |
886
|
|
|
|
|
|
|
return $_->{age}; |
887
|
|
|
|
|
|
|
} ); # ==> 32.33333 |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
=item C<< aggregate( CALLABLE, INITIAL? ) >> |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
LINQ's version of C<reduce> (from L<List::Util>). We pass C<< $a >> and |
892
|
|
|
|
|
|
|
C<< $b >> as the last arguments to CALLABLE, rather than using the package |
893
|
|
|
|
|
|
|
variables like List::Util does. |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
The CALLABLE must not be a flattened list, but may still be an arrayref. |
896
|
|
|
|
|
|
|
INITIAL is an initial value. |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
my $people = LINQ( [ |
899
|
|
|
|
|
|
|
{ name => "Alice", age => 32 }, |
900
|
|
|
|
|
|
|
{ name => "Bob", age => 31 }, |
901
|
|
|
|
|
|
|
{ name => "Carol", age => 34 }, |
902
|
|
|
|
|
|
|
] ); |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
my dotted_names = $people |
905
|
|
|
|
|
|
|
->select( sub { $_->{name} } ) |
906
|
|
|
|
|
|
|
->aggregate( sub { |
907
|
|
|
|
|
|
|
my ( $a, $b ) = @_; |
908
|
|
|
|
|
|
|
return "$a.$b"; |
909
|
|
|
|
|
|
|
} ); |
910
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
print "$dotted_names\n"; # ==> Alice.Bob.Carol |
912
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
=item C<< join( Y, HINT?, X_KEYS, Y_KEYS, JOINER ) >> |
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
This is akin to an SQL join. |
916
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
my $people = LINQ( [ |
918
|
|
|
|
|
|
|
{ name => "Alice", dept => 'Marketing' }, |
919
|
|
|
|
|
|
|
{ name => "Bob", dept => 'IT' }, |
920
|
|
|
|
|
|
|
{ name => "Carol", dept => 'IT' }, |
921
|
|
|
|
|
|
|
] ); |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
my $departments = LINQ( [ |
924
|
|
|
|
|
|
|
{ dept_name => 'Accounts', cost_code => 1 }, |
925
|
|
|
|
|
|
|
{ dept_name => 'IT', cost_code => 7 }, |
926
|
|
|
|
|
|
|
{ dept_name => 'Marketing', cost_code => 8 }, |
927
|
|
|
|
|
|
|
] ); |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
my $BY_HASH_KEY = sub { |
930
|
|
|
|
|
|
|
my ($key) = @_; |
931
|
|
|
|
|
|
|
return $_->{$key}; |
932
|
|
|
|
|
|
|
}; |
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
my $joined = $people->join( |
935
|
|
|
|
|
|
|
$departments, |
936
|
|
|
|
|
|
|
-inner, # inner join |
937
|
|
|
|
|
|
|
[ $BY_HASH_KEY, 'dept' ], # select from $people |
938
|
|
|
|
|
|
|
[ $BY_HASH_KEY, 'dept_name' ], # select from $departments |
939
|
|
|
|
|
|
|
sub { |
940
|
|
|
|
|
|
|
my ( $person, $dept ) = @_; |
941
|
|
|
|
|
|
|
return { |
942
|
|
|
|
|
|
|
name => $person->{name}, |
943
|
|
|
|
|
|
|
dept => $person->{dept}, |
944
|
|
|
|
|
|
|
expense_code => $dept->{cost_code}, |
945
|
|
|
|
|
|
|
}; |
946
|
|
|
|
|
|
|
}, |
947
|
|
|
|
|
|
|
); |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
Hints C<< -inner >>, C<< -left >>, C<< -right >>, and C<< -outer >> are |
950
|
|
|
|
|
|
|
supported, analagous to the joins with the same names in SQL. |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
X_KEYS and Y_KEYS are non-list callables which return the values to join the |
953
|
|
|
|
|
|
|
two collections by. |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
JOINER is a callable (which may be a flattened list) which is passed items |
956
|
|
|
|
|
|
|
from each of the two collections and should return a new item. In the case |
957
|
|
|
|
|
|
|
of left/right/outer joins, one of those items may be undef. |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
=item C<< group_join( Y, HINT?, X_KEYS, Y_KEYS, JOINER ) >> |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
Similar to C<group> except that rather than JOINER being called for every |
962
|
|
|
|
|
|
|
X/Y combination, all the Ys for a particular X are put in a collection, and |
963
|
|
|
|
|
|
|
the JOINER is called for each X and passed the collection of Ys. |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
The only hints supported are C<< -inner >> and C<< -left >>. |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
This is best explained with a full example: |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
my $departments = LINQ( [ |
970
|
|
|
|
|
|
|
{ dept_name => 'Accounts', cost_code => 1 }, |
971
|
|
|
|
|
|
|
{ dept_name => 'IT', cost_code => 7 }, |
972
|
|
|
|
|
|
|
{ dept_name => 'Marketing', cost_code => 8 }, |
973
|
|
|
|
|
|
|
] ); |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
my $people = LINQ( [ |
976
|
|
|
|
|
|
|
{ name => "Alice", dept => 'Marketing' }, |
977
|
|
|
|
|
|
|
{ name => "Bob", dept => 'IT' }, |
978
|
|
|
|
|
|
|
{ name => "Carol", dept => 'IT' }, |
979
|
|
|
|
|
|
|
] ); |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
my $BY_HASH_KEY = sub { |
982
|
|
|
|
|
|
|
my ($key) = @_; |
983
|
|
|
|
|
|
|
return $_->{$key}; |
984
|
|
|
|
|
|
|
}; |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
my $joined = $departments->group_join( |
987
|
|
|
|
|
|
|
$people, |
988
|
|
|
|
|
|
|
-left, # left join |
989
|
|
|
|
|
|
|
[ $BY_HASH_KEY, 'dept_name' ], # select from $departments |
990
|
|
|
|
|
|
|
[ $BY_HASH_KEY, 'dept' ], # select from $people |
991
|
|
|
|
|
|
|
sub { |
992
|
|
|
|
|
|
|
my ( $dept, $people ) = @_; # $people is a LINQ::Collection |
993
|
|
|
|
|
|
|
my $names = $people->select( $BY_HASH_KEY, 'name' )->to_array; |
994
|
|
|
|
|
|
|
return { |
995
|
|
|
|
|
|
|
dept => $dept->{dept_name}, |
996
|
|
|
|
|
|
|
cost_code => $dept->{cost_code}, |
997
|
|
|
|
|
|
|
people => $names, |
998
|
|
|
|
|
|
|
}; |
999
|
|
|
|
|
|
|
}, |
1000
|
|
|
|
|
|
|
); |
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
# [ |
1003
|
|
|
|
|
|
|
# { |
1004
|
|
|
|
|
|
|
# 'cost_code' => 1, |
1005
|
|
|
|
|
|
|
# 'dept' => 'Accounts', |
1006
|
|
|
|
|
|
|
# 'people' => [] |
1007
|
|
|
|
|
|
|
# }, |
1008
|
|
|
|
|
|
|
# { |
1009
|
|
|
|
|
|
|
# 'cost_code' => 7, |
1010
|
|
|
|
|
|
|
# 'dept' => 'IT', |
1011
|
|
|
|
|
|
|
# 'people' => [ |
1012
|
|
|
|
|
|
|
# 'Bob', |
1013
|
|
|
|
|
|
|
# 'Carol' |
1014
|
|
|
|
|
|
|
# ] |
1015
|
|
|
|
|
|
|
# }, |
1016
|
|
|
|
|
|
|
# { |
1017
|
|
|
|
|
|
|
# 'cost_code' => 8, |
1018
|
|
|
|
|
|
|
# 'dept' => 'Marketing', |
1019
|
|
|
|
|
|
|
# 'people' => [ |
1020
|
|
|
|
|
|
|
# 'Alice' |
1021
|
|
|
|
|
|
|
# ] |
1022
|
|
|
|
|
|
|
# } |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
=item C<< take( N ) >> |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
Takes just the first N items from a collection, returning a new collection. |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
=item C<< take_while( CALLABLE ) >> |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
Takes items from the collection, stopping at the first item where CALLABLE |
1031
|
|
|
|
|
|
|
returns false. |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
If CALLABLE dies, there are some issues on older versions of Perl with the |
1034
|
|
|
|
|
|
|
error message getting lost. |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
=item C<< skip( N ) >> |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
Skips the first N items from a collection, and returns the rest as a new |
1039
|
|
|
|
|
|
|
collection. |
1040
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
=item C<< skip_while( CALLABLE ) >> |
1042
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
Skips the first items from a collection while CALLABLE returns true, and |
1044
|
|
|
|
|
|
|
returns the rest as a new collection. |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
=item C<< concat( COLLECTION ) >> |
1047
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
Returns a new collection by concatenating this collection with another |
1049
|
|
|
|
|
|
|
collection. |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
my $deck_of_cards = $red_cards->concat( $black_cards ); |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
=item C<< order_by( HINT?, CALLABLE? ) >> |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
HINT may be C<< -numeric >> (the default) or C<< -string >>. |
1056
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
If CALLABLE is given, it should return a number or string to sort by. |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
my $sorted = $people->order_by( |
1060
|
|
|
|
|
|
|
-string, |
1061
|
|
|
|
|
|
|
[ $BY_HASH_KEY, 'name' ] # CALLABLE as an arrayref |
1062
|
|
|
|
|
|
|
); |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
=item C<< then_by( HINT?, CALLABLE ) >> |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
Not implemented. |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
=item C<< order_by_descending( HINT?, CALLABLE ) >> |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
Like C<order_by> but uses reverse order. |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
=item C<< then_by_descending( HINT?, CALLABLE ) >> |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
Not implemented. |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
=item C<< reverse >> |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
Reverses the order of the collection. |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
=item C<< group_by( CALLABLE ) >> |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
Groups the items by the key returned by CALLABLE. |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
The collection of groups is a LINQ::Collection and each grouping is a |
1085
|
|
|
|
|
|
|
LINQ::Grouping. LINQ::Grouping provides two accessors: C<key> and C<values>, |
1086
|
|
|
|
|
|
|
with C<values> returning a LINQ::Collection of items. |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
my $people = LINQ( [ |
1089
|
|
|
|
|
|
|
{ name => "Alice", dept => 'Marketing' }, |
1090
|
|
|
|
|
|
|
{ name => "Bob", dept => 'IT' }, |
1091
|
|
|
|
|
|
|
{ name => "Carol", dept => 'IT' }, |
1092
|
|
|
|
|
|
|
] ); |
1093
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
my $groups = $people->group_by( sub { $_->{dept} } ); |
1095
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
for my $group ( $groups->to_list ) { |
1097
|
|
|
|
|
|
|
print "Dept: ", $group->key, "\n"; |
1098
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
for my $person ( $group->values->to_list ) { |
1100
|
|
|
|
|
|
|
print " - ", $person->{name}; |
1101
|
|
|
|
|
|
|
} |
1102
|
|
|
|
|
|
|
} |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
=item C<< distinct( CALLABLE? ) >> |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
Returns a new collection without any duplicates which were in the original. |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
If CALLABLE is provided, this will be used to determine when two items are |
1109
|
|
|
|
|
|
|
considered identical/equivalent. Otherwise, numeric equality is used. |
1110
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
=item C<< union( COLLECTION, CALLABLE? ) >> |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
Returns a new collection formed from the union of both collections. |
1114
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
my $first = LINQ( [ 1, 2, 3, 4 ] ); |
1116
|
|
|
|
|
|
|
my $second = LINQ( [ 3, 4, 5, 6 ] ); |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
$first->union( $second )->to_array; # ==> [ 1, 2, 3, 4, 5, 6 ] |
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
If CALLABLE is provided, this will be used to determine when two items are |
1121
|
|
|
|
|
|
|
considered identical/equivalent. Otherwise, numeric equality is used. |
1122
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
=item C<< intersect( COLLECTION, CALLABLE? ) >> |
1124
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
Returns a new collection formed from the union of both collections. |
1126
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
my $first = LINQ( [ 1, 2, 3, 4 ] ); |
1128
|
|
|
|
|
|
|
my $second = LINQ( [ 3, 4, 5, 6 ] ); |
1129
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
$first->intersect( $second )->to_array; # ==> [ 3, 4 ] |
1131
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
If CALLABLE is provided, this will be used to determine when two items are |
1133
|
|
|
|
|
|
|
considered identical/equivalent. Otherwise, numeric equality is used. |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
=item C<< except( COLLECTION, CALLABLE? ) >> |
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
Returns a new collection formed from the asymmetric difference of both |
1138
|
|
|
|
|
|
|
collections. |
1139
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
my $first = LINQ( [ 1, 2, 3, 4 ] ); |
1141
|
|
|
|
|
|
|
my $second = LINQ( [ 3, 4, 5, 6 ] ); |
1142
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
$first->except( $second )->to_array; # ==> [ 1, 2 ] |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
If CALLABLE is provided, this will be used to determine when two items are |
1146
|
|
|
|
|
|
|
considered identical/equivalent. Otherwise, numeric equality is used. |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
=item C<< sequence_equal( COLLECTION, CALLABLE? ) >> |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
Returns true if and only if each item in the first collection is |
1151
|
|
|
|
|
|
|
identical/equivalent to its corresponding item in the second collection, |
1152
|
|
|
|
|
|
|
considered in order, according to CALLABLE. |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
If CALLABLE isn't given, then numeric equality is used. |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
=item C<< first( CALLABLE? ) >> |
1157
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
Returns the first item in a collection. |
1159
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
If CALLABLE is provided, returns the first item in the collection where |
1161
|
|
|
|
|
|
|
CALLABLE returns true. |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
If there is no item to return, does not return undef, but throws a |
1164
|
|
|
|
|
|
|
LINQ::Exception::NotFound exception. |
1165
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
=item C<< first_or_default( CALLABLE?, DEFAULT ) >> |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
Like C<first>, but instead of throwing an exception, will return the DEFAULT. |
1169
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
=item C<< last( CALLABLE? ) >> |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
Returns the last item in a collection. |
1173
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
If CALLABLE is provided, returns the last item in the collection where |
1175
|
|
|
|
|
|
|
CALLABLE returns true. |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
If there is no item to return, does not return undef, but throws a |
1178
|
|
|
|
|
|
|
LINQ::Exception::NotFound exception. |
1179
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
=item C<< last_or_default( CALLABLE?, DEFAULT ) >> |
1181
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
Like C<last>, but instead of throwing an exception, will return the DEFAULT. |
1183
|
|
|
|
|
|
|
|
1184
|
|
|
|
|
|
|
=item C<< single( CALLABLE? ) >> |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
Returns the only item in a collection. |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
If CALLABLE is provided, returns the only item in the collection where |
1189
|
|
|
|
|
|
|
CALLABLE returns true. |
1190
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
If there is no item to return, does not return undef, but throws a |
1192
|
|
|
|
|
|
|
LINQ::Exception::NotFound exception. |
1193
|
|
|
|
|
|
|
|
1194
|
|
|
|
|
|
|
If there are multiple items in the collection, or multiple items where |
1195
|
|
|
|
|
|
|
CALLABLE returns true, throws a LINQ::Exception::MultipleFound exception. |
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
=item C<< single_or_default( CALLABLE?, DEFAULT ) >> |
1198
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
Like C<single> but rather than throwing an exception, will return DEFAULT. |
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
=item C<< element_at( N ) >> |
1202
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
Returns element N within the collection. N may be negative to count from the |
1204
|
|
|
|
|
|
|
end of the collection. Collections are indexed from zero. |
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
If N exceeds the length of the collection, throws a LINQ::Exception::NotFound |
1207
|
|
|
|
|
|
|
exception. |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
=item C<< element_at_or_default( N, DEFAULT ) >> |
1210
|
|
|
|
|
|
|
|
1211
|
|
|
|
|
|
|
Like C<element_at> but rather than throwing an exception, will return DEFAULT. |
1212
|
|
|
|
|
|
|
|
1213
|
|
|
|
|
|
|
=item C<< any( CALLABLE? ) >> |
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
Returns true if CALLABLE returns true for any item in the collection. |
1216
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
=item C<< all( CALLABLE? ) >> |
1218
|
|
|
|
|
|
|
|
1219
|
|
|
|
|
|
|
Returns true if CALLABLE returns true for every item in the collection. |
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
=item C<< contains( ITEM, CALLABLE? ) >> |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
Returns true if the collection contains ITEM. By default, this is checked |
1224
|
|
|
|
|
|
|
using numeric equality. |
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
If CALLABLE is given, this is passed two items and should return true |
1227
|
|
|
|
|
|
|
if they should be considered identical/equivalent. |
1228
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
my $SAME_NAME = sub { |
1230
|
|
|
|
|
|
|
$_[0]{name} eq $_[1]{name}; |
1231
|
|
|
|
|
|
|
}; |
1232
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
if ( $people->contains( { name => "Bob" }, $SAME_NAME ) ) { |
1234
|
|
|
|
|
|
|
print "The collection includes Bob.\n"; |
1235
|
|
|
|
|
|
|
} |
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
=item C<< count >> |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
Returns the size of the collection. (Number of items.) |
1240
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
=item C<< to_list >> |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
Returns the collection as a list. |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
=item C<< to_array >> |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
Returns an arrayref for the collection. This may be a tied arrayref and you |
1248
|
|
|
|
|
|
|
should not assume it will be writable. |
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
=item C<< to_dictionary( CALLABLE ) >> |
1251
|
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
The CALLABLE will be called for each item in the collection and is expected to |
1253
|
|
|
|
|
|
|
return a string key. |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
The method will return a hashref mapping the keys to each item in the |
1256
|
|
|
|
|
|
|
collection. |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
=item C<< to_lookup( CALLABLE ) >> |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
Alias for C<to_dictionary>. |
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
=item C<< to_iterator >> |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
Returns a coderef which can be used to iterate through the collection. |
1265
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
my $people = LINQ( [ |
1267
|
|
|
|
|
|
|
{ name => "Alice", dept => 'Marketing' }, |
1268
|
|
|
|
|
|
|
{ name => "Bob", dept => 'IT' }, |
1269
|
|
|
|
|
|
|
{ name => "Carol", dept => 'IT' }, |
1270
|
|
|
|
|
|
|
] ); |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
my $next_person = $people->to_iterator; |
1273
|
|
|
|
|
|
|
|
1274
|
|
|
|
|
|
|
while ( my $person = $next_person->() ) { |
1275
|
|
|
|
|
|
|
print $person->{name}, "\n"; |
1276
|
|
|
|
|
|
|
} |
1277
|
|
|
|
|
|
|
|
1278
|
|
|
|
|
|
|
=item C<< cast( TYPE ) >> |
1279
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
Given a type constraint (see L<Type::Tiny>) will attempt to coerce every item |
1281
|
|
|
|
|
|
|
in the collection to the type, and will return the collection of coerced |
1282
|
|
|
|
|
|
|
values. If any item cannot be coerced, throws a LINQ::Exception::Cast |
1283
|
|
|
|
|
|
|
exception. |
1284
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
=item C<< of_type( TYPE ) >> |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
Given a type constraint (see L<Type::Tiny>) will attempt to coerce every item |
1288
|
|
|
|
|
|
|
in the collection to the type, and will return the collection of coerced |
1289
|
|
|
|
|
|
|
values. Any items which cannot be coerced will be skipped. |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
=item C<< zip( COLLECTION, CALLABLE ) >> |
1292
|
|
|
|
|
|
|
|
1293
|
|
|
|
|
|
|
Will loop through both collections in parallel and pass one item from each |
1294
|
|
|
|
|
|
|
collection to CALLABLE as arguments. |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
If the two collections are of different sizes, will stop after exhausing the |
1297
|
|
|
|
|
|
|
shorter collection. |
1298
|
|
|
|
|
|
|
|
1299
|
|
|
|
|
|
|
=item C<< default_if_empty( ITEM ) >> |
1300
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
If this collection contains one or more items, returns itself. |
1302
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
If the collection is empty, returns a new collection containing just a single |
1304
|
|
|
|
|
|
|
item, given as a parameter. |
1305
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
my $collection = $people->default_if_empty( "Bob" ); |
1307
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
# Equivalent to: |
1309
|
|
|
|
|
|
|
my $collection = $people->count ? $people : LINQ( [ "Bob" ] ); |
1310
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
=item C<< foreach( CALLABLE ) >> |
1312
|
|
|
|
|
|
|
|
1313
|
|
|
|
|
|
|
This calls CALLABLE on each item in the collection. The following are roughly |
1314
|
|
|
|
|
|
|
equivalent: |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
for ( $collection->to_list ) { |
1317
|
|
|
|
|
|
|
say $_; |
1318
|
|
|
|
|
|
|
} |
1319
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
$collection->foreach( sub { |
1321
|
|
|
|
|
|
|
say $_; |
1322
|
|
|
|
|
|
|
} ); |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
The advantage of the latter is that it avoids calling C<to_list>, which would |
1325
|
|
|
|
|
|
|
obviously fail on infinite collections. |
1326
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
You can break out of the loop using C<< LINQ::LAST >>. |
1328
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
my $counter = 0; |
1330
|
|
|
|
|
|
|
$collection->foreach( sub { |
1331
|
|
|
|
|
|
|
say $_; |
1332
|
|
|
|
|
|
|
LINQ::LAST if ++$counter >= 10; |
1333
|
|
|
|
|
|
|
} ); |
1334
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
Microsoft's official LINQ API doesn't include a C<ForEach> method, but this |
1336
|
|
|
|
|
|
|
method is provided by the MoreLINQ extension. |
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
=back |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
=head1 WORKING WITH INFINITE COLLECTIONS |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
Because LINQ collections can be instantiated from an iterator, they may |
1343
|
|
|
|
|
|
|
contain infinite items. |
1344
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
Certain methods aggregate the entire collection, so can go into an infinite |
1346
|
|
|
|
|
|
|
loop. This includes: C<aggregate>, C<min>, C<max>, C<sum>, C<average>, and |
1347
|
|
|
|
|
|
|
C<count>. |
1348
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
Other methods which will go into an infinite loop on infinite collections: |
1350
|
|
|
|
|
|
|
C<join>, C<group_join>, C<group_by>, C<order_by>, C<order_by_descending>, |
1351
|
|
|
|
|
|
|
C<reverse>, C<to_lookup>, C<to_dictionary>, and C<to_list>. |
1352
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
The C<to_array> method in general I<will> succeed on infinite collections |
1354
|
|
|
|
|
|
|
as it can return a reference to a tied array. However, trying to dereference |
1355
|
|
|
|
|
|
|
the entire array to a list will fail. |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
=head1 BUGS |
1358
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
Please report any bugs to |
1360
|
|
|
|
|
|
|
L<http://rt.cpan.org/Dist/Display.html?Queue=LINQ>. |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
=head1 SEE ALSO |
1363
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
L<LINQ>, L<LINQ::Grouping>. |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
L<https://en.wikipedia.org/wiki/Language_Integrated_Query> |
1367
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
=head1 AUTHOR |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
Toby Inkster E<lt>tobyink@cpan.orgE<gt>. |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENCE |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
This software is copyright (c) 2014, 2021 by Toby Inkster. |
1375
|
|
|
|
|
|
|
|
1376
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
1377
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
1378
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
=head1 DISCLAIMER OF WARRANTIES |
1380
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
1382
|
|
|
|
|
|
|
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
1383
|
|
|
|
|
|
|
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |