Acme-Numbers

 view release on metacpan or  search on metacpan

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


=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) 
    } else {
        # bit of a hack here
        my $tmp = ($method eq 'zero')? 0 : words2nums($method);
        # maybe this should die 
        return unless defined $tmp;
        $val = $self->new($tmp, 'num', $method);
    }

    # If we're the first number in the chain 
    # then just return ourselves
    if (!ref $self) {
        return $val;
    } else {
        # Otherwise do the magic 
        return $self->handle($val);
    }
}

=head2 handle <Acme::Numbers>

Handle putting these two objects together

=cut

sub handle {
    my ($self, $val) = @_;
    # If we haven't passed a pounds, pence or point marker
    if ($self->{operator} !~ m!^p!) {
        # If the new object is marker ...
        if ($val->{operator} =~ m!^p!) {
            # ... Just propogate along but make a note
            # A pound should not be overidden by a pence
            $self->{operator} = $val->{operator} unless $self->{operator} =~ m!^pounds?$!;
            return $self;

        # Otherwise ...
        } else {
            my $val = $val->{value};
            # If we're not currently adding and the new more than the old
            # e.g two.hundred then multiply
            if ($self->{value} < $val && $self->{operator} ne 'add') {
                $val *= $self->{value};
            # Otherwise add
            } else {
                $val += $self->{value};
            }
            return $self->new($val, 'num', $self->{operator});
        }
    } else { # point, pound, pence
        # first get the fractional part
        my ($num, $frac) = split /\./, $self->{value};



( run in 0.457 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )