File Coverage

blib/lib/Zeta/Util.pm
Criterion Covered Total %
statement 109 120 90.8
branch 33 46 71.7
condition 15 21 71.4
subroutine 28 28 100.0
pod 13 13 100.0
total 198 228 86.8


line stmt bran cond sub pod time code
1             ##############################################################################
2             #
3             # NAME: Zeta::Util
4             # Author: Gregory S. Youngblood
5             # Copyright 1995-2012 Gregory S. Youngblood, all rights reserved.
6             #
7             ##############################################################################
8             package Zeta::Util;
9              
10             =head1 NAME
11              
12             Zeta::Util
13              
14             =cut
15              
16             ##############################################################################
17             # Version
18             ##############################################################################
19              
20             =head1 VERSION
21              
22             Version 0.02
23              
24             =cut
25              
26             BEGIN {
27 8     8   171804 our $VERSION = '0.02';
28             }
29              
30             ##############################################################################
31             # Description
32             ##############################################################################
33              
34             =head1 SYNOPSIS
35              
36             use Zeta::Util qw(:ALL);
37             ...
38             sub example {
39             my %opts = get_opts(@_);
40             ...
41             }
42            
43             =cut
44              
45             ##############################################################################
46             # Pull in additional modules
47             ##############################################################################
48              
49 8     8   70 use strict;
  8         14  
  8         227  
50 8     8   39 use warnings;
  8         15  
  8         213  
51 8     8   50 use Carp;
  8         21  
  8         778  
52              
53 8     8   48 use B qw(svref_2object);
  8         14  
  8         461  
54 8     8   70 use Fcntl qw(:mode);
  8         27  
  8         2578  
55 8     8   55 use File::Basename;
  8         14  
  8         933  
56              
57             ##############################################################################
58             # Define Exports
59             ##############################################################################
60 8     8   40 use Exporter 'import';
  8         15  
  8         300  
61 8     8   45 use vars qw(@EXPORT @EXPORT_OK %EXPORT_TAGS);
  8         15  
  8         1398  
62             @EXPORT = ();
63             @EXPORT_OK = (qw(
64             TRUE
65             FALSE
66             get_opts
67             is_numeric is_float is_int is_string
68             is_type_float is_type_int is_type_string
69             get_file_details
70             is_mod_perl
71             is_empty is_blank no_undef
72             ));
73             %EXPORT_TAGS = (
74             ALL => [ @EXPORT, @EXPORT_OK ],
75             BOOL => [ qw(TRUE FALSE) ],
76             DATATYPE => [ qw(is_numeric is_float is_int is_string) ],
77             PERLTYPE => [ qw(is_type_string is_type_int is_type_float ) ],
78             FILE => [ qw(get_file_details) ],
79             ENV => [ qw(is_mod_perl) ],
80             STRING => [ qw(is_empty is_blank no_undef) ],
81             );
82              
83             =head1 EXPORT
84              
85             Nothing is exported by default. The following items are available:
86              
87             =cut
88              
89             ##############################################################################
90             # Set Defaults, declare globals, etc.
91             ##############################################################################
92              
93             # constants
94 8     8   53 use constant TRUE => 1;
  8         15  
  8         741  
95 8     8   46 use constant FALSE => 0;
  8         21  
  8         5964  
96              
97             # scalars
98             our $get_opts_scalar_key = 'arg1';
99              
100             # arrays/lists
101              
102             # hashes
103             our %FILE_TYPES = (
104             S_IFBLK, 'block', # -b
105             S_IFCHR, 'char', # -c
106             S_IFDIR, 'dir', # -d
107             S_IFREG, 'file', # -f
108             S_IFLNK, 'link', # -l
109             S_IFIFO, 'pipe', # -p
110             S_IFSOCK, 'socket', # -S
111             );
112              
113             ##############################################################################
114             #
115             # Module Code
116             #
117             ##############################################################################
118              
119             ##############################################################################
120             =head1 FUNCTIONS
121             ##############################################################################
122              
123             =head2 get_opts
124              
125             Generic method of getting arguments passed to a function as a hash or an array.
126             Automatically converts a hash reference into a hash. If a single scalar
127             argument or an object reference is passed then it will be returned as a hash
128             using the key defined by $Zeta::Util::get_opts_scalar_key (default:arg1).
129             An array reference or an odd number of arguments will be converted and returned
130             as a list (array).
131              
132             NOTE: If an odd number of arguments are passed and returned as a list (array),
133             and a hash is expected, and warnings are enabled (use warnings), then the
134             warning "Odd number of elements in hash assignment" will be displayed.
135              
136             If called in scalar context, get_opts will return a hash ref. Otherwise
137             get_opts returns a hash.
138              
139             =cut
140              
141             sub get_opts {
142 10 100   10 1 5540 if (scalar(@_) == 1) {
143             # detected only one argument
144             # is it a scalar, arrayref, or hashref?
145 6         12 my $reftype = ref($_[0]);
146 6 100       22 if (not $reftype) {
    100          
    50          
147             # scalar
148 2         8 my %hash = ($get_opts_scalar_key, $_[0]);
149             # returns either the hash with a default key
150             # or if called in scalar context returns the
151             # opt directly... presumes a single opt was
152             # intentional and should be maintained
153 2 100       14 return wantarray ? %hash : $_[0];
154             } elsif ($reftype eq 'ARRAY') {
155             # array ref
156 2         3 my @arr = @{$_[0]};
  2         7  
157             # returns either array as a list or as the
158             # original arrayref passed in
159 2 100       11 return wantarray ? @arr : $_[0];
160             } elsif ($reftype eq 'HASH') {
161             # hash ref
162 2         4 my %hash = %{$_[0]};
  2         10  
163             # returns either the hash or the original
164             # hash ref depending on context for return
165 2 100       14 return wantarray ? %hash : $_[0];
166             } else {
167             # probably an object
168 0         0 my %hash = ($get_opts_scalar_key, $_[0]);
169             # returns either the hash with a default key
170             # the object itself depending on the context
171 0 0       0 return wantarray ? %hash : $_[0];
172             }
173             } else {
174             # detected more than one argument
175 4 100       17 if (scalar(@_) % 2 == 1) {
176             # odd number of arguments, treat as an array
177 2         29 my @arr = @_;
178             # return either list or array ref based on context
179 2 100       21 return wantarray ? @arr : \@arr;
180             } else {
181             # even number of arguments, treat as a hash
182 2         9 my %hash = @_;
183             # return hash or hash ref based on context
184 2 100       15 return wantarray ? %hash : \%hash;
185             }
186             }
187             # safety, we should never get here but just in case
188 0 0       0 return wantarray ? @_ : [@_];
189             }
190              
191             ##############################################################################
192             # Numeric and Data Type Tests
193             ##############################################################################
194              
195             =head2 _b_cmp_flags
196              
197             Internal procedure, not meant to be used outside this module, not in export_ok
198              
199             =cut
200              
201             sub _b_cmp_flags($$) {
202 82     82   93 my $ref = shift();
203 82         84 my $flags = shift();
204 82 100       479 return $flags & svref_2object($ref)->FLAGS ? TRUE : FALSE;
205             }
206              
207             =head2 is_type_string
208              
209             =cut
210              
211             sub is_type_string($) {
212 6     6 1 1380 return _b_cmp_flags(\$_[0], B::SVf_POK | B::SVp_POK);
213             }
214              
215             =head2 is_type_int
216              
217             =cut
218              
219             sub is_type_int($) {
220 38     38 1 1646 return _b_cmp_flags(\$_[0], B::SVf_IOK | B::SVp_IOK);
221             }
222              
223             =head2 is_type_float
224              
225             =cut
226              
227             sub is_type_float($) {
228 38     38 1 1373 return _b_cmp_flags(\$_[0], B::SVf_NOK | B::SVp_NOK);
229             }
230              
231             =head2 is_string
232              
233             =cut
234              
235             sub is_string($) {
236             # since anything can be a string, we'll fake it say yes
237             # provided of course it's not a ref
238 16     16 1 6071 my $str = FALSE;
239 16 50       35 if (not ref($_[0])) {
240 16         21 $str = TRUE;
241             }
242 16         27 return $str;
243             }
244              
245             =head2 is_int
246              
247             =cut
248              
249             sub is_int($) {
250 32     32 1 6637 my $value = $_[0];
251 32         60 my $response;
252 8     8   45 no warnings 'numeric';
  8         14  
  8         7730  
253 32 100       88 if ($value =~ /^[0-9]+\.$/) {
254             # fix problem where 2. doesn't get recognized as int
255             # by trimming trailing decimal point before testing.
256 4         13 $value =~ s/\.$//;
257             }
258 32         88 $response = is_type_int($value+0);
259 32   100     167 return (($response) and ($value eq ($value+0)));
260             }
261              
262             =head2 is_float
263              
264             =cut
265              
266             sub is_float($) {
267 32     32 1 5728 my $value = $_[0];
268 32         35 my $response;
269 8     8   46 no warnings 'numeric';
  8         14  
  8         1255  
270 32 100       80 if ($value =~ /^[0-9]*\.0+$/) {
271             # fix problem where 2.00 doesn't get recognized as float
272             # by making sure a non-zero decimal exists for numbers that
273             # have a decimal and 1 or more 0s
274 6         14 $value += 0.01;
275 6         11 $response = is_type_float($value);
276 6         10 $value -= 0.01;
277             } else {
278 26         71 $response = is_type_float($value+0.0);
279             }
280 32   100     219 return (($response) and ($value eq ($value+0.0)));
281             }
282              
283             =head2 is_numeric
284              
285             =cut
286              
287             sub is_numeric($) {
288 8     8   44 no warnings 'numeric';
  8         15  
  8         11350  
289 16     16 1 6541 return is_int($_[0]) | is_float($_[0]);
290             }
291              
292             ##############################################################################
293             # File and Path methods
294             ##############################################################################
295              
296             =head2 get_file_details
297              
298             Returns a hashref containing details about the specified file. Returns undef
299             if the file is not defined, does not exist, or is not readable.
300              
301             Example of returned hashref:
302             $VAR1 = {
303             'filetype' => 'file',
304             'blocks' => 8,
305             'blocksize' => 4096,
306             'mode' => '0664',
307             'size' => 387,
308             'hardlinks' => 1,
309             'file_name' => '05-fileinfo',
310             'mode_dec' => 436,
311             'ctime' => 1334455408,
312             'rdev' => 0,
313             'filetype_dec' => 32768,
314             'uid' => 501,
315             'mtime' => 1334455408,
316             'file_extension' => 't',
317             'path' => 't/',
318             'device' => 234881027,
319             'inode' => 6282915,
320             'filename' => '05-fileinfo.t',
321             'fullname' => 't/05-fileinfo.t',
322             'atime' => 1334455410,
323             'gid' => 20
324             };
325              
326             =cut
327              
328             sub get_file_details {
329 1     1 1 18 my $filename = shift();
330 1 50 33     42 if ((defined $filename) and (-e $filename) and (-r $filename)) {
      33        
331 1         2 my $details = {};
332 1 50       14 if (-l $filename) {
333 0         0 @{$details}{
334 0         0 'device','inode','mode','hardlinks','uid','gid','rdev',
335             'size','atime','mtime','ctime','blocksize','blocks'
336             } = lstat($filename);
337 0         0 $details->{'link_target'} = readlink($filename);
338             } else {
339 1         12 @{$details}{
340 1         16 'device','inode','mode','hardlinks','uid','gid','rdev',
341             'size','atime','mtime','ctime','blocksize','blocks'
342             } = stat($filename);
343             }
344 1         70 my ($fname, $fpath, $fext) = fileparse($filename, qw/\.[^.]*/);
345 1         4 $fext =~ s/^\.//;
346 1         2 my $mode = $details->{'mode'};
347 1         5 $details->{'mode_dec'} = S_IMODE($mode);
348 1         16 $details->{'filetype_dec'} = S_IFMT($mode);
349 1         5 $details->{'mode'} = sprintf("%04o", $details->{'mode_dec'});
350 1         29 $details->{'filetype'} = $FILE_TYPES{$details->{'filetype_dec'}};
351 1         3 $details->{'path'} = $fpath;
352             # fix bug where filenames without extensions had a period
353             # added to their filename.
354 1 50 33     9 if ((not defined $fext) or
355             ($fext =~ /^\s*$/)) {
356             # fix edge case where filename ending with period
357             # would have period dropped
358 0 0       0 if ($filename =~ /\.$/) {
359 0         0 $fname .= '.';
360             }
361 0         0 $details->{'filename'} = $fname;
362             } else {
363 1         3 $details->{'filename'} = $fname . '.' . $fext;
364             }
365 1         2 $details->{'file_name'} = $fname;
366 1         2 $details->{'file_extension'} = $fext;
367 1         3 $details->{'fullname'} = $filename;
368 1         3 my ($arc) = ($details->{'filename'} =~ /\.(tar\..{1,3}|tar|cpio|tbz2|tgz|tbz|zip|rar|arc|arj|bzip|tz|zoo|7z)$/i);
369 1 50       3 if (defined $arc) {
370 0         0 $details->{'archive'} = $arc;
371             }
372 1         4 return $details;
373             }
374 0         0 return;
375             }
376              
377             ##############################################################################
378             # Environment Functions
379             ##############################################################################
380              
381             =head2 is_mod_perl
382              
383             Checks to see if mod_perl is detected. This is done by looking for the MOD_PERL
384             environment variable. Returns 1 (TRUE) if found, or 0 (FALSE) if not.
385              
386             =cut
387              
388             sub is_mod_perl {
389 1 50   1 1 18 return exists $ENV{'MOD_PERL'} ? TRUE : FALSE;
390             }
391              
392             ##############################################################################
393             # String Functions
394             ##############################################################################
395              
396             =head2 is_empty
397              
398             Returns true if variable is not defined or equal to ''
399              
400             =cut
401              
402             sub is_empty {
403 12     12 1 3397 my $string = $_[0];
404 12   100     113 return ((not defined $string) or ($string eq ''));
405             }
406              
407             =head2 is_blank
408              
409             Returns true if variable is not defined, equal to '', or contains nothing
410             but whitespace (/^\s*$/).
411              
412             =cut
413              
414             sub is_blank {
415 6     6 1 2973 my $string = $_[0];
416 6   100     17 return ((is_empty($string)) or ($string =~ /^\s*$/));
417             }
418              
419             =head2 no_undef
420              
421             Returns the variable passed to it, unchanged, unless the variable has a value
422             of undef, in which case it returns ''.
423              
424             =cut
425              
426             sub no_undef {
427 6 100   6 1 2808 return (defined $_[0] ? $_[0] : '');
428             }
429              
430             ##############################################################################
431             #
432             # PerlDoc
433             #
434             ##############################################################################
435              
436             =head1 AUTHOR
437              
438             Gregory S. Youngblood, C<< >>
439              
440             =head1 BUGS
441              
442             Please report any bugs or feature requests to C, or through
443             the web interface at L. I will be notified, and then you'll
444             automatically be notified of progress on your bug as I make changes.
445              
446             =head1 SUPPORT
447              
448             You can find documentation for this module with the perldoc command.
449              
450             perldoc Zeta::Util
451              
452              
453             You can also look for information at:
454              
455             =over 4
456              
457             =item * RT: CPAN's request tracker
458              
459             L
460              
461             =item * AnnoCPAN: Annotated CPAN documentation
462              
463             L
464              
465             =item * CPAN Ratings
466              
467             L
468              
469             =item * Search CPAN
470              
471             L
472              
473             =back
474              
475              
476             =head1 ACKNOWLEDGEMENTS
477              
478              
479             =head1 COPYRIGHT & LICENSE
480              
481             Copyright 1995-2012 Gregory S. Youngblood, all rights reserved.
482              
483             This program is free software; you can redistribute it and/or modify it
484             under the same terms as Perl itself.
485              
486              
487             =cut
488              
489             ##############################################################################
490             #
491             # Make perl happy
492             #
493             ##############################################################################
494             1;