File Coverage

blib/lib/builtin/compat.pm
Criterion Covered Total %
statement 37 39 94.8
branch 6 10 60.0
condition n/a
subroutine 7 7 100.0
pod n/a
total 50 56 89.2


line stmt bran cond sub pod time code
1             package builtin::compat;
2 2     2   217022 use strict;
  2         4  
  2         106  
3 2     2   13 use warnings;
  2         18  
  2         195  
4              
5             our $VERSION = '0.003003';
6             $VERSION =~ tr/_//d;
7              
8 2     2   1230 use namespace::clean ();
  2         44197  
  2         440  
9              
10             sub true ();
11             sub false ();
12             sub is_bool ($);
13             sub inf ();
14             sub nan ();
15             sub weaken ($);
16             sub unweaken ($);
17             sub is_weak ($);
18             sub blessed ($);
19             sub refaddr ($);
20             sub reftype ($);
21             sub created_as_string ($);
22             sub created_as_number ($);
23             sub stringify ($);
24             sub ceil ($);
25             sub floor ($);
26             sub trim ($);
27             sub indexed (@);
28             sub load_module ($);
29              
30 2     2   11 BEGIN { eval { require builtin } }
  2         1233  
31             {
32             package #hide
33             experimental::builtin;
34             if(!$warnings::Offsets{+__PACKAGE__}) {
35             require warnings::register;
36             warnings::register->import;
37             }
38             }
39              
40             my @fb = (
41             true => 'sub true () { !!1 }',
42             false => 'sub false () { !!0 }',
43             is_bool => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
44             use Scalar::Util ();
45             sub is_bool ($) {
46             my $value = shift;
47              
48             return (
49             defined $value
50             && !length ref $value
51             && Scalar::Util::isdual($value)
52             && (
53             $value
54             ? ( $value == 1 && $value eq '1' )
55             : ( $value == 0 && $value eq '' )
56             )
57             );
58             }
59             END_CODE
60             inf => 'sub inf () { 9**9**9**9 }',
61             nan => 'sub nan () { 9**9**9**9*0 }',
62             weaken => \'Scalar::Util::weaken',
63             unweaken => \'Scalar::Util::unweaken',
64             is_weak => \'Scalar::Util::isweak',
65             blessed => \'Scalar::Util::blessed',
66             refaddr => \'Scalar::Util::refaddr',
67             reftype => \'Scalar::Util::reftype',
68             created_as_number => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
69             sub created_as_number ($) {
70             my $value = shift;
71              
72             no warnings 'numeric';
73             return (
74             defined $value
75             && !length ref $value
76             && !is_bool($value)
77             && !utf8::is_utf8($value)
78             && length( (my $dummy = '') & $value )
79             && 0 + $value eq $value
80             );
81             }
82              
83             END_CODE
84             created_as_string => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
85             sub created_as_string ($) {
86             my $value = shift;
87              
88             return (
89             defined $value
90             && !length ref $value
91             && !is_bool($value)
92             && !created_as_number($value)
93             );
94             }
95             END_CODE
96             stringify => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
97             sub stringify ($) {
98             "$_[0]"
99             }
100             END_CODE
101             ceil => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
102             use POSIX ();
103             sub ceil ($) {
104             goto &POSIX::ceil;
105             }
106             END_CODE
107             floor => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
108             use POSIX ();
109             sub floor ($) {
110             goto &POSIX::floor;
111             }
112             END_CODE
113             trim => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
114             sub trim ($) {
115             my $string = shift;
116             s/\A\s+//, s/\s+\z// for $string;
117             return $string;
118             }
119             END_CODE
120             indexed => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
121             sub indexed (@) {
122             my $i = 0;
123             map +($i++, $_), @_;
124             }
125             END_CODE
126             is_tainted => \'Scalar::Util::tainted',
127             load_module => ( ( "$]" < 5.011 && !("$]" >= 5.009004 && "$]" < 5.010001) )
128             ? sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE'
129             sub builtin::compat::load_module::__GUARD__::DESTROY {
130             delete $INC{$_[0]->[0]} if @{$_[0]};
131             }
132              
133             sub load_module ($) {
134             my $module = $_[0];
135             (my $file = $module) =~ s{::}{/}g;
136             $file .= ".pm";
137              
138             local %^H;
139             my $guard = bless [ $file ], 'builtin::compat::load_module::__GUARD__';
140             CORE::require($file);
141             pop @$guard;
142              
143             return $module;
144             }
145             END_CODE
146             : sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE'
147             sub load_module ($) {
148             my $module = $_[0];
149             (my $file = $module) =~ s{::}{/}g;
150             $file .= ".pm";
151             CORE::require($file);
152             return $module;
153             }
154             END_CODE
155             ),
156             );
157              
158             my @EXPORT_OK;
159              
160             my $code = '';
161              
162 2     2   1267 no strict 'refs';
  2         28  
  2         207  
163              
164             while (my ($sub, $fb) = splice @fb, 0, 2) {
165             push @EXPORT_OK, $sub;
166             if (defined &{'builtin::'.$sub}) {
167 2     2   15 no warnings 'prototype';
  2         4  
  2         2026  
168             *$sub = \&{'builtin::'.$sub};
169             next;
170             }
171             if (ref $fb) {
172             my ($mod) = $$fb =~ /\A(.*)::/s;
173             (my $file = "$mod.pm") =~ s{::}{/}g;
174             require $file;
175             die "Unable to find $$fb"
176             unless defined &{$$fb};
177             *$sub = \&{$$fb};
178             }
179             else {
180             $code .= $fb . "\n";
181             }
182              
183             if (!defined &{'builtin::'.$sub}) {
184             my $subref = \&$sub;
185             if ($] < '5.038000' && (ref $fb || prototype($subref) eq '')) {
186             require Scalar::Util;
187             my $wrap = sub { goto &$subref };
188             Scalar::Util::set_prototype(\&$wrap, prototype($subref));
189             *{'builtin::'.$sub} = $wrap;
190             }
191             else {
192             *{'builtin::'.$sub} = $subref;
193             }
194             }
195             }
196              
197             my $e;
198             {
199             local $@;
200             eval "$code; 1" or $e = $@;
201             }
202             die $e
203             if defined $e;
204              
205             my %EXPORT_OK = map +($_ => 1), @EXPORT_OK;
206              
207             our $NO_DISABLE_WARNINGS;
208             sub import {
209 3     3   87547 my $class = shift;
210             return
211 3 100       2160 unless @_;
212              
213             # search for caller that is being compiled. can't just use caller directly,
214             # beause it may not be the same level as builtin would use for its lexical
215             # exports
216 2         5 my $caller;
217 2         3 my $level = 0;
218 2         19 while (my @caller = caller(++$level)) {
219 2 50       19 if ($caller[3] =~ /\A(.*)::BEGIN\z/s) {
220 2         7 $caller = $1;
221 2         8 last;
222             }
223             }
224 2 50       9 if (!defined $caller) {
225 0         0 require Carp;
226 0         0 Carp::croak("builtin::compat::import can only be called at compile time");
227             }
228              
229 2         6 for my $import (@_) {
230 38         124 require Carp;
231             Carp::croak("'$import' is not recognised as a builtin function")
232 38 50       91 if !$EXPORT_OK{$import};
233 38         76 *{$caller.'::'.$import} = \&$import;
  38         152  
234             }
235              
236 2 50       8 unless ($NO_DISABLE_WARNINGS) {
237 2         5 local $@;
238 2         4 eval { warnings->unimport('experimental::builtin') };
  2         68  
239             }
240 2         17 namespace::clean->import(-cleanee => $caller, @_);
241 2         1491 return;
242             }
243              
244             if (!defined &builtin::import) {
245             *builtin::import = sub {
246             local $NO_DISABLE_WARNINGS = 1;
247             &import;
248             };
249             }
250              
251             $INC{'builtin.pm'} ||= __FILE__;
252              
253             1;
254             __END__