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