File Coverage

lib/Data/Hopen/Util/Data.pm
Criterion Covered Total %
statement 50 50 100.0
branch 32 32 100.0
condition 8 8 100.0
subroutine 10 10 100.0
pod 4 4 100.0
total 104 104 100.0


line stmt bran cond sub pod time code
1             # Data::Hopen::Util::Data - general-purpose data-manipulation functions
2             package Data::Hopen::Util::Data;
3 19     19   122 use Data::Hopen;
  19         40  
  19         1360  
4 19     19   141 use strict;
  19         73  
  19         593  
5 19     19   92 use Data::Hopen::Base;
  19         50  
  19         152  
6              
7             our $VERSION = '0.000021';
8              
9 19     19   5475 use parent 'Exporter';
  19         41  
  19         178  
10             our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS);
11             BEGIN {
12 19     19   3164 @EXPORT = qw();
13 19         71 @EXPORT_OK = qw(boolify clone dedent forward_opts identical);
14 19         780 %EXPORT_TAGS = (
15             default => [@EXPORT],
16             all => [@EXPORT, @EXPORT_OK]
17             );
18             }
19              
20 19     19   164 use Scalar::Util qw( refaddr blessed );
  19         87  
  19         18768  
21              
22             # Docs {{{1
23              
24             =head1 NAME
25              
26             Data::Hopen::Util::Data - general-purpose data-manipulation functions
27              
28             =head1 FUNCTIONS
29              
30             Nothing is exported by default --- specify C<:all> if you want it all.
31              
32             =cut
33              
34             # }}}1
35              
36             =head2 boolify
37              
38             Convert a scalar to a Boolean as Perl does, except:
39              
40             =over
41              
42             =item * Falsy
43              
44             C
45              
46             =back
47              
48             So C, C, C, empty string, C, numeric C<0>, and
49             string C<'0'> are falsy, and all other values are truthy.
50              
51             =cut
52              
53             sub boolify {
54 9 100 100 9 1 4784 return false if ($_[0]//'') =~ /^(false|off|no)$/i;
55 6         27 return !!$_[0];
56             } #boolify()
57              
58             =head2 clone
59              
60             Clones a scalar or a reference. Thin wrapper around L.
61              
62             =cut
63              
64             sub clone {
65 25     25 1 434 my $val = shift;
66 25 100       178 return $val unless ref($val);
67 1         103 return Storable::dclone($val);
68             } #clone()
69              
70             =head2 dedent
71              
72             Yet Another routine for dedenting multiline strings. Removes the leading
73             horizontal whitespace on the first nonblank line from all lines. If the first
74             argument is a reference, also trims for use in multiline C/C.
75             Usage:
76              
77             dedent " some\n multiline string";
78             dedent [], q(
79             very indented
80             ); # [] (or any ref) means do the extra trimming.
81              
82             The extra trimming includes:
83              
84             =over
85              
86             =item *
87              
88             Removing the initial C<\n>, if any; and
89              
90             =item *
91              
92             Removing trailing horizontal whitespace between the last C<\n> and the
93             end of the string.
94              
95             =back
96              
97             =cut
98              
99             sub dedent {
100 16 100 100 16 1 22539 my $extra_trim = (@_ && ref $_[0]) ? (shift, true) : false;
101 16 100       42 my $val = @_ ? $_[0] : $_;
102 16         31 my $initial_NL;
103              
104 16 100       49 if(substr($val, 0, 1) eq "\n") {
105 4         9 $initial_NL = true;
106 4         10 $val = substr($val, 1);
107             }
108              
109             # Find first nonblank
110 16         27 my $ws;
111 16         116 while($val =~ m/^(.*)$/mg) {
112 18         56 my $line = $1;
113 18 100       109 if($line =~ m/^(?\h+)\S/m) { # nonblank with leading ws
    100          
114 6         45 $ws = $+{ws};
115 6         19 last;
116             } elsif($line =~ m/\S/) { # nonblank without leading ws
117 10         120 last;
118             }
119             }
120              
121             # Strip leading WS
122 16 100       136 $val =~ s/^\Q$ws\E//gm if defined $ws;
123              
124 16 100       52 $val =~ s/^\h+\z//m if $extra_trim;
125              
126 16 100 100     106 return (($initial_NL && !$extra_trim) ? "\n" : '') . $val;
127             } #dedent()
128              
129             =head2 forward_opts
130              
131             Returns a list of key-value pairs extracted from a given hashref. Usage:
132              
133             my %forwarded_opts = forward_opts(\%original_opts, [option hashref,]
134             'name'[, 'name2'...]);
135              
136             If the option hashref is given, the following can be provided:
137              
138             =over
139              
140             =item lc
141              
142             If truthy, lower-case the key names in the output
143              
144             =item '-'
145              
146             If present, add C<-> to the beginning of each name in the output.
147             This is useful with L.
148              
149             =back
150              
151             =cut
152              
153             sub forward_opts {
154 745 100   745 1 8082 my $hrIn = shift or croak 'Need an input option set';
155 744 100       3951 croak 'Need a hashref' unless ref $hrIn eq 'HASH';
156 743         1187 my $hrOpts = {};
157 743 100       2092 $hrOpts = shift if ref $_[0] eq 'HASH';
158              
159 743         1106 my %result;
160 743         1534 foreach my $name (@_) {
161 1283 100       3240 next unless exists $hrIn->{$name};
162              
163 883 100       1986 my $newname = $hrOpts->{lc} ? lc($name) : $name;
164 883 100       2270 $newname = "-$newname" if $hrOpts->{'-'};
165 883         2523 $result{$newname} = $hrIn->{$name}
166             }
167              
168 743         4140 return %result;
169             } #forward_opts()
170              
171             # The following are commented out as they are not currently in use.
172             #=head2 identical
173             #
174             #Return truthy if the given parameters are identical objects.
175             #Taken from L by Paul Evans, which is licensed under the same
176             #terms as Perl itself.
177             #
178             #=cut
179             #
180             #sub _describe
181             #{
182             # my ( $ref ) = @_;
183             #
184             # if( !defined $ref ) {
185             # return "undef";
186             # }
187             # elsif( !refaddr $ref ) {
188             # return "a non-reference";
189             # }
190             # elsif( blessed $ref ) {
191             # return "a reference to a " . ref( $ref );
192             # }
193             # else {
194             # return "an anonymous " . ref( $ref ) . " ref";
195             # }
196             #} #_describe()
197             #
198             #sub identical($$)
199             #{
200             # my ( $got, $expected ) = @_;
201             #
202             # my $got_desc = _describe $got;
203             # my $exp_desc = _describe $expected;
204             #
205             # # TODO: Consider if undef/undef ought to do this...
206             # if( $got_desc ne $exp_desc ) {
207             # return false;
208             # }
209             #
210             # if( !defined $got ) {
211             # # Two undefs
212             # return true;
213             # }
214             #
215             # my $got_addr = refaddr $got;
216             # my $exp_addr = refaddr $expected;
217             #
218             # if( $got_addr != $exp_addr ) {
219             # return false;
220             # }
221             #
222             # return true;
223             #} #identical()
224              
225             1;
226             __END__