File Coverage

blib/lib/Z.pm
Criterion Covered Total %
statement 54 79 68.3
branch 5 18 27.7
condition 2 10 20.0
subroutine 13 13 100.0
pod 0 3 0.0
total 74 123 60.1


line stmt bran cond sub pod time code
1 1     1   67590 use 5.008008;
  1         4  
2 1     1   7 use strict;
  1         2  
  1         20  
3 1     1   4 use warnings;
  1         2  
  1         48  
4              
5             package Z;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.006';
9              
10 1     1   493 use Import::Into ();
  1         2691  
  1         25  
11 1     1   8 use Module::Runtime qw( use_module );
  1         1  
  1         5  
12 1     1   587 use Zydeco::Lite qw( true false );
  1         181931  
  1         10  
13              
14             BEGIN {
15 1 50   1   2096 *PERL_IS_MODERN = ( $] ge '5.014' ) ? \&true : \&false;
16             }
17              
18             my $STRICT = 0;
19             $ENV{$_} && ++$STRICT && last for qw(
20             EXTENDED_TESTING
21             AUTHOR_TESTING
22             RELEASE_TESTING
23             PERL_STRICT
24             );
25              
26             sub import {
27 1     1   27 my ($target, $class ) = ( scalar caller, shift );
28            
29 1         2 my $mode = '-modern';
30 1 50 50     8 ( $_[0] || '' ) =~ /^-/ and $mode = shift;
31            
32 1         2 my $collection = 'modules';
33            
34 1         2 if ( PERL_IS_MODERN ) {
35 1 50       4 $collection = 'compat_modules' if $mode eq '-compat';
36             }
37             else {
38             $collection = 'compat_modules';
39            
40             if ( $mode eq '-modern' ) {
41             require Carp;
42             return Carp::croak( "$target requires Perl v5.14 or above; stopping" );
43             }
44             elsif ( $mode eq '-detect' ) {
45             require Carp;
46             Carp::carp( "$target may require Perl v5.14 or above; attempting compatibility mode" );
47             }
48             }
49            
50 1         4 for my $modules ( $class->$collection ) {
51 12         163827 my ( $name, $version, @args ) = @$modules;
52 12         60 use_module( $name, $version )->import::into( $target, @args );
53             }
54            
55             eval {
56 1         533 require indirect;
57 1         1069 'indirect'->unimport::out_of( $target );
58 1         210 1;
59 1 50 33     315 } or !$STRICT or do {
60 0         0 require Carp;
61 0         0 Carp::carp( "Could not load indirect.pm" );
62             };
63            
64 1         10 $class->also( $target, @_ );
65            
66 1         5 use_module( 'namespace::autoclean' )->import::into( $target );
67            
68 1         374 return $class;
69             }
70              
71             sub modules {
72 1     1 0 2 my $class = shift;
73            
74             return (
75 1         13 [ 'Syntax::Keyword::Try', '0.018', qw( try ) ],
76             [ 'Zydeco::Lite', '0.070', qw( -all ) ],
77             [ 'Types::Standard', '1.010000', qw( -types -is -assert ) ],
78             [ 'Types::Common::Numeric', '1.010000', qw( -types -is -assert ) ],
79             [ 'Types::Common::String', '1.010000', qw( -types -is -assert ) ],
80             [ 'Types::Path::Tiny', '0', qw( -types -is -assert ) ],
81             [ 'Object::Adhoc', '0.003', qw( object ) ],
82             [ 'Path::Tiny', '0.101', qw( path ) ],
83             [ 'match::simple', '0.010', qw( match ) ],
84             [ 'strict', '0', qw( refs subs vars ) ],
85             [ 'warnings', '0', qw( all ) ],
86             [ 'feature', '0', qw( say state ) ],
87             );
88             }
89              
90             sub compat_modules {
91 1     1 0 3 my $class = shift;
92            
93             my @modules =
94 1         2 grep { my $name = $_->[0]; $name !~ /feature|Try/ }
  12         18  
  12         29  
95             $class->modules;
96              
97 1         4 push @modules, [ 'Try::Tiny', '0.30' ];
98              
99 1 50       5 if ( $] ge '5.010' ) {
100 1         2 push @modules, [ 'feature', '0', qw( say ) ];
101             }
102             else {
103 0         0 push @modules, [ 'Perl6::Say', '0.06' ];
104 0         0 push @modules, [ 'UNIVERSAL::DOES', '0.001' ];
105             }
106            
107 1         3 return @modules;
108             }
109              
110             my %also = (
111             Dumper => sub {
112             require Data::Dumper;
113             return sub {
114             local $Data::Dumper::Deparse;
115             Data::Dumper::Dumper(@_);
116             },
117             },
118             croak => sub {
119             return sub {
120             require Carp;
121             Carp::croak( @_ > 1 ? sprintf(shift, @_) : @_ );
122             };
123             },
124             carp => sub {
125             return sub {
126             require Carp;
127             Carp::carp( @_ > 1 ? sprintf(shift, @_) : @_ );
128             };
129             },
130             cluck => sub {
131             return sub {
132             require Carp;
133             Carp::cluck( @_ > 1 ? sprintf(shift, @_) : @_ );
134             };
135             },
136             maybe => sub {
137             if ( eval 'use PerlX::Maybe::XS 0.003 (); 1' ) {
138             return \&PerlX::Maybe::XS::maybe;
139             }
140             return sub ($$@) {
141             ( defined $_[0] and defined $_[1] )
142             ? @_
143             : ( ( @_ > 1 ) ? @_[2 .. $#_] : qw() )
144             };
145             },
146             provided => sub {
147             if ( eval 'use PerlX::Maybe::XS 0.003 (); 1' ) {
148             return \&PerlX::Maybe::XS::provided;
149             }
150             return sub ($$$@) {
151             ( shift )
152             ? @_
153             : ( ( @_ > 1 ) ? @_[2 .. $#_] : qw() )
154             };
155             },
156             encode_json => sub {
157             if ( eval 'use JSON::MaybeXS 1.003000 (); 1' ) {
158             return \&JSON::MaybeXS::encode_json;
159             }
160             require JSON::PP;
161             return \&JSON::PP::encode_json;
162             },
163             decode_json => sub {
164             if ( eval 'use JSON::MaybeXS 1.003000 (); 1' ) {
165             return \&JSON::MaybeXS::decode_json;
166             }
167             require JSON::PP;
168             return \&JSON::PP::decode_json;
169             },
170             STRICT => sub {
171             $STRICT ? sub () { !!1 } : sub () { !!0 };
172             },
173             LAX => sub {
174             $STRICT ? sub () { !!0 } : sub () { !!1 };
175             },
176             all => q(List::Util),
177             any => q(List::Util),
178             first => q(List::Util),
179             head => q(List::Util),
180             max => q(List::Util),
181             maxstr => q(List::Util),
182             min => q(List::Util),
183             minstr => q(List::Util),
184             none => q(List::Util),
185             notall => q(List::Util),
186             pairfirst => q(List::Util),
187             pairgrep => q(List::Util),
188             pairkeys => q(List::Util),
189             pairmap => q(List::Util),
190             pairs => q(List::Util),
191             pairvalues => q(List::Util),
192             product => q(List::Util),
193             reduce => q(List::Util),
194             reductions => q(List::Util),
195             sample => q(List::Util),
196             shuffle => q(List::Util),
197             sum => q(List::Util),
198             sum0 => q(List::Util),
199             tail => q(List::Util),
200             uniq => q(List::Util),
201             uniqnum => q(List::Util),
202             uniqstr => q(List::Util),
203             unpairs => q(List::Util),
204             blessed => q(Scalar::Util),
205             dualvar => q(Scalar::Util),
206             isdual => q(Scalar::Util),
207             isvstring => q(Scalar::Util),
208             isweak => q(Scalar::Util),
209             looks_like_number => q(Scalar::Util),
210             openhandle => q(Scalar::Util),
211             readonly => q(Scalar::Util),
212             refaddr => q(Scalar::Util),
213             reftype => q(Scalar::Util),
214             set_prototype => q(Scalar::Util),
215             tainted => q(Scalar::Util),
216             unweaken => q(Scalar::Util),
217             weaken => q(Scalar::Util),
218             prototype => q(Sub::Util),
219             set_prototype => q(Sub::Util),
220             set_subname => q(Sub::Util),
221             subname => q(Sub::Util),
222             );
223              
224             sub also {
225 1     1 0 4 my ( $class, $target ) = ( shift, shift );
226            
227 1         3 my %imports;
228 1         3 for my $arg ( @_ ) {
229 0         0 my ( $func, $dest ) = split /:/, $arg;
230 0 0       0 $dest = $func unless $dest;
231            
232 0 0       0 my $source = $also{$func} or do {
233 0         0 require Carp;
234 0         0 Carp::croak( "Do not know where to find function $func" );
235 0         0 next;
236             };
237            
238 0 0 0     0 push @{ $imports{ ref($source) or $source } ||= [] },
  0   0     0  
239             ref($source) ? [ $dest, $source ] : [ $dest, $func ];
240             }
241            
242 1         5 for my $source ( sort keys %imports ) {
243 0 0         if ( $source eq 'CODE' ) {
244 0           for my $func ( @{$imports{$source}} ) {
  0            
245 0           my ( $name, $gen ) = @$func;
246 1     1   11 no strict 'refs';
  1         2  
  1         92  
247 0           *{"$target\::$name"} = $gen->();
  0            
248             }
249             }
250             else {
251 0           use_module( $source );
252 0           for my $func ( @{$imports{$source}} ) {
  0            
253 0           my ( $name, $orig ) = @$func;
254 1     1   7 no strict 'refs';
  1         10  
  1         152  
255 0           *{"$target\::$name"} = \&{"$source\::$orig"};
  0            
  0            
256             }
257             }
258             }
259             }
260              
261             1;
262              
263             __END__
264              
265             =pod
266              
267             =encoding utf-8
268              
269             =head1 NAME
270              
271             Z - collection of modules for rapid app development
272              
273             =head1 SYNOPSIS
274              
275             This:
276              
277             use Z;
278              
279             Is a shortcut for:
280              
281             use strict;
282             use warnings;
283             use feature 'say', 'state';
284             use namespace::autoclean;
285             use Syntax::Keyword::Try 'try';
286             use Zydeco::Lite -all;
287             use Path::Tiny 'path';
288             use Object::Adhoc 'object';
289             use match::simple 'match';
290             use Types::Standard -types, -is, -assert;
291             use Types::Common::String -types, -is, -assert;
292             use Types::Common::Numeric -types, -is, -assert;
293             use Types::Path::Tiny -types, -is, -assert;
294              
295             It will also do C<< no indirect >> if L<indirect> is installed.
296              
297             =head1 DESCRIPTION
298              
299             Just a shortcut for loading a bunch of modules that allow you to
300             quickly code Perl stuff. I've tried to avoid too many domain-specific
301             modules like HTTP::Tiny, etc. The modules chosen should be broadly
302             useful for a wide variety of tasks.
303              
304             =head2 Perl Version Compatibility
305              
306             By default, Z requires Perl v5.14, but it has a compatibility mode where
307             for Perl v5.8.8 and above.
308              
309             It will use L<Try::Tiny> instead of L<Syntax::Keyword::Try>. (Bear in mind
310             that these are not 100% compatible with each other.) It will also load
311             L<Perl6::Say> as a fallback for the C<say> built-in. And it will not provide
312             C<state>. It will also load L<UNIVERSAL::DOES> if there's no built-in
313             UNIVERSAL::DOES method.
314              
315             You can specify whether you want the modern modules or the compatibility
316             modules:
317              
318             use Z -modern;
319             # Uses modern modules.
320             # Requres Perl 5.14+.
321            
322             use Z -compat;
323             # Uses compatible modules.
324             # Requires Perl 5.8.8+.
325            
326             use Z -detect;
327             # Uses modern modules on Perl 5.14+.
328             # Prints a warning and uses compatible modules on Perl 5.8.8+.
329              
330             The default is C<< -modern >>.
331              
332             =head2 Additional Functions
333              
334             There are a whole bunch of other useful functions that Z I<could> make
335             available, but it's hard to know the best place to draw the line. So
336             other functions are available on request:
337              
338             use Z qw( weaken unweaken isweak );
339            
340             use Z -compat, qw( pairmap pairgrep );
341            
342             # Rename functions...
343             use Z qw( pairmap:pmap pairgrep:pgrep );
344              
345             (The things listed in the L</SYNOPSIS> are always imported and don't
346             support the renaming feature.)
347              
348             The additional functions available are: everything from L<Scalar::Util>,
349             everything from L<List::Util>, everything from L<Sub::Util>, everything
350             from L<Carp> (wrapped versions with C<sprintf> functionality, except
351             C<confess> which is part of the standard set of functions already),
352             C<Dumper> from L<Data::Dumper>, C<maybe> and C<provided> from
353             L<PerlX::Maybe>, C<encode_json> and C<decode_json> from
354             L<JSON::MaybeXS> or L<JSON::PP> (depending which is installed), and
355             C<STRICT> and C<LAX> from L<Devel::StrictMode>.
356              
357             If you specify a compatibility mode (like C<< -modern >>), this must be
358             first in the import list.
359              
360             =head1 BUGS
361              
362             Please report any bugs to
363             L<http://rt.cpan.org/Dist/Display.html?Queue=Z>.
364              
365             =head1 SEE ALSO
366              
367             L<Zydeco::Lite>,
368             L<Types::Standard>,
369             L<Syntax::Feature::Try>,
370             L<Path::Tiny>,
371             L<match::simple>,
372             L<Object::Adhoc>.
373              
374             =head1 AUTHOR
375              
376             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
377              
378             =head1 COPYRIGHT AND LICENCE
379              
380             This software is copyright (c) 2020 by Toby Inkster.
381              
382             This is free software; you can redistribute it and/or modify it under
383             the same terms as the Perl 5 programming language system itself.
384              
385             =head1 DISCLAIMER OF WARRANTIES
386              
387             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
388             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
389             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
390