Question

I have a string being generated passed to and outputed by template toolkit using:

https://metacpan.org/module/Template::Plugin::Number::Format

Its using format_price I want to drop the cents off the price if they are zero. So 100.00 becomes 100

Can't find any clear solution to this.

Update:

format_price is used in hundreds of places within this project and if possible i'd like to not change that and override the method with this functionality if possible.

Was it helpful?

Solution

You can extend Template::Plugin::Number::Format to create your own plugin like so:

package Template::Plugin::My::Number::Format;
use base qw(Template::Plugin::Number::Format);
use Number::Format;

sub init {
    my ($self, $config) = @_;
    $self->SUPER::init($config);
    my $nfo = Number::Format->new(%$config);
    $self->{ _CONTEXT }->define_filter(format_price => sub {
        my ($context, @args) = @_;
        return sub {
            my $text = shift;
            my $result = $nfo->format_price($text, @args);
            $result =~ s/\.00$//;
            return $result;
        };
    }, 1);
    return $self;
}

Then inside your templates you would use your plugin like so:

[% USE My.Number.Format %]
...
[% some_number | format_price %]

OTHER TIPS

It should be relatively straightforward to implement an override of this function to behave as you require.

The plugin code is almost trivial in what it does. Take a copy of it from wherever you have it installed and make it part of your code-base, so your version is the one that will be found during compilation, i.e.

Myapp/lib/Template/Plugin/Number/Format.pm

edit it thus:

-use Number::Format;
+use Number::Format::NoZeroCents;

Then add a new module to your code:

Myapp/lib/Number/Format/NoZeroCents.pm;

that looks like this:

package Number::Format::NoZeroCents;

use strict;
use warnings;

use base 'Number::Format';

sub format_price {
    my $self = shift;
    my ($number, $precision, $symbol) = @_;
    if(defined $precision){ #default behaviour
        printf STDERR "%s: default behaviour for %s\n", __PACKAGE__, join(';',@_);
        return $self->SUPER::format_price(@_)
    }
    else {
        $precision = 0 if $number == int($number);
        printf STDERR "%s: override behaviour for %s\n", __PACKAGE__, $number;
        return $self->SUPER::format_price($number, $precision, $symbol)
    }
}

1;

And that should mean your NoZeroCents approach is used by default throughout your code, but you can override by calling [% number | format_price(2) %] when you want $100.00 to appear.


UPDATE

Number::Format definitely does the right thing when told to use precision => 0, as this quick test confirms:

#!/usr/bin/env perl

use strict;
use warnings;

use Number::Format qw(format_price);

my $v = 100.00;

printf "Original value as string '%s'; as number '%f'; as fp '%s'; as fp0: '%s'\n",
       $v, $v, format_price($v), format_price($v,0);

which produces:

Original value as string '100'; as number '100.000000'; as fp 'AUD 100.00'; as fp0: 'AUD 100'

It looks like the extra zeros are especially for currency mode.

format_price($precision) Returns a string containing "$number" formatted similarly to "format_number()", except that the decimal portion may have trailing zeroes added to make it be exactly "$precision" characters long, and the currency string will be prefixed.

If you still want to avoid it, I guess just not using this mode will suffice

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top