Acme-Numbers

 view release on metacpan or  search on metacpan

lib/Acme/Numbers.pm  view on Meta::CPAN

Inspired by this post

http://beautifulcode.oreillynet.com/2007/12/the_cardinality_of_a_fluent_in.php

and a burning curiosity. At leats, I hope the burning 
was curiosity.

=head1 ONE BIIIIIIIIIIIILLION

By default billion is 10**12 because, dammit, that's right.

If you want it to be an American billion then do

    use Acme::Numbers billion => 10**9;

Setting this automatically changes all the larger numbers 
(trillion, quadrillion, etc) to match.

=head1 METHODS

You should never really use these methods on the class directly.

All numbers handled by C<Lingua::EN::Words2Nums> are handled by this module.

In addition ...

=cut

sub import {
    my $class = shift;
    my %opts  = @_;

    $opts{billion} = 10**12 unless defined $opts{billion};
    no strict 'refs';
    no warnings 'redefine';
    my ($pkg, $file) = caller; 
    $Lingua::EN::Words2Nums::billion = $opts{billion};
    foreach my $num ((keys %Lingua::EN::Words2Nums::nametosub, 
                      'and', 'point', 'zero', 
                      'pound', 'pounds', 'pence', 'p',
                      'dollars', 'cents')) 
    {
        *{"$pkg\::$num"} = sub { $class->$num };
    }
};



=head2 new <value> <operator>

C<operator> can be 'num', 'and' or 'point'

=cut

sub new {
    my $class = shift;
    $class = ref $class if ref $class;
    my $val   = shift;
    my $op    = shift;
    my $name  = shift || $op;
    bless { value => $val, operator => $op, name => $name }, $class;
}

=head2 name 

The name of this object (i.e the method that was originally called).

=cut

sub name {
	return $_[0]->{name};
}

=head2 value

The current numeric value

=cut

sub value { 
    my $self = shift;
    my $val = $self->{value};
    # if we're 'pence' then divide by 100 and then pretend we're pounds
    if ($self->{operator} =~ m!^p(ence)?$!) {
        # this fixes something where there's 0 
        # pounds and a trailing zero like 0.50
        $self->{last_added} = $val; 
        $val = $val/100;
        $self->{operator} = 'pounds';
    }
    if ($self->{operator} =~ m!^pounds?$!) {
        my ($num, $frac) = split /\./, $val;
        $frac ||= 0;
        # this also fixes 0 pounds trailing zero
        $frac = $self->{last_added} if defined $self->{last_added} && $self->{last_added}>$frac;
        # we substr to fix one.pound.fifty.pence which 
        # leaves $frac as '500' 
        $val  = sprintf("%d.%02d",$num,substr($frac,0,2));
    } 

    return $val;
}

sub AUTOLOAD {
    my $self   = shift;
    my $method = $AUTOLOAD;
    $method    =~ s/.*://;   # strip fully-qualified portion
    my $val;
    # nasty override - we should probably have a 
    # generic major or minor currency indicator
    # if we could store and propogate the currency
    # then we could also throw errors at mismatched 
    # units e.g five.pounds.and.fifty.cents
    # but maybe also print out the correct sigil
    # e.g $5.50
    $method = 'pounds' if $method eq 'dollars';
    $method = 'pence'  if $method eq 'cents';

    # dummy methods
    if ($method eq 'and' || $method =~ m!^p!) {
        $val = $self->new(0, $method) 



( run in 0.906 second using v1.01-cache-2.11-cpan-39bf76dae61 )