File Coverage

blib/lib/perl5i/2/SCALAR.pm
Criterion Covered Total %
statement 117 128 91.4
branch 50 58 86.2
condition 13 31 41.9
subroutine 30 33 90.9
pod 0 25 0.0
total 210 275 76.3


line stmt bran cond sub pod time code
1             # vi: set ts=4 sw=4 ht=4 et :
2             package perl5i::2::SCALAR;
3 101     101   1870 use 5.010;
  101         285  
  101         3879  
4              
5 101     101   455 use strict;
  101         163  
  101         3014  
6 101     101   418 use warnings;
  101         138  
  101         3018  
7             require Carp::Fix::1_25;
8 101     101   434 use perl5i::2::autobox;
  101         228  
  101         572  
9              
10             sub title_case {
11 4     4 0 31 my ($string) = @_;
12 4         36 $string =~ s/\b(\w)/\U$1/g;
13 4         16 return $string;
14             }
15              
16              
17             sub center {
18 27     27 0 6803 my ($string, $size, $char) = @_;
19 27 100       76 Carp::Fix::1_25::carp("Use of uninitialized value for size in center()") if !defined $size;
20 27   100     524 $size //= 0;
21 27   100     78 $char //= ' ';
22              
23 27 100       55 if (length $char > 1) {
24 1         2 my $bad = $char;
25 1         2 $char = substr $char, 0, 1;
26 1         12 Carp::Fix::1_25::carp("'$bad' is longer than one character, using '$char' instead");
27             }
28              
29 27         412 my $len = length $string;
30              
31 27 100       57 return $string if $size <= $len;
32              
33 21         24 my $padlen = $size - $len;
34              
35             # pad right with half the remaining characters
36 21         36 my $rpad = int( $padlen / 2 );
37              
38             # bias the left padding to one more space, if $size - $len is odd
39 21         21 my $lpad = $padlen - $rpad;
40              
41 21         103 return $char x $lpad . $string . $char x $rpad;
42             }
43              
44              
45             sub ltrim {
46 44     44 0 56 my ($string,$trim_charset) = @_;
47 44 100       93 $trim_charset = '\s' unless defined $trim_charset;
48 44         267 my $re = qr/^[$trim_charset]*/;
49 44         197 $string =~ s/$re//;
50 44         144 return $string;
51             }
52              
53              
54             sub rtrim {
55 44     44 0 55 my ($string,$trim_charset) = @_;
56 44 100       88 $trim_charset = '\s' unless defined $trim_charset;
57 44         220 my $re = qr/[$trim_charset]*$/;
58 44         211 $string =~ s/$re//;
59 44         153 return $string;
60             }
61              
62              
63             sub trim {
64 28     28 0 34 my $charset = $_[1];
65              
66 28         55 return rtrim(ltrim($_[0], $charset), $charset);
67             }
68              
69              
70             sub wrap {
71 30     30 0 20712 my ($string, %args) = @_;
72              
73 30   100     98 my $width = $args{width} // 76;
74 30   50     96 my $separator = $args{separator} // "\n";
75              
76 30 100       90 return $string if $width <= 0;
77              
78 18         650 require Text::Wrap;
79 18         2663 local $Text::Wrap::separator = $separator;
80 18         17 local $Text::Wrap::columns = $width;
81              
82 18         48 return Text::Wrap::wrap('', '', $string);
83              
84             }
85              
86              
87             # Always reverse the scalar, not a single element list.
88             sub reverse {
89 2     2 0 9 return scalar CORE::reverse $_[0];
90             }
91              
92              
93             # Compatiblity wrappers. Remove in 3.0.
94             sub untaint {
95 1     1 0 6 return $_[0]->mo->untaint;
96             }
97              
98             sub taint {
99 1     1 0 5 return $_[0]->mo->taint;
100             }
101              
102             sub is_tainted {
103 3     3 0 327 return $_[0]->mo->is_tainted;
104             }
105              
106              
107             sub require {
108 37     37 0 1881 my $error = do {
109             # Don't let them leak out or get reset
110 37         141 local($!,$@);
111 37 100       45 return $_[0] if eval { require $_[0]->module2path };
  37         135  
112 2         7 $@;
113             };
114              
115 2         5 my($pack, $file, $line) = caller;
116 2         17 $error =~ s{ at .*? line .*?\.\n$}{ at $file line $line.\n};
117 2         10 die $error;
118             }
119              
120              
121             sub alias {
122 3 100   3 0 1733 Carp::Fix::1_25::croak(<<ERROR) if !ref $_[0];
123             Due to limitations in autoboxing, scalars cannot be aliased.
124             Sorry. Use a scalar reference instead.
125             ERROR
126              
127 2         8 goto &perl5i::2::UNIVERSAL::alias;
128             }
129              
130              
131             require POSIX;
132             *ceil = \&POSIX::ceil;
133             *floor = \&POSIX::floor;
134             *round_up = \&ceil;
135             *round_down = \&floor;
136             sub round {
137 7 100   7 0 3560 return 0 if $_[0] == 0;
138              
139 6 100       23 if( $_[0]->is_positive ) {
140 3 100       21 abs($_[0] - int($_[0])) < 0.5 ? round_down($_[0])
141             : round_up($_[0])
142             }
143             else {
144 3 100       24 abs($_[0] - int($_[0])) < 0.5 ? round_up($_[0])
145             : round_down($_[0])
146             }
147             }
148              
149             require Scalar::Util;
150             *is_number = \&Scalar::Util::looks_like_number;
151 32 100   32 0 832 sub is_positive { $_[0]->is_number && $_[0] > 0 }
152 7 100   7 0 276 sub is_negative { $_[0]->is_number && $_[0] < 0 }
153             sub is_integer {
154 43 100   43 0 952 return 0 if !$_[0]->is_number;
155 38         365 return $_[0] =~ m{ ^[+-]? \d+ $}x;
156             }
157             *is_int = \&is_integer;
158 5 100   5 0 20 sub is_even { $_[0]->is_integer && !($_[0] % 2) }
159 5 100   5 0 16 sub is_odd { $_[0]->is_integer && ($_[0] % 2) }
160             sub is_decimal {
161 9 100   9 0 268 return 0 if !$_[0]->is_number;
162              
163             # Fast and reliable way to spot most decimals
164 7 100       30 return 1 if ((int($_[0]) - $_[0]) != 0);
165              
166             # Final gate for tricky things like 1.0, 1. and .0
167 5         28 return $_[0] =~ m{^ [+-]? (?: \d+\.\d* | \.\d+ ) $}x;
168             }
169              
170             sub group_digits {
171 15     15 0 17 my($self, $opts) = @_;
172              
173 15         16 state $defaults = {
174             thousands_sep => ",",
175             grouping => 3,
176             decimal_point => ".",
177             };
178              
179 15         15 my $is_money = $opts->{currency};
180 15   0     39 my $sep = $opts->{separator} // (_get_from_locale("thousands_sep", $is_money)
      33        
181             || $defaults->{thousands_sep});
182 15   0     27 my $grouping = $opts->{grouping} // (_get_grouping($is_money)
      33        
183             || $defaults->{grouping});
184 15   0     24 my $decimal_point = $opts->{decimal_point} // (_get_from_locale("decimal_point", $is_money)
      33        
185             || $defaults->{decimal_point});
186 15 100       30 return $self if $grouping == 0;
187              
188 14         49 my($integer, $decimal) = split m{\.}, $self, 2;
189              
190 14         20 $integer = CORE::reverse $integer;
191 14         161 $integer =~ s/(\d{$grouping})(?=\d)(?!\d*\.)/$1$sep/g;
192 14         21 $integer = CORE::reverse $integer;
193              
194 14         16 my $number = $integer;
195 14 100       22 $number .= $decimal_point . $decimal if defined $decimal;
196              
197 14         80 return $number;
198             }
199              
200             sub commify {
201 15     15 0 2302 my($self, $args) = @_;
202              
203 15         19 state $defaults = {
204             separator => ",",
205             grouping => 3,
206             decimal_point => ".",
207             };
208              
209 15         58 my $opts = $defaults->merge($args);
210              
211 15         50 return $self->group_digits( $opts );
212             }
213              
214              
215             sub _get_lconv {
216 0   0 0   0 return eval {
217             require POSIX;
218             POSIX::localeconv();
219             } || {};
220             }
221              
222             sub _get_grouping {
223 0     0   0 my $is_money = shift;
224 0 0       0 my $key = $is_money ? "mon_grouping" : "grouping";
225              
226 0         0 my $lconv = _get_lconv;
227              
228 0 0       0 if( $lconv->{$key} ) {
229 0         0 return (unpack("C*", $lconv->{$key}))[0];
230             }
231             else {
232 0         0 return;
233             }
234             }
235              
236             sub _get_from_locale {
237 0     0   0 my($key, $is_money) = @_;
238 0 0       0 $key = "mon_$key" if $is_money;
239              
240 0         0 my $lconv = _get_lconv;
241 0         0 return $lconv->{$key};
242             }
243              
244              
245             sub path2module {
246 7     7 0 1171 my $path = shift;
247              
248 7         84 my($vol, $dirs, $file) = File::Spec->splitpath($path);
249 7         42 my @dirs = grep length, File::Spec->splitdir($dirs);
250              
251 7 100 100     393 Carp::Fix::1_25::croak("'$path' does not look like a Perl module path")
252             if $file !~ m{\.pm$} or File::Spec->file_name_is_absolute($path);
253              
254 4         15 $file =~ s{\.pm$}{};
255              
256 4         5 my $module = join "::", @dirs, $file;
257 4 50       13 Carp::Fix::1_25::croak("'$module' is not a valid module name") unless $module->is_module_name;
258              
259 4         11 return $module;
260             }
261              
262              
263             sub is_module_name {
264 60     60 0 2711 my $name = shift;
265              
266 60 50       122 return 0 unless defined($name);
267              
268 60 100       1053 return 0 unless $name =~ qr{\A
269             [[:alpha:]_] # Must start with an alpha or _
270             [[:word:]]* # Then any number of alpha numerics or _
271             (?: :: [[:word:]]+ )* # Then optional ::word's
272             \z
273             }x;
274              
275 50         171 return 1;
276             }
277              
278              
279             sub module2path {
280 44     44 0 2430 my $module = shift;
281              
282 44 100       113 Carp::Fix::1_25::croak("'$module' is not a valid module name") unless $module->is_module_name;
283              
284 40         126 my @parts = split /::/, $module;
285 40         57 $parts[-1] .= ".pm";
286              
287 40         1884 return join "/", @parts;
288             }
289              
290              
291             # On the first call, load Path::Tiny and replace our path() with
292             # Path::Tiny::path() so we don't try to load it again.
293             # Shaves about 1/6 off the call time.
294             sub path {
295 1     1 0 994 require Path::Tiny;
296 101     101   254914 no warnings 'redefine';
  101         202  
  101         8773  
297 1         8455 *path = \&Path::Tiny::path;
298 1         4 goto &Path::Tiny::path;
299             }
300              
301             1;