File Coverage

blib/lib/builtins/compat.pm
Criterion Covered Total %
statement 70 78 91.0
branch 25 30 83.3
condition 17 23 73.9
subroutine 17 17 100.0
pod 0 3 0.0
total 129 151 86.0


line stmt bran cond sub pod time code
1 7     7   220599 use 5.008001;
  7         58  
2 7     7   34 use strict;
  7         18  
  7         134  
3 7     7   29 use warnings;
  7         9  
  7         791  
4              
5             package builtins::compat;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.004';
9              
10             sub _true () {
11             !!1;
12             }
13              
14             sub _false () {
15             !!0;
16             }
17              
18             BEGIN {
19             # uncoverable statement
20 7 50   7   2482 *LEGACY_PERL = ( $] lt '5.036' ) ? \&_true : \&_false;
21             };
22              
23             our %EXPORT_TAGS = (
24             '5.36' => [ qw<
25             true false is_bool
26             weaken unweaken is_weak
27             blessed refaddr reftype
28             created_as_string created_as_number
29             ceil floor trim indexed
30             > ],
31             'bool' => [ qw< true false is_bool > ],
32             );
33              
34             sub parse_args {
35 7     7 0 23 my $class = shift;
36 7 100       24 my @args = @_ ? @_ : ':5.36';
37              
38 7         9 my $want = {};
39 7         15 for my $arg ( @args ) {
40 7 100       36 if ( $arg =~ /^:(.+)/ ) {
    50          
41 6         17 my $tag = $1;
42 6 100       17 if ( not exists $EXPORT_TAGS{$tag} ) {
43 1         4 require Carp;
44 1         92 Carp::carp( qq["$tag" is not defined in $class\::EXPORT_TAGS] );
45             }
46 6 100       13 $want->{$_} = 1 for @{ $EXPORT_TAGS{$tag} or [] };
  6         47  
47             }
48             elsif ( $arg =~ /^\!(.+)/ ) {
49 0         0 my $unwanted = $1;
50 0         0 delete $want->{$_};
51             }
52             else {
53 1         3 $want->{$arg} = 1;
54             }
55             }
56              
57 7         54 return $want;
58             }
59              
60             sub import {
61 7     7   1292 goto \&import_compat if LEGACY_PERL;
62              
63 0         0 my $class = shift;
64 0         0 my %want = %{ $class->parse_args( @_ ) };
  0         0  
65              
66             # uncoverable statement
67 0         0 'warnings'->unimport( 'experimental::builtin' );
68              
69             # uncoverable statement
70 0         0 'builtin'->import( keys %want );
71             }
72              
73             sub import_compat {
74 7     7 0 15 my $class = shift;
75              
76 7         14 my $caller = caller;
77 7         14 my $subs = $class->get_subs;
78 7         13 my %want = %{ $class->parse_args( @_ ) };
  7         17  
79              
80 7         54 for my $name ( sort keys %want ) {
81              
82 64 100       108 if ( my $code = $subs->{$name} ) {
83 7     7   45 no strict 'refs';
  7         11  
  7         2066  
84 63         63 *{"$caller\::$name"} = $code;
  63         214  
85             }
86             else {
87 1         4 require Carp;
88 1         173 Carp::carp( qq["$name" is not exported by the $class module] );
89 1         9 delete $want{$name}; # hide from namespace::clean
90             }
91             }
92              
93 7         2323 require namespace::clean;
94 7         82268 'namespace::clean'->import(
95             -cleanee => $caller,
96             keys( %want ),
97             );
98             }
99              
100             {
101             my $subs;
102             sub get_subs {
103 14     14 0 60 require Scalar::Util;
104 14         218 'Scalar::Util'->VERSION( '1.36' );
105              
106 14   100     155 $subs ||= {
107             true => \&_true,
108             false => \&_false,
109             is_bool => \&_is_bool,
110             weaken => \&Scalar::Util::weaken,
111             unweaken => \&Scalar::Util::unweaken,
112             is_weak => \&Scalar::Util::isweak,
113             blessed => \&Scalar::Util::blessed,
114             refaddr => \&Scalar::Util::refaddr,
115             reftype => \&Scalar::Util::reftype,
116             weaken => \&Scalar::Util::weaken,
117             created_as_string => \&_created_as_string,
118             created_as_number => \&_created_as_number,
119             ceil => \&_ceil, # POSIX::ceil has wrong prototype
120             floor => \&_floor, # POSIX::floor has wrong prototype
121             trim => \&_trim,
122             indexed => \&_indexed,
123             };
124             }
125             }
126              
127             if ( LEGACY_PERL ) {
128             my $subs = __PACKAGE__->get_subs;
129             while ( my ( $name, $code ) = each %$subs ) {
130 7     7   43 no strict 'refs';
  7         19  
  7         2962  
131             *{"builtin::$name"} = $code
132             unless exists &{"builtin::$name"};
133             }
134             }
135              
136             sub _is_bool ($) {
137 40     40   2285 my $value = shift;
138              
139 40 100       78 return _false unless defined $value;
140 39 100       89 return _false if ref $value;
141 35 100       134 return _false unless Scalar::Util::isdual( $value );
142 13 50 66     73 return _true if $value && "$value" eq '1' && $value+0 == 1;
      66        
143 7 50 33     88 return _true if !$value && "$value" eq q'' && $value+0 == 0;
      33        
144 0         0 return _false;
145             }
146              
147             sub _created_as_number ($) {
148 42     42   140 my $value = shift;
149              
150 42 50       100 return _false if utf8::is_utf8($value);
151              
152 42         173 require B;
153 42         144 my $b_obj = B::svref_2object(\$value);
154 42         114 my $flags = $b_obj->FLAGS;
155 42 100 100     166 return _true if $flags & ( B::SVp_IOK() | B::SVp_NOK() ) and !( $flags & B::SVp_POK() );
156 26         109 return _false;
157             }
158              
159             sub _created_as_string ($) {
160 25     25   46 my $value = shift;
161              
162 25 100 100     114 defined($value)
      100        
163             && !ref($value)
164             && !_is_bool($value)
165             && !_created_as_number($value);
166             }
167              
168             sub _indexed {
169 2     2   4 my $ix = 0;
170 2         17 return map +( $ix++, $_ ), @_;
171             }
172              
173             sub _trim {
174 2     2   4 my $value = shift;
175              
176 2         14 $value =~ s{\A\s+|\s+\z}{}g;
177 2         10 return $value;
178             }
179              
180             sub _ceil ($) {
181 2     2   12 require POSIX;
182 2         17 return POSIX::ceil( $_[0] );
183             }
184              
185             sub _floor ($) {
186 2     2   876 require POSIX;
187 2         10595 return POSIX::floor( $_[0] );
188             }
189              
190             1;
191              
192             __END__