Skip to content

Commit

Permalink
Merge pull request #620 from kraih/better_json
Browse files Browse the repository at this point in the history
smarter number and string detection for Mojo::JSON
  • Loading branch information
kraih committed May 12, 2014
2 parents 6517670 + 9934604 commit fc1819b
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 6 deletions.
13 changes: 8 additions & 5 deletions lib/Mojo/JSON.pm
Expand Up @@ -263,8 +263,12 @@ sub _encode_value {
return 'null' unless defined $value;

# Number
my $flags = B::svref_2object(\$value)->FLAGS;
return 0 + $value if $flags & (B::SVp_IOK | B::SVp_NOK) && $value * 0 == 0;
if (B::svref_2object(\$value)->FLAGS & (B::SVp_IOK | B::SVp_NOK)) {
no warnings 'numeric';
my $num = $value;
$num += 0;
return $num if $num eq $value && $num * 0 == 0;
}

# String
return _encode_string($value);
Expand Down Expand Up @@ -321,9 +325,8 @@ It supports normal Perl data types like scalar, array reference, hash
reference and will try to call the C<TO_JSON> method on blessed references, or
stringify them if it doesn't exist. Differentiating between strings and
numbers in Perl is hard, depending on how it has been used, a scalar can be
both at the same time. Since numeric comparisons on strings are very unlikely
to happen intentionally, the numeric value always gets priority, so any
scalar that has been used in numeric context is considered a number.
both at the same time. The string value always gets precedence unless both
representations are equivalent.
[1, -2, 3] -> [1, -2, 3]
{"foo": "bar"} -> {foo => 'bar'}
Expand Down
13 changes: 12 additions & 1 deletion t/mojo/json.t
Expand Up @@ -12,6 +12,7 @@ use Test::More;
use Mojo::ByteStream 'b';
use Mojo::JSON qw(decode_json encode_json j);
use Mojo::Util 'encode';
use Scalar::Util 'dualvar';

# Decode array
my $array = decode_json '[]';
Expand Down Expand Up @@ -289,9 +290,19 @@ is encode_json({test => [$num, $str]}), '{"test":[3.21,"3.21"]}',
'upgraded number detected';
$str = '0 but true';
$num = 1 + $str;
is encode_json({test => [$num, $str]}), '{"test":[1,0]}',
is encode_json({test => [$num, $str]}), '{"test":[1,"0 but true"]}',
'upgraded number detected';

# Upgraded string
$str = "bar";
{ no warnings 'numeric'; $num = 23 + $str }
is encode_json({test => [$num, $str]}), '{"test":[23,"bar"]}',
'upgraded string detected';

# dualvar
my $dual = dualvar 23, 'twenty three';
is encode_json([$dual]), '["twenty three"]', 'dualvar stringified';

# Ensure numbers and strings are not upgraded
my $mixed = [3, 'three', '3', 0, "0"];
is encode_json($mixed), '[3,"three","3",0,"0"]',
Expand Down

0 comments on commit fc1819b

Please sign in to comment.