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   69629 use 5.008008;
  1         3  
2 1     1   6 use strict;
  1         1  
  1         25  
3 1     1   5 use warnings;
  1         2  
  1         48  
4              
5             package Z;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.007';
9              
10 1     1   512 use Import::Into ();
  1         2788  
  1         25  
11 1     1   6 use Module::Runtime qw( use_module );
  1         7  
  1         4  
12 1     1   637 use Zydeco::Lite qw( true false );
  1         185689  
  1         9  
13              
14             BEGIN {
15 1 50   1   2078 *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   16 my ($target, $class ) = ( scalar caller, shift );
28            
29 1         2 my $mode = '-modern';
30 1 50 50     7 ( $_[0] || '' ) =~ /^-/ and $mode = shift;
31            
32 1         2 my $collection = 'modules';
33            
34 1         2 if ( PERL_IS_MODERN ) {
35 1 50       3 $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         164715 my ( $name, $version, @args ) = @$modules;
52 12         44 use_module( $name, $version )->import::into( $target, @args );
53             }
54            
55             eval {
56 1         506 require indirect;
57 1         1075 'indirect'->unimport::out_of( $target );
58 1         212 1;
59 1 50 33     317 } or !$STRICT or do {
60 0         0 require Carp;
61 0         0 Carp::carp( "Could not load indirect.pm" );
62             };
63            
64 1         9 $class->also( $target, @_ );
65            
66 1         4 use_module( 'namespace::autoclean' )->import::into( $target );
67            
68 1         378 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 2 my $class = shift;
92            
93             my @modules =
94 1         4 grep { my $name = $_->[0]; $name !~ /feature|Try/ }
  12         21  
  12         27  
95             $class->modules;
96              
97 1         5 push @modules, [ 'Try::Tiny', '0.30' ];
98              
99 1 50       4 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         5 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             check_module_name => q(Module::Runtime),
223             check_module_spec => q(Module::Runtime),
224             compose_module_name => q(Module::Runtime),
225             is_module_name => q(Module::Runtime),
226             is_module_spec => q(Module::Runtime),
227             is_valid_module_name => q(Module::Runtime),
228             is_valid_module_spec => q(Module::Runtime),
229             module_notional_filename => q(Module::Runtime),
230             require_module => q(Module::Runtime),
231             use_module => q(Module::Runtime),
232             use_package_optimistically => q(Module::Runtime),
233             );
234              
235             sub also {
236 1     1 0 3 my ( $class, $target ) = ( shift, shift );
237            
238 1         2 my %imports;
239 1         5 for my $arg ( @_ ) {
240 0         0 my ( $func, $dest ) = split /:/, $arg;
241 0 0       0 $dest = $func unless $dest;
242            
243 0 0       0 my $source = $also{$func} or do {
244 0         0 require Carp;
245 0         0 Carp::croak( "Do not know where to find function $func" );
246 0         0 next;
247             };
248            
249 0 0 0     0 push @{ $imports{ ref($source) or $source } ||= [] },
  0   0     0  
250             ref($source) ? [ $dest, $source ] : [ $dest, $func ];
251             }
252            
253 1         5 for my $source ( sort keys %imports ) {
254 0 0         if ( $source eq 'CODE' ) {
255 0           for my $func ( @{$imports{$source}} ) {
  0            
256 0           my ( $name, $gen ) = @$func;
257 1     1   11 no strict 'refs';
  1         3  
  1         89  
258 0           *{"$target\::$name"} = $gen->();
  0            
259             }
260             }
261             else {
262 0           use_module( $source );
263 0           for my $func ( @{$imports{$source}} ) {
  0            
264 0           my ( $name, $orig ) = @$func;
265 1     1   7 no strict 'refs';
  1         7  
  1         167  
266 0           *{"$target\::$name"} = \&{"$source\::$orig"};
  0            
  0            
267             }
268             }
269             }
270             }
271              
272             1;
273              
274             __END__
275              
276             =pod
277              
278             =encoding utf-8
279              
280             =head1 NAME
281              
282             Z - collection of modules for rapid app development
283              
284             =head1 SYNOPSIS
285              
286             This:
287              
288             use Z;
289              
290             Is a shortcut for:
291              
292             use strict;
293             use warnings;
294             use feature 'say', 'state';
295             use namespace::autoclean;
296             use Syntax::Keyword::Try 'try';
297             use Zydeco::Lite -all;
298             use Path::Tiny 'path';
299             use Object::Adhoc 'object';
300             use match::simple 'match';
301             use Types::Standard -types, -is, -assert;
302             use Types::Common::String -types, -is, -assert;
303             use Types::Common::Numeric -types, -is, -assert;
304             use Types::Path::Tiny -types, -is, -assert;
305              
306             It will also do C<< no indirect >> if L<indirect> is installed.
307              
308             =head1 DESCRIPTION
309              
310             Just a shortcut for loading a bunch of modules that allow you to
311             quickly code Perl stuff. I've tried to avoid too many domain-specific
312             modules like HTTP::Tiny, etc. The modules chosen should be broadly
313             useful for a wide variety of tasks.
314              
315             =head2 Perl Version Compatibility
316              
317             By default, Z requires Perl v5.14, but it has a compatibility mode where
318             for Perl v5.8.8 and above.
319              
320             It will use L<Try::Tiny> instead of L<Syntax::Keyword::Try>. (Bear in mind
321             that these are not 100% compatible with each other.) It will also load
322             L<Perl6::Say> as a fallback for the C<say> built-in. And it will not provide
323             C<state>. It will also load L<UNIVERSAL::DOES> if there's no built-in
324             UNIVERSAL::DOES method.
325              
326             You can specify whether you want the modern modules or the compatibility
327             modules:
328              
329             use Z -modern;
330             # Uses modern modules.
331             # Requres Perl 5.14+.
332            
333             use Z -compat;
334             # Uses compatible modules.
335             # Requires Perl 5.8.8+.
336            
337             use Z -detect;
338             # Uses modern modules on Perl 5.14+.
339             # Prints a warning and uses compatible modules on Perl 5.8.8+.
340              
341             The default is C<< -modern >>.
342              
343             =head2 Additional Functions
344              
345             There are a whole bunch of other useful functions that Z I<could> make
346             available, but it's hard to know the best place to draw the line. So
347             other functions are available on request:
348              
349             use Z qw( weaken unweaken isweak );
350            
351             use Z -compat, qw( pairmap pairgrep );
352            
353             # Rename functions...
354             use Z qw( pairmap:pmap pairgrep:pgrep );
355              
356             (The things listed in the L</SYNOPSIS> are always imported and don't
357             support the renaming feature.)
358              
359             The additional functions available are: everything from L<Scalar::Util>,
360             everything from L<List::Util>, everything from L<Sub::Util>, everything
361             from L<Carp> (wrapped versions with C<sprintf> functionality, except
362             C<confess> which is part of the standard set of functions already),
363             all the functions (but not the exported regexps) from L<Module::Runtime>,
364             C<Dumper> from L<Data::Dumper>, C<maybe> and C<provided> from
365             L<PerlX::Maybe>, C<encode_json> and C<decode_json> from
366             L<JSON::MaybeXS> or L<JSON::PP> (depending which is installed), and
367             C<STRICT> and C<LAX> from L<Devel::StrictMode>.
368              
369             If you specify a compatibility mode (like C<< -modern >>), this must be
370             first in the import list.
371              
372             =head1 BUGS
373              
374             Please report any bugs to
375             L<http://rt.cpan.org/Dist/Display.html?Queue=Z>.
376              
377             =head1 SEE ALSO
378              
379             L<Zydeco::Lite>,
380             L<Types::Standard>,
381             L<Syntax::Feature::Try>,
382             L<Path::Tiny>,
383             L<match::simple>,
384             L<Object::Adhoc>.
385              
386             =head1 AUTHOR
387              
388             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
389              
390             =head1 COPYRIGHT AND LICENCE
391              
392             This software is copyright (c) 2020 by Toby Inkster.
393              
394             This is free software; you can redistribute it and/or modify it under
395             the same terms as the Perl 5 programming language system itself.
396              
397             =head1 DISCLAIMER OF WARRANTIES
398              
399             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
400             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
401             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
402