diff options
author | Father Chrysostomos <sprout@cpan.org> | 2012-10-04 00:35:05 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2012-10-04 09:37:58 -0700 |
commit | 9663a7f582d8b5a489da7d8d8800291ca31c05a1 (patch) | |
tree | 07eaba3c2416a2c2a6e46b05825c1e089b3b3cb8 /dist/bignum/t | |
parent | 40f316a72b14619d13e83acddaab24c95cb0c03c (diff) | |
download | perl-9663a7f582d8b5a489da7d8d8800291ca31c05a1.tar.gz |
Rewrite bignum’s hex and oct overrides
As mentioned in <https://rt.cpan.org/Ticket/Display.html?id=79915>,
bigint.pm does not use any prototype when globally overriding hex.
This means that map { hex } ... will stop working in completely unre-
lated code if bigint happens to be loaded. (Explicit $_ will con-
tinue to work.)
I thought it would be a simple matter of adding the right prototype
depending on perl version (and inferring $_), but the basic tests
I added failed for other reasons after I fixed the prototype and
$_ handling.
It turns out this whole thing is a mess, so I have basically reimple-
mented these two overrides.
What bigint, bignum and bigrat were doing was this: In import,
*CORE::GLOBAL::hex and ::oct are assigned functions that create
Math::BigInt objects if the pragma is in effect. If import is passed
'hex' or 'oct', then the function assigned does not check the pragma
hints, but simply creates Math::BigInt objects regardless.
This means that ‘use bigrat’ stops hex() and oct() from creating
objects in ‘use bigint’ scopes, and vice versa. In fact, whichever
pragma is loaded last wins. Any scopes elsewhere in the program that
use the same pragma will have special hex() and oct() behaviour. But
the other two lowercase big* pragmata will be disabled with regard to
hex and oct.
Having ‘use bigint 'hex'’ override hex globally makes no sense to me.
I have no qualms about changing it, as it was already broken. Any
subsequent ‘use bigint;’ would turn off the global override. So now
it exports hex or oct to the calling package, just like a normal mod-
ule. You can now also call bigint::hex.
Also, in writing tests I found that oct("20") gives me 20. Apparently
this was never tested properly.
I also found notes about ‘5.9.4 or later’ when the code checked
$] > 5.009004. (Actually, in one place the code checked > 5.009003,
so I made it match, as we use the _ prototype now, which was intro-
duced in 5.9.5.) One was in the docs, so I changed it to 5.10.0,
since it is not helpful to mention dev versions. The docs were also
wrong to imply that ‘no bigint’ would countermand ‘use bigint 'hex'’.
Diffstat (limited to 'dist/bignum/t')
-rw-r--r-- | dist/bignum/t/overrides.t | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/dist/bignum/t/overrides.t b/dist/bignum/t/overrides.t new file mode 100644 index 0000000000..d807228887 --- /dev/null +++ b/dist/bignum/t/overrides.t @@ -0,0 +1,100 @@ +#!perl -w + +# Test behaviour of hex and oct overrides in detail, and also how the three +# modules interact. + +use Test::More tests => 35; + +# For testing that existing CORE::GLOBAL overrides are not clobbered +BEGIN + { + if ($] > 5.009004) + { + no warnings 'syntax'; + *CORE::GLOBAL::hex = sub(_) { ++$hex_called; CORE::hex(@_?$_[0]:$_) }; + *CORE::GLOBAL::oct = sub(_) { ++$oct_called; CORE::oct(@_?$_[0]:$_) }; + } + else + { + *CORE::GLOBAL::hex = sub(;$) { ++$hex_called; CORE::hex(@_?$_[0]:$_) }; + *CORE::GLOBAL::oct = sub(;$) { ++$oct_called; CORE::oct(@_?$_[0]:$_) }; + } + } + +{ + use bigint; + $_ = "20"; + is hex, "32", 'bigint hex override without arguments infers $_'; + is oct, "16", 'bigint oct override without arguments infers $_'; + @_ = 1..20; + is hex(@_), "32", 'bigint hex override provides scalar context'; + is oct(@_), "16", 'bigint oct override provides scalar context'; + is ref hex(1), 'Math::BigInt', + 'bigint hex() works when bignum and bigrat are loaded'; + is ref oct(1), 'Math::BigInt', + 'bigint oct() works when bignum and bigrat are loaded'; +} +{ + use bignum; + $_ = "20"; + is hex, "32", 'bignum hex override without arguments infers $_'; + is oct, "16", 'bignum oct override without arguments infers $_'; + @_ = 1..20; + is hex(@_), "32", 'bignum hex override provides scalar context'; + is oct(@_), "16", 'bignum oct override provides scalar context'; + is ref hex(1), 'Math::BigInt', + 'bignum hex() works when bigint and bigrat are loaded'; + is ref oct(1), 'Math::BigInt', + 'bignum oct() works when bigint and bigrat are loaded'; +} +{ + use bigrat; + $_ = "20"; + is hex, "32", 'bigrat hex override without arguments infers $_'; + is oct, "16", 'bigrat oct override without arguments infers $_'; + @_ = 1..20; + is hex(@_), "32", 'bigrat hex override provides scalar context'; + is oct(@_), "16", 'bigrat oct override provides scalar context'; + is ref hex(1), 'Math::BigInt', + 'bigrat hex() works when bignum and bigint are loaded'; + is ref oct(1), 'Math::BigInt', + 'bigrat oct() works when bignum and bigint are loaded'; +} + +$hex_called = 0; +() = hex 0; +is $hex_called, 1, 'existing hex overrides are called'; +$oct_called = 0; +() = oct 0; +is $oct_called, 1, 'existing oct overrides are called'; + +{ + package _importer; + { + use bigint 'hex', 'oct'; + ::is \&hex, \&bigint::hex, 'exported hex function'; + ::is \&oct, \&bigint::oct, 'exported oct function'; + } + ::ok ref hex(), 'exported hex function returns ref outside pragma scope'; + ::ok ref oct(), 'exported oct function returns ref outside pragma scope'; + ::is oct("20"), "16", 'exported oct function works with "decimal"'; + # (used to return 20 because it thought it was decimal) +} +{ + package _importer2; + use bignum 'hex', 'oct'; + ::is \&hex, \&bignum::hex, 'bignum exports hex'; + ::is \&oct, \&bignum::oct, 'bignum exports oct'; + ::is \&hex, \&bigint::hex, 'bignum exports same hex as bigint'; + ::is \&oct, \&bigint::oct, 'bignum exports same oct as bigint'; +} +{ + package _importer3; + use bigrat 'hex', 'oct'; + ::is \&hex, \&bigrat::hex, 'bigrat exports hex'; + ::is \&oct, \&bigrat::oct, 'bigrat exports oct'; + ::is \&hex, \&bigint::hex, 'bigrat exports same hex as bigint'; + ::is \&oct, \&bigint::oct, 'bigrat exports same oct as bigint'; +} +is ref hex 0, "", 'hex export is not global'; +is ref oct 0, "", 'oct export is not global'; |