Perl как отбросить десятичные точки, если 00

У меня есть сгенерированная строка, переданная и выведенная набором инструментов шаблона, используя:

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

Используя format_price, я хочу сбросить центы с цены, если они равны нулю. Таким образом, 100.00 становится 100.

Не могу найти четкого решения для этого.

Обновлять:

format_price используется в сотнях мест в этом проекте, и, если возможно, я хотел бы не менять это и, если возможно, переопределить метод с этой функциональностью.


person kevzettler    schedule 05.02.2013    source источник
comment
Есть ли требование делать это только с помощью модуля? В противном случае используйте sprintf для форматирования, как вы хотите.   -  person chris    schedule 05.02.2013
comment
Никаких требований к модулю, если бы я мог получить что-то, чтобы подключить его к набору инструментов шаблона, который будет работать.   -  person kevzettler    schedule 05.02.2013
comment
format_price($precision) : Returns a string containing "$number" formatted similarly to "format_number()", except that the decimal portion may have trailing zeroes added ... Есть ли какая-то конкретная причина, по которой вы не можете использовать format_number вместо этого?   -  person TLP    schedule 05.02.2013


Ответы (3)


Вы можете расширить Template::Plugin::Number::Format для создания собственного плагина следующим образом:

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;
}

Затем внутри ваших шаблонов вы должны использовать свой плагин следующим образом:

[% USE My.Number.Format %]
...
[% some_number | format_price %]
person Naveed    schedule 06.02.2013
comment
Это, конечно, самый простой способ переопределить поведение по умолчанию (гораздо больше, чем мой ответ), но у меня сложилось четкое впечатление, что ОП хотел избежать изменения существующих шаблонов. - person RET; 07.02.2013

Должно быть относительно просто реализовать переопределение этой функции, чтобы вести себя так, как вам нужно.

Код плагина почти тривиален в том, что он делает. Возьмите его копию из того места, где вы его установили, и сделайте его частью своей кодовой базы, чтобы ваша версия была той, которая будет найдена во время компиляции, т.е.

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

отредактируйте его таким образом:

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

Затем добавьте новый модуль в свой код:

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

это выглядит так:

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;

И это должно означать, что ваш подход NoZeroCents используется по умолчанию во всем вашем коде, но вы можете переопределить его, вызвав [% number | format_price(2) %], когда вы хотите, чтобы отображалось значение $100.00.


ОБНОВЛЕНИЕ

Number::Format определенно поступает правильно, когда ему говорят использовать точность => 0, что подтверждает этот быстрый тест:

#!/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);

который производит:

Original value as string '100'; as number '100.000000'; as fp 'AUD 100.00'; as fp0: 'AUD 100'
person RET    schedule 05.02.2013
comment
Это похоже на лучшее решение, но я получаю сообщение об ошибке с этой реализацией. Я не уверен насчет Warning caught during route execution: Useless use of a variable in void context at /opt/public-site/lib/Number/Format/NoZeroCents.pm line 8. /opt/public-site/lib/Number/Format/NoZeroCents.pm around line 8 5 use base 'Number::Format'; 6 7 sub format_price { 8 my ($self, $number, $precision, $symbol) = shift, @_; 9 if(defined $precision){ #default behaviour 10 $self->SUPER::format_price(@_) 11 } - person kevzettler; 06.02.2013
comment
Я внес небольшие коррективы. Непослушный меня за то, что я оставил строгие/предупреждения в новом модуле, и я заставил родительские вызовы format_price() явно возвращаться, что, как я подозреваю, было причиной предупреждения о «бесполезном использовании». - person RET; 06.02.2013
comment
это работает лучше. Теперь у меня проблема с переопределением существующего модуля. Я использую это в проекте Perl Dancer и скопировал оба этих файла в свой каталог ./lib. Однако, похоже, его не вызывают. Что я должен искать и как я могу убедиться, что он загружен правильно? - person kevzettler; 06.02.2013
comment
Предположительно, вы указали полные пути, как описано, и каталог «lib» — это место, где живет весь ваш код Perl? (Мой опыт работы с фреймворком — Catalyst, но применимы те же общие принципы. То, что мы сделали здесь, — это классические подклассы Perl и методы переопределения, фреймворк на самом деле не имеет значения.) Добавьте строку в каждый из ваших новых модулей непосредственно перед 1; завершите чтение printf "**** %s ****\n", __PACKAGE__ ; и посмотрите, появится ли это в журнале вашего сервера разработки, когда вы его запустите. Если это не так, у вас есть проблемы с вашим путем perl. - person RET; 06.02.2013
comment
Строки выводятся и выглядят правильно. -- /opt/public-site/lib/Template/Plugin/Number/Format.pm updated. Killing the existing server (pid:14257) 2013/02/06-10:11:36 Server closing! **** Number::Format::NoZeroCents **** **** Template::Plugin::Number::Format **** Successfully killed! Restarting the new server process. Setting gid to "33 33 33" Starman: Accepting connections at http://*:5000/ Однако я скептически отношусь к верхней строке, в которой говорится, что Format.pm был обновлен. Я также не вижу поведения в своих представлениях. - person kevzettler; 06.02.2013
comment
Если вы видите эти сообщения, ваши модули загружаются. Я добавил несколько строк отладки в качестве примера того, как вы можете отследить проблему. Я быстро просмотрел исходный код для Number::Format, и похоже, что он должен работать правильно, когда вы хотите, чтобы точность = 0 в вызове format_price(). - person RET; 07.02.2013

Похоже, лишние нули специально для валютного режима.

format_price($precision) Возвращает строку, содержащую «$number», отформатированную аналогично «format_number()», за исключением того, что к десятичной части могут быть добавлены конечные нули, чтобы длина была ровно «$precision», а строка валюты будет префикс.

Если вы все еще хотите избежать этого, думаю, будет достаточно просто не использовать этот режим.

person Karthik T    schedule 05.02.2013