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 )