File Coverage

blib/lib/Tie/Comma.pm
Criterion Covered Total %
statement 38 41 92.6
branch 16 20 80.0
condition 5 6 83.3
subroutine 7 9 77.7
pod 0 2 0.0
total 66 78 84.6


line stmt bran cond sub pod time code
1             =for gpg
2             -----BEGIN PGP SIGNED MESSAGE-----
3             Hash: SHA1
4              
5             =head1 NAME
6              
7             Tie::Comma - A simple and easy way to format numbers with commas,
8             using a tied hash.
9              
10             =head1 VERSION
11              
12             This documentation describes version 0.04 of Tie::Comma, January 07, 2005
13              
14             =cut
15              
16 2     2   11068 use strict;
  2         4  
  2         102  
17             package Tie::Comma;
18             $Tie::Comma::VERSION = 0.04;
19              
20 2     2   9 use Exporter;
  2         3  
  2         81  
21 2     2   9 use vars qw/@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS %comma/;
  2         20  
  2         1725  
22             @ISA = qw/Exporter/;
23             @EXPORT = qw/%comma/;
24             @EXPORT_OK = qw/commify/;
25             %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]);
26              
27             # Defaults
28             our $thou_sep = ',';
29             our $deci_sep = '.';
30             our $grouping = 3;
31              
32             # Configure for locale, if possible.
33             eval
34             {
35             require POSIX;
36             my $loc = POSIX::setlocale(POSIX::LC_NUMERIC());
37             my $lc = POSIX::localeconv();
38             $thou_sep = $lc->{thousands_sep} || $thou_sep;
39             $deci_sep = $lc->{decimal_point} || $deci_sep;
40             $grouping = $lc->{grouping}? unpack('c', $lc->{grouping}) : $grouping;
41             }; # Ignore any errors in this block -- just fall back to the defaults.
42              
43             # Substitution pattern
44             my $num_pat = "(" . ("\\d" x $grouping) . ")(?=\\d)(?!\\d*\\$deci_sep)";
45             my $num_re = qr/$num_pat/;
46              
47             # Here's the statement that makes it all happen.
48             tie our %comma, 'Tie::Comma';
49              
50             # Delay loading Carp.pm until needed.
51             sub Tie::Comma::croak
52             {
53 0     0 0 0 require Carp;
54 0         0 goto &Carp::croak;
55             }
56              
57             #---> $string = commify $number;
58             # commify : Formats a number with commas.
59             # This version is taken from the Perl Cookbook.
60             sub commify ($)
61             {
62 24     24 0 40 my $rev_num = reverse shift; # The number to be formatted, reversed.
63 24         198 $rev_num =~ s/$num_re/$1$thou_sep/g;
64 24         68 return scalar reverse $rev_num;
65             }
66              
67             sub TIEHASH
68             {
69 2     2   4 my $class = shift;
70 2         4 my $dummy; # not used, but we need a reference.
71 2         8 bless \$dummy, $class;
72             }
73              
74             sub FETCH
75             {
76 26     26   411 my $self = shift;
77 26         31 my $key = shift;
78 26 100       67 return '' if !defined $key; # No args? or undef? return empty string.
79              
80 24         105 my @args = split $;, $key, -1;
81 24 50       58 @args > 3 and Tie::Comma::croak "Too many arguments to %comma";
82 24         39 my ($num, $dp, $min_fw) = @args;
83              
84 24         39 for ($dp, $min_fw)
85             {
86 48 100       103 next unless defined;
87 24 100       43 next unless length;
88 22         47 s/\Q$deci_sep\E.*//o; # remove any fractional part
89 22 50       94 $_ = 0 unless /^-?\d+$/;
90             }
91 24 100 66     104 $min_fw = 0 if (!defined $min_fw or length $min_fw == 0);
92              
93             # Caller specified number of decimal places?
94 24 100 100     88 if (defined $dp && length $dp)
95             {
96 14 50       32 Tie::Comma::croak "Negative decimal places in %comma" if $dp < 0;
97 14         16 $dp = abs($dp);
98 14         105 $num = sprintf "%.${dp}f", $num;
99             }
100              
101 24         44 my $cnum = commify $num;
102              
103             # Pad, if necessary.
104 24 100       122 return $cnum if length $cnum >= abs($min_fw);
105 6         15 my $spaces = ' ' x (abs($min_fw) - length $cnum);
106 6 50       39 return $min_fw < 0? "$cnum$spaces" : "$spaces$cnum";
107             }
108              
109 2         11 use subs qw(
110 2     2   1922 STORE EXISTS CLEAR FIRSTKEY NEXTKEY );
  2         57  
111             *STORE = *EXISTS = *CLEAR = *FIRSTKEY = *NEXTKEY = sub
112             {
113 0     0     Tie::Comma::croak "Invalid call to Tie::Comma internal function";
114             };
115              
116              
117             1;
118             __END__