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   69325 use strict;
  1         2  
  1         28  
3 1     1   4 use warnings;
  1         2  
  1         45  
4              
5             our $VERSION = '0.002000';
6             $VERSION =~ tr/_//d;
7              
8 1     1   522 use namespace::clean ();
  1         16423  
  1         115  
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   2 BEGIN { eval { require builtin } }
  1         576  
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   6 use Scalar::Util ();
  1         2  
  1         97  
41             sub is_bool ($) {
42 20     20 1 946 my $value = shift;
43              
44             return (
45 20   66     275 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 18 my $value = shift;
65              
66 1     1   6 no warnings 'numeric';
  1         2  
  1         157  
67             return (
68 9   100     45 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 2933 my $value = shift;
81              
82             return (
83 5   100     36 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   588 use POSIX ();
  1         6943  
  1         51  
92             sub ceil ($) {
93 1     1 1 12 goto &POSIX::ceil;
94             }
95             END_CODE
96             floor => sprintf(qq{#line %s "%s"\n}, __LINE__+1, __FILE__).<<'END_CODE',
97 1     1   6 use POSIX ();
  1         2  
  1         110  
98             sub floor ($) {
99 1     1 1 9 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         12 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         10 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   5 no strict 'refs';
  1         2  
  1         592  
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             *{'builtin::'.$sub} = \&$sub;
143             }
144              
145             my $e;
146             {
147             local $@;
148             eval "$code; 1" or $e = $@;
149             }
150             die $e
151             if defined $e;
152              
153             my %EXPORT_OK = map +($_ => 1), @EXPORT_OK;
154              
155             our $NO_DISABLE_WARNINGS;
156             sub import {
157 3     3   9648 my $class = shift;
158              
159             # search for caller that is being compiled. can't just use caller directly,
160             # beause it may not be the same level as builtin would use for its lexical
161             # exports
162 3         4 my $caller;
163 3         5 my $level = 0;
164 3         24 while (my @caller = caller(++$level)) {
165 4 100       28 if ($caller[3] =~ /\A(.*)::BEGIN\z/s) {
166 3         7 $caller = $1;
167 3         9 last;
168             }
169             }
170 3 50       7 if (!defined $caller) {
171 0         0 require Carp;
172 0         0 Carp::croak("builtin::compat::import can only be called at compile time");
173             }
174              
175 3         7 for my $import (@_) {
176 45         136 require Carp;
177             Carp::croak("'$import' is not recognised as a builtin function")
178 45 50       88 if !$EXPORT_OK{$import};
179 45         70 *{$caller.'::'.$import} = \&$import;
  45         156  
180             }
181              
182 3 100       7 unless ($NO_DISABLE_WARNINGS) {
183 2         3 local $@;
184 2         3 eval { warnings->unimport('experimental::builtin') };
  2         29  
185             }
186 3         15 namespace::clean->import(-cleanee => $caller, @_);
187 3         823 return;
188             }
189              
190             if (!defined &builtin::import) {
191             *builtin::import = sub {
192 1     1   18038 local $NO_DISABLE_WARNINGS = 1;
193 1         3 &import;
194             };
195             }
196              
197             $INC{'builtin.pm'} ||= __FILE__;
198              
199             1;
200             __END__