File Coverage

blib/lib/builtin/compat.pm
Criterion Covered Total %
statement 60 62 96.7
branch 6 8 75.0
condition 8 9 88.8
subroutine 18 18 100.0
pod 7 7 100.0
total 99 104 95.1


line stmt bran cond sub pod time code
1             package builtin::compat;
2 1     1   55304 use strict;
  1         3  
  1         24  
3 1     1   5 use warnings;
  1         1  
  1         40  
4              
5             our $VERSION = '0.001002';
6             $VERSION =~ tr/_//d;
7              
8 1     1   759 use namespace::clean ();
  1         12822  
  1         94  
9              
10             sub true ();
11             sub false ();
12             sub is_bool ($);
13             sub weaken ($);
14             sub unweaken ($);
15             sub is_weak ($);
16             sub blessed ($);
17             sub refaddr ($);
18             sub reftype ($);
19             sub created_as_string ($);
20             sub created_as_number ($);
21             sub ceil ($);
22             sub floor ($);
23             sub trim;
24             sub indexed;
25              
26 1     1   3 BEGIN { eval { require builtin } }
  1         415  
27              
28             my @fb = (
29             true => 'sub true () { !!1 }',
30             false => 'sub false () { !!0 }',
31             is_bool => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
32 1     1   6 use Scalar::Util ();
  1         1  
  1         87  
33             sub is_bool ($) {
34 20     20 1 731 my $value = shift;
35              
36             return (
37 20   66     221 defined $value
38             && !length ref $value
39             && Scalar::Util::isdual($value)
40             && (
41             $value
42             ? ( $value == 1 && $value eq '1' )
43             : ( $value == 0 && $value eq '' )
44             )
45             );
46             }
47             END_CODE
48             weaken => \'Scalar::Util::weaken',
49             unweaken => \'Scalar::Util::unweaken',
50             is_weak => \'Scalar::Util::isweak',
51             blessed => \'Scalar::Util::blessed',
52             refaddr => \'Scalar::Util::refaddr',
53             reftype => \'Scalar::Util::reftype',
54             created_as_number => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
55             sub created_as_number ($) {
56 9     9 1 14 my $value = shift;
57              
58 1     1   6 no warnings 'numeric';
  1         1  
  1         113  
59             return (
60 9   100     32 defined $value
61             && !length ref $value
62             && !is_bool($value)
63             && !utf8::is_utf8($value)
64             && length( (my $dummy = '') & $value )
65             && 0 + $value eq $value
66             );
67             }
68              
69             END_CODE
70             created_as_string => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
71             sub created_as_string ($) {
72 5     5 1 2318 my $value = shift;
73              
74             return (
75 5   100     22 defined $value
76             && !length ref $value
77             && !is_bool($value)
78             && !created_as_number($value)
79             );
80             }
81             END_CODE
82             ceil => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
83 1     1   440 use POSIX ();
  1         5249  
  1         42  
84             sub ceil ($) {
85 1     1 1 14 goto &POSIX::ceil;
86             }
87             END_CODE
88             floor => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
89 1     1   7 use POSIX ();
  1         2  
  1         92  
90             sub floor ($) {
91 1     1 1 7 goto &POSIX::floor;
92             }
93             END_CODE
94             trim => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
95             sub trim {
96 1     1 1 2 my $string = shift;
97 1         9 s/\A\s+//, s/\s+\z// for $string;
98 1         5 return $string;
99             }
100             END_CODE
101             indexed => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
102             sub indexed {
103 1     1 1 2 my $i = 0;
104 1         7 map +($i++, $_), @_;
105             }
106             END_CODE
107             );
108              
109             my @EXPORT_OK;
110              
111             my $code = '';
112              
113 1     1   6 no strict 'refs';
  1         1  
  1         480  
114              
115             while (my ($sub, $fb) = splice @fb, 0, 2) {
116             push @EXPORT_OK, $sub;
117             if (defined &{'builtin::'.$sub}) {
118             *$sub = \&{'builtin::'.$sub};
119             next;
120             }
121             if (ref $fb) {
122             my ($mod) = $$fb =~ /\A(.*)::/s;
123             (my $file = "$mod.pm") =~ s{::}{/}g;
124             require $file;
125             die "Unable to find $$fb"
126             unless defined &{$$fb};
127             *$sub = \&{$$fb};
128             }
129             else {
130             $code .= $fb . "\n";
131             }
132              
133             *{'builtin::'.$sub} = \&$sub;
134             }
135              
136             my $e;
137             {
138             local $@;
139             eval "$code; 1" or $e = $@;
140             }
141             die $e
142             if defined $e;
143              
144             my %EXPORT_OK = map +($_ => 1), @EXPORT_OK;
145              
146             our $NO_DISABLE_WARNINGS;
147             sub import {
148 3     3   8004 my $class = shift;
149              
150             # search for caller that is being compiled. can't just use caller directly,
151             # beause it may not be the same level as builtin would use for its lexical
152             # exports
153 3         4 my $caller;
154 3         5 my $level = 0;
155 3         20 while (my @caller = caller(++$level)) {
156 4 100       23 if ($caller[3] =~ /\A(.*)::BEGIN\z/s) {
157 3         7 $caller = $1;
158 3         7 last;
159             }
160             }
161 3 50       7 if (!defined $caller) {
162 0         0 require Carp;
163 0         0 Carp::croak("builtin::compat::import can only be called at compile time");
164             }
165              
166 3         6 for my $import (@_) {
167 45         113 require Carp;
168             Carp::croak("'$import' is not recognised as a builtin function")
169 45 50       75 if !$EXPORT_OK{$import};
170 45         64 *{$caller.'::'.$import} = \&$import;
  45         152  
171             }
172              
173 3 100       7 unless ($NO_DISABLE_WARNINGS) {
174 2         2 local $@;
175 2         4 eval { warnings->unimport('experimental::builtin') };
  2         288  
176             }
177 3         20 namespace::clean->import(-cleanee => $caller, @_);
178 3         651 return;
179             }
180              
181             if (!defined &builtin::import) {
182             *builtin::import = sub {
183 1     1   15048 local $NO_DISABLE_WARNINGS = 1;
184 1         2 &import;
185             };
186             }
187              
188             $INC{'builtin.pm'} ||= __FILE__;
189              
190             1;
191             __END__