File Coverage

blib/lib/LINQ.pm
Criterion Covered Total %
statement 51 51 100.0
branch 22 22 100.0
condition 3 3 100.0
subroutine 15 15 100.0
pod 3 3 100.0
total 94 94 100.0


line stmt bran cond sub pod time code
1 116     116   13764225 use 5.006;
  116         1303  
2 116     116   644 use strict;
  116         260  
  116         2469  
3 116     116   554 use warnings;
  116         206  
  116         7063  
4              
5              
6             our $AUTHORITY = 'cpan:TOBYINK';
7             our $VERSION = '0.003';
8              
9             use Exporter::Shiny qw( LINQ Range Repeat END );
10 116     116   49886  
  116         62042  
  116         733  
11             our $FORCE_ITERATOR;
12             our $IN_LOOP;
13              
14             my $end = do {
15              
16             our $AUTHORITY = 'cpan:TOBYINK';
17             our $VERSION = '0.003';
18             my $x = 42;
19             bless( \$x );
20             &Internals::SvREADONLY( \$x, !!1 );
21             \$x;
22              
23             my $last = do {
24              
25             our $AUTHORITY = 'cpan:TOBYINK';
26             our $VERSION = '0.003';
27             my $x = 666;
28             bless( \$x );
29             &Internals::SvREADONLY( \$x, !!1 );
30             \$x;
31              
32             BEGIN {
33             *LINQ::END = sub () { $end };
34            
35             *LINQ::LAST = sub () {
36             if ( $IN_LOOP ) {
37             die( $last );
38 116     116   28476 }
  1932     1932   18597  
39             require LINQ::Exception;
40             'LINQ::Exception::CallerError'->throw(
41 6 100   6   3035 message => "Cannot call LINQ::LAST outside foreach",
42 3         25 );
43             };
44 3         1482 } #/ BEGIN
45 3         26  
46             my $data = shift;
47             my $ref = ref( $data );
48 116         57276
49             if ( $ref eq 'ARRAY' ) {
50             if ( $FORCE_ITERATOR ) {
51             my @data = @$data;
52 793     793 1 142852 require LINQ::Iterator;
53 793         1619 return LINQ::Iterator::->new( sub { @data ? shift( @data ) : LINQ::END } );
54             }
55 793 100       2105
56 473 100       1093 require LINQ::Array;
57 216         912 return LINQ::Array::->new( $data );
58 216         22373 } #/ if ( $ref eq 'ARRAY' )
59 216 100   1251   1321
  1251         3076  
60             if ( $ref eq 'CODE' ) {
61             require LINQ::Iterator;
62 257         25817 return LINQ::Iterator::->new( $data );
63 257         929 }
64            
65             require Scalar::Util;
66 320 100       894 if ( Scalar::Util::blessed( $data ) and $data->DOES( 'LINQ::Collection' ) ) {
67 317         24477 return $data;
68 317         1163 }
69            
70             require LINQ::Exception;
71 3         16 'LINQ::Exception::CallerError'->throw(
72 3 100 100     27 message => "Cannot create LINQ object from '$data'",
73 1         26 );
74             } #/ sub LINQ ($)
75              
76 2         474 my ( $min, $max ) = @_;
77 2         18
78             my $value = defined( $min ) ? $min : 0;
79            
80             if ( not defined $max ) {
81             return LINQ sub { $value++ };
82             }
83 7     7 1 268
84             return LINQ sub { return LINQ::END if $value > $max; $value++ };
85 7 100       22 } #/ sub Range
86              
87 7 100       21 my ( $value, $count ) = @_;
88 2     15   14
  15         35  
89             if ( not defined $count ) {
90             return LINQ sub { $value };
91 5 100   35   24 }
  35         77  
  31         66  
92            
93             return LINQ sub { return LINQ::END if $count-- <= 0; $value };
94             }
95 6     6 1 270  
96             1;
97 6 100       25  
98 5     35   39  
  35         94  
99             =pod
100              
101 1 100   8   8 =encoding utf-8
  8         18  
  7         13  
102              
103             =head1 NAME
104              
105             LINQ - an interpretation of Microsoft's Language Integrated Query
106              
107             =head1 SYNOPSIS
108              
109             use feature qw( say );
110             use LINQ qw( LINQ )';
111            
112             my $double_even_numbers =
113             LINQ( [ 1 .. 100 ] )
114             ->where( sub { $_ % 2 == 0 } )
115             ->select( sub { $_ * 2 } );
116            
117             for my $n ( $double_even_numbers->to_list ) {
118             say $n;
119             }
120              
121             =head1 DESCRIPTION
122              
123             LINQ is basically an application of SQL concepts to arrays and iterators.
124             Hopefully this implementation will eventually cover other data types like
125             SQL tables, XML and JSON data, etc.
126              
127             Not much is documented yet, but the test suite includes numerous examples
128             of LINQ's usage.
129              
130             =head1 FUNCTIONS
131              
132             The C<LINQ>, C<Range>, and C<Repeat> functions return LINQ collections,
133             objects implementing the L<LINQ::Collection> interface.
134              
135             The C<< LINQ::END() >> and C<< LINQ::LAST() >> functions are used as
136             signals to control LINQ's iterators and loops.
137              
138             Additional utility functions can be found in L<LINQ::Util>.
139              
140             =over
141              
142             =item C<< LINQ( SOURCE ) >>
143              
144             Creates a LINQ collection from a source. The source may be an existing LINQ
145             collection, which will be returned as-is, an arrayref of items, or a coderef
146             which will be called in scalar context and expected to return a single item
147             each time it is called. It should return the special value C<< LINQ::END() >>
148             to indicate that the end of the collection has been reached.
149              
150             C<LINQ> may be exported, but is not exported by default.
151              
152             =item C<< Range( MIN, MAX ) >>
153              
154             Returns a LINQ collection containing the range of numbers from MIN to MAX.
155             If MIN is undef, it is treated as 0. If MAX is undef, it is treated as positive
156             infinity.
157              
158             If you want a range from 0 to negative infinity, use:
159              
160             my $below_zero = Range( 0, undef )->select( sub { -$_ } );
161              
162             C<Range> may be exported, but is not exported by default.
163              
164             =item C<< Repeat( VALUE, COUNT ) >>
165              
166             Returns a LINQ collection containing the same value multiple times. If COUNT
167             is undef, then it is treated as infinity.
168              
169             C<Repeat> may be exported, but is not exported by default.
170              
171             =item C<< END() >>
172              
173             Returns the special value C<< LINQ::END() >>.
174              
175             C<END> may be exported, but is not exported by default, and I recommend
176             calling it by its fully qualified name for clarity.
177              
178             =item C<< LAST() >>
179              
180             Used by the C<foreach> method of L<LINQ::Collection>. If called otherwise,
181             will die.
182              
183             =back
184              
185             =head1 HISTORY
186              
187             I wrote this back in 2014, but never released it. After a discussion
188             about how nice it would be to have a programming language which used SQL
189             concepts natively, eliminating the need to "map" between how your
190             application handled data and how your database handled data, I remembered
191             this. So I thought I'd push what I had so far onto CPAN and maybe think
192             about reviving it.
193              
194             =head1 BUGS
195              
196             Please report any bugs to
197             L<http://rt.cpan.org/Dist/Display.html?Queue=LINQ>.
198              
199             =head1 SEE ALSO
200              
201             L<LINQ::Collection>, L<LINQ::Util>, L<LINQ::Exception>.
202              
203             L<https://en.wikipedia.org/wiki/Language_Integrated_Query>
204              
205             =head1 AUTHOR
206              
207             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
208              
209             =head1 COPYRIGHT AND LICENCE
210              
211             This software is copyright (c) 2014, 2021 by Toby Inkster.
212              
213             This is free software; you can redistribute it and/or modify it under
214             the same terms as the Perl 5 programming language system itself.
215              
216             =head1 DISCLAIMER OF WARRANTIES
217              
218             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
219             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
220             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.