File Coverage

blib/lib/builtins/compat.pm
Criterion Covered Total %
statement 69 76 92.1
branch 22 24 91.6
condition 12 14 85.7
subroutine 17 17 100.0
pod 0 3 0.0
total 120 134 90.3


line stmt bran cond sub pod time code
1 7     7   224015 use 5.008001;
  7         56  
2 7     7   29 use strict;
  7         23  
  7         140  
3 7     7   26 use warnings;
  7         11  
  7         802  
4              
5             package builtins::compat;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.003';
9              
10             sub _true () {
11             !!1;
12             }
13              
14             sub _false () {
15             !!0;
16             }
17              
18             BEGIN {
19             # uncoverable statement
20 7 50   7   2660 *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 15 my $class = shift;
36 7 100       22 my @args = @_ ? @_ : ':5.36';
37              
38 7         12 my $want = {};
39 7         15 for my $arg ( @args ) {
40 7 100       36 if ( $arg =~ /^:(.+)/ ) {
    50          
41 6         18 my $tag = $1;
42 6 100       28 if ( not exists $EXPORT_TAGS{$tag} ) {
43 1         4 require Carp;
44 1         96 Carp::carp( qq["$tag" is not defined in $class\::EXPORT_TAGS] );
45             }
46 6 100       14 $want->{$_} = 1 for @{ $EXPORT_TAGS{$tag} or [] };
  6         48  
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         55 return $want;
58             }
59              
60             sub import {
61 7     7   1325 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 12 my $class = shift;
75              
76 7         16 my $caller = caller;
77 7         15 my $subs = $class->get_subs;
78 7         12 my %want = %{ $class->parse_args( @_ ) };
  7         22  
79              
80 7         69 for my $name ( sort keys %want ) {
81              
82 64 100       105 if ( my $code = $subs->{$name} ) {
83 7     7   42 no strict 'refs';
  7         12  
  7         2166  
84 63         68 *{"$caller\::$name"} = $code;
  63         218  
85             }
86             else {
87 1         4 require Carp;
88 1         156 Carp::carp( qq["$name" is not exported by the $class module] );
89 1         7 delete $want{$name}; # hide from namespace::clean
90             }
91             }
92              
93 7         2346 require namespace::clean;
94 7         77348 'namespace::clean'->import(
95             -cleanee => $caller,
96             keys( %want ),
97             );
98             }
99              
100             {
101             my $subs;
102             sub get_subs {
103 14     14 0 62 require Scalar::Util;
104 14         214 'Scalar::Util'->VERSION( '1.36' );
105              
106 14   100     148 $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   42 no strict 'refs';
  7         16  
  7         2961  
131             *{"builtin::$name"} = $code
132             unless exists &{"builtin::$name"};
133             }
134             }
135              
136             sub _is_bool ($) {
137 40     40   2163 my $value = shift;
138              
139 40 100       75 return _false unless defined $value;
140 39 100       83 return _false if ref $value;
141 35 100       132 return _false unless Scalar::Util::isdual( $value );
142             return !! (
143 13   33     117 ( "$value" eq "1" or "$value" eq "" )
144             and ( $value+0 == 1 or $value+0 == 0 )
145             );
146             }
147              
148             sub _created_as_number ($) {
149 42     42   251 require B;
150              
151 42         54 my $value = shift;
152              
153 42         128 my $b_obj = B::svref_2object(\$value);
154 42         98 my $flags = $b_obj->FLAGS;
155 42 100 100     164 return _true if $flags & ( B::SVp_IOK() | B::SVp_NOK() ) and !( $flags & B::SVp_POK() );
156 26         113 return _false;
157             }
158              
159             sub _created_as_string ($) {
160 25     25   43 my $value = shift;
161              
162 25 100 100     137 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         13 return map { $ix++, $_ } @_;
  6         16  
171             }
172              
173             sub _trim ($) {
174 2     2   5 my $value = shift;
175              
176 2         13 $value =~ s{^\s+|\s+$}{}g;
177 2         7 return $value;
178             }
179              
180             sub _ceil ($) {
181 2     2   9 require POSIX;
182 2         15 return POSIX::ceil( $_[0] );
183             }
184              
185             sub _floor ($) {
186 2     2   842 require POSIX;
187 2         10602 return POSIX::floor( $_[0] );
188             }
189              
190             1;
191              
192             __END__