Skip Menu |

This queue is for tickets about the Math-Currency CPAN distribution.

Report information
The Basics
Id: 115247
Status: resolved
Priority: 0/
Queue: Math-Currency

People
Owner: Nobody in particular
Requestors: DRZIGMAN [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: (no value)
Fixed in: 0.48



Subject: Math::Currency Operator Comparisons Failing since Math-BigInt-1.999718
Greetings, Since Math::BigInt v1.999718 all operator comparisons using Math::Currency objects are now failing: cmp_ok( Math::Currency->new('19.95'), '==', Math::Currency->new('19.95'), 'Object == Object' ); not ok 1 - Object == Object # Failed test 'Object == Object' # at t/007_comparision.t line 12. # got: 19.95 # expected: 19.95 This was caused by the following noted change in Math::BigInt: 2016-04-22 v1.999718 pjacklam * Add overloading of '==', '!=', '<', '<=', '>', to to Math::BigInt and Math::BigFloat and fix the broken overloading of '>='. These overloaded operators now behave like the equivalent core Perl operators. (via Bisection I am able to confirm that v1.999717 works with Math::Currency while v1.999718 does not). I've gone ahead and created a failing test (attached as t/007_comparision.t) and a patch to Math::Currency that resolves the issue (attached as bcmp.patch). Hopefully this patch can be applied and the test added so that we have a nice regression test. I've tried to write the test in your style to minimize the amount of work needed on your side. Please feel free to reach out to me if you need more information, wish to discuss, or if I can be of any assistance. Thank you!
Subject: 007_comparision.t
use Test::More qw(no_plan); BEGIN { use_ok('Math::Currency') }; # For subsequent testing, we need to make sure that format is default US Math::Currency->format('USD'); subtest '==' => sub { my $object = Math::Currency->new('19.95'); my $scalar = 19.95; cmp_ok( $object, '==', $object, 'Object == Object' ); cmp_ok( $scalar, '==', $object, 'Scalar == Object' ); cmp_ok( $object, '==', $scalar, 'Object == Scalar' ); ok( !( Math::Currency->new('19.95') == Math::Currency->new('15.00') ), 'Object != Object' ); }; subtest '<=' => sub { subtest '==' => sub { my $object = Math::Currency->new('19.95'); my $scalar = 19.95; cmp_ok( $object, '<=', $object, 'Object == Object' ); cmp_ok( $scalar, '<=', $object, 'Scalar == Object' ); cmp_ok( $object, '<=', $scalar, 'Object == Scalar' ); ok( !( Math::Currency->new('19.95') <= Math::Currency->new('15.00') ), 'Object (!)<= Object' ); }; subtest '<=' => sub { my $lesser_object = Math::Currency->new('15.00'); my $lesser_scalar = 15.00; my $greater_object = Math::Currency->new('19.95'); my $greater_scalar = 19.95; cmp_ok( $lesser_object, '<=', $greater_object, 'Object <= Object' ); cmp_ok( $lesser_scalar, '<=', $greater_object, 'Scalar <= Object' ); cmp_ok( $lesser_object, '<=', $greater_scalar, 'Object <= Scalar' ); ok( !( $greater_object <= $lesser_object ), 'Object (!)<= Object' ); }; }; subtest '>=' => sub { subtest '==' => sub { my $object = Math::Currency->new('19.95'); my $scalar = 19.95; cmp_ok( $object, '>=', $object, 'Object == Object' ); cmp_ok( $scalar, '>=', $object, 'Scalar == Object' ); cmp_ok( $object, '>=', $scalar, 'Object == Scalar' ); ok( !( Math::Currency->new('15.00') >= Math::Currency->new('19.95') ), 'Object (!)>= Object' ); }; subtest '>=' => sub { my $lesser_object = Math::Currency->new('15.00'); my $lesser_scalar = 15.00; my $greater_object = Math::Currency->new('19.95'); my $greater_scalar = 19.95; cmp_ok( $lesser_object, '>=', $lesser_object, 'Object >= Object' ); cmp_ok( $lesser_scalar, '>=', $lesser_object, 'Scalar >= Object' ); cmp_ok( $lesser_object, '>=', $lesser_scalar, 'Object >= Scalar' ); ok( !( $lesser_object >= $greater_object ), 'Object (!)>= Object' ); }; };
Subject: bcmp.patch
--- lib/Math/Currency.org.pm 2016-06-10 13:41:55.370303622 -0500 +++ lib/Math/Currency.pm 2016-06-10 13:42:02.464231293 -0500 @@ -314,7 +314,7 @@ # we override the default here because we only want to compare the precision of # the currency we're dealing with, not the precision of the underlying object sub bcmp { - my $class = shift; + my $class = __PACKAGE__; # make sure we're dealing with two Math::Currency objects my ( $x, $y ) = map { ref $_ ne $class ? $class->new($_) : $_ } @_[ 0, 1 ];
From: dmaestro12
Thanks DRZIGMAN for the patch. I was also working on fixing this, and want to contribute a substitute patch which is backward-compatible with older versions of Math::BigInt as well, and also provides successful testing with perl 5.18. Your insight provided a simpler and better approach than what I was already working on, as revealed by your test. This version has been tested successfully against Math::BigInt versions 1.89, 1.999717, 1.999718, and 1.999723, using perl 5.18.
Subject: Math-Currency.patch
diff -ru sources/Math-Currency-0.47/lib/Math/Currency.pm sources/Math-Currency/lib/Math/Currency.pm --- sources/Math-Currency-0.47/lib/Math/Currency.pm 2010-08-10 14:33:55.000000000 -0500 +++ sources/Math-Currency/lib/Math/Currency.pm 2016-06-16 09:13:05.329390701 -0500 @@ -22,6 +22,11 @@ $accuracy $precision $div_scale $round_mode $use_int $always_init); use Exporter; use Math::BigFloat 1.60; +use vars qw($_legacy_bigint); +BEGIN { + $_legacy_bigint = Math::BigInt->VERSION <= '1.999717'; +} + use overload '""' => \&bstr; use POSIX qw(locale_h); @@ -314,7 +319,8 @@ # we override the default here because we only want to compare the precision of # the currency we're dealing with, not the precision of the underlying object sub bcmp { - my $class = shift; + my $class = __PACKAGE__; + $class = shift if $_legacy_bigint; # make sure we're dealing with two Math::Currency objects my ( $x, $y ) = diff -ru sources/Math-Currency-0.47/t/002_basic.t sources/Math-Currency/t/002_basic.t --- sources/Math-Currency-0.47/t/002_basic.t 2010-08-10 14:33:55.000000000 -0500 +++ sources/Math-Currency/t/002_basic.t 2016-06-16 08:23:30.276217829 -0500 @@ -41,12 +41,12 @@ ok ( defined $FORMAT, "format defaults configured" ); - foreach $param qw( INT_CURR_SYMBOL CURRENCY_SYMBOL MON_DECIMAL_POINT + foreach $param ( qw( INT_CURR_SYMBOL CURRENCY_SYMBOL MON_DECIMAL_POINT MON_THOUSANDS_SEP MON_GROUPING POSITIVE_SIGN NEGATIVE_SIGN INT_FRAC_DIGITS FRAC_DIGITS P_CS_PRECEDES P_SEP_BY_SPACE N_CS_PRECEDES N_SEP_BY_SPACE P_SIGN_POSN N_SIGN_POSN - ) # hardcoded keys to be sure they are all there + ) ) # hardcoded keys to be sure they are all there { ok ( defined $CLASS->format($param), sprintf(" \t%-20s = '%s'",$param,$CLASS->format($param)) ); } diff -ru sources/Math-Currency-0.47/t/004_localize.t sources/Math-Currency/t/004_localize.t --- sources/Math-Currency-0.47/t/004_localize.t 2010-08-10 14:33:55.000000000 -0500 +++ sources/Math-Currency/t/004_localize.t 2016-06-16 08:23:32.636279126 -0500 @@ -12,13 +12,13 @@ skip ("No locale support", 16) unless Math::Currency->localize(); pass("Re-initialized locale with en_GB"); - foreach my $param qw( + foreach my $param ( qw( INT_CURR_SYMBOL CURRENCY_SYMBOL MON_DECIMAL_POINT MON_THOUSANDS_SEP MON_GROUPING POSITIVE_SIGN NEGATIVE_SIGN INT_FRAC_DIGITS FRAC_DIGITS P_CS_PRECEDES P_SEP_BY_SPACE N_CS_PRECEDES N_SEP_BY_SPACE P_SIGN_POSN N_SIGN_POSN - ) # hardcoded keys to be sure they are all there + ) ) # hardcoded keys to be sure they are all there { ok( defined $format->{$param}, sprintf( " \t%-20s = '%s'", $param, $format->{$param} ) ); @@ -33,13 +33,13 @@ unless $format->{INT_CURR_SYMBOL} =~ /GBP/; use_ok("Math::Currency::en_GB"); - foreach my $param qw( + foreach my $param ( qw( INT_CURR_SYMBOL CURRENCY_SYMBOL MON_DECIMAL_POINT MON_THOUSANDS_SEP MON_GROUPING POSITIVE_SIGN NEGATIVE_SIGN INT_FRAC_DIGITS FRAC_DIGITS P_CS_PRECEDES P_SEP_BY_SPACE N_CS_PRECEDES N_SEP_BY_SPACE P_SIGN_POSN N_SIGN_POSN - ) # hardcoded keys to be sure they are all there + ) ) # hardcoded keys to be sure they are all there { my $global_param = $LC_MONETARY->{'en_GB'}->{$param}; ok( $format->{$param} eq $global_param,
I have just uploaded v0.48 to CPAN which fixes this issue. Thanks!
Greetings, Excellent thinking ensuring you have backwards compatibility. I'm glad I was able to provide some assistance and thanks everyone for taking care of this so quickly! I've tested the 0.48 version and can confirm that it works as expected with Math::BigInt 1.999723 on perl 5.16.3. Great work and thanks again! Best Regards, Robert Stone
This fix is reportedly broke things on Debian 8.4 Possibly Debian patched an earlier version of Math::BigInt so _LEGACY_MATH_BIGINT is set to 1 when it shoudld be set to 0 there. Haven't confirmed why its broken there yet. Just noting here for investigation. -- Regards, Michael Schout
On Thu Jun 30 12:05:11 2016, MSCHOUT wrote: Show quoted text
> This fix is reportedly broke things on Debian 8.4
In 1.99, the overloading of <=> was ref($_[0])->bcmp($_[0],$_[1]) which in 1.999719 changed to my $cmp = $_[0] -> bcmp($_[1]); which changes the signature of the bcmp() sub in an incompatible way. The former is a class method (which matches what M::C has done all along) and the latter is an object method. I think the proposed change from Daniel to check the number of parameters is probably the best bet at this point. John
On Thu Jun 30 22:02:34 2016, JPEACOCK wrote: Show quoted text
> In 1.99, the overloading of <=> was > > ref($_[0])->bcmp($_[0],$_[1]) > > which in 1.999719 changed to > > my $cmp = $_[0] -> bcmp($_[1]);
Thanks John. I understand whats going on here now. I'm going to mark this ticket resolved and work the proposed solution (which solves both <=> overload and also bcmp() usage) in the other ticket. -- Regards, Michael Schout