Skip to content

Commit 09a4136

Browse files
authored
Merge pull request #37 from ijackson/no-string-guessing
Avoid looking at string values to try to find the type
2 parents 5c89aa2 + e930584 commit 09a4136

File tree

6 files changed

+94
-12
lines changed

6 files changed

+94
-12
lines changed

README.pod

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,17 @@ routine.
251251
};
252252
);
253253

254+
=item no_string_guessing
255+
256+
When encoding a Perl scalar it is not always clear what the TOML type
257+
of the value is supposed to be. By default, C<TOML::Tiny> will, for
258+
unblessed scalars, guess based on the scalar's appearance. Strings
259+
that look like datetimes, or special floating point values, will be
260+
encoded as such.
261+
262+
With no_string_guessing, C<TOML::Tiny> will never guess a scalar's
263+
TOML type from its string value.
264+
254265
=item strict
255266

256267
C<strict> imposes some miscellaneous strictures on C<TOML> input, such as
@@ -285,7 +296,7 @@ tighten things up. C<TOML::Tiny> defaults to (somewhat) stricter parsing,
285296
enabling some extra strictures with L</strict>.
286297

287298
C<TOML::Tiny> supports a number of options which do not exist in L<TOML>:
288-
L</inflate_integer>, L</inflate_float>, and L</strict>.
299+
L</inflate_integer>, L</inflate_float>, L</no_string_guessing>, and L</strict>.
289300

290301
C<TOML::Tiny> ignores invalid surrogate pairs within basic and multiline
291302
strings (L<TOML> may attempt to decode an invalid pair). Additionally, only

lib/TOML/Tiny.pm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ sub decode {
6868

6969
sub encode {
7070
my ($self, $data) = @_;
71-
TOML::Tiny::Writer::to_toml($data, strict => $self->{strict});
71+
TOML::Tiny::Writer::to_toml(
72+
$data,
73+
strict => $self->{strict},
74+
no_string_guessing => $self->{no_string_guessing},
75+
);
7276
}
7377

7478
#-------------------------------------------------------------------------------

lib/TOML/Tiny/Parser.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ sub parse_datetime {
344344
$value =~ tr/z/Z/;
345345
$value =~ tr/ /T/;
346346
$value =~ s/t/T/;
347-
$value =~ s/(\.\d+)($TimeOffset)$/sprintf(".%06d%s", $1 * 1000000, $2)/e;
347+
$value =~ s/(\.\d+)($TimeOffset)$/sprintf(".%09d%s", $1 * 1000000000, $2)/e;
348348

349349
return $self->{inflate_datetime}->($value);
350350
}

lib/TOML/Tiny/Writer.pm

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ my @KEYS;
1717
sub to_toml {
1818
my $data = shift;
1919
die 'toml: data to encode must be a hashref' if ref $data ne 'HASH';
20-
return _to_toml( $data );
20+
return _to_toml( $data, { @_ } );
2121
}
2222

23-
sub _to_toml {
23+
sub _to_toml ($$);
24+
sub _to_toml ($$) {
2425
my $data = shift;
25-
my $param = ref($_[1]) eq 'HASH' ? $_[1] : undef;
26+
my $param = shift;
2627

2728
die 'toml: found undefined value, which is unsupported by TOML' if ! defined $data;
2829

@@ -82,6 +83,7 @@ sub _to_toml {
8283
return 'nan' if Math::BigFloat->new($data)->is_nan;
8384
return $data;
8485
}
86+
return to_toml_string($data) if $param->{no_string_guessing};
8587
#return $data if svref_2object(\$data)->FLAGS & (SVf_IOK | SVf_NOK);
8688
return $data if $data =~ /^$DateTime$/;
8789
return lc($data) if $data =~ /^$SpecialFloat$/;
@@ -103,7 +105,7 @@ sub to_toml_inline_table {
103105
if (ref $val eq 'HASH') {
104106
push @buff, $key . '=' . to_toml_inline_table($val);
105107
} else {
106-
push @buff, $key . '=' . _to_toml($val);
108+
push @buff, $key . '=' . _to_toml($val, $param);
107109
}
108110
}
109111

@@ -144,7 +146,7 @@ sub to_toml_table {
144146

145147
for (@{ $data->{$k} }) {
146148
push @buff_tables, '', '[[' . join('.', map{ to_toml_key($_) } @KEYS) . ']]';
147-
push @buff_tables, _to_toml($_);
149+
push @buff_tables, _to_toml($_, $param);
148150
}
149151

150152
pop @KEYS;

t/faithful.t

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use utf8;
2+
use Test2::V0;
3+
use Data::Dumper;
4+
use DateTime::Format::ISO8601;
5+
use TOML::Tiny;
6+
7+
binmode STDIN, ':encoding(UTF-8)';
8+
binmode STDOUT, ':encoding(UTF-8)';
9+
10+
my $input = q{
11+
datetime=2020-05-04T16:37:02.905408062+01:00
12+
datetimes="2020-05-04T16:37:02.905408062+01:00"
13+
float=3.14
14+
floats="3.14"
15+
uint=3
16+
uints="3"
17+
nint=-4
18+
nints="-4"
19+
bigint=1852528528562625752750
20+
bigints="1852528528562625752750"
21+
hex=0x12
22+
oct=0o751
23+
bin=0b11010110
24+
boolf=false
25+
boolt=true
26+
boolfs="false"
27+
boolts="true"
28+
dtlocal=1979-05-27T00:32:00.643144312
29+
dtlocals="1979-05-27T00:32:00.643144312"
30+
};
31+
32+
sub norm ($) {
33+
join "\n", (
34+
sort
35+
map {
36+
s{=0o(\d+)$}{ '='.oct($1) }e;
37+
s{=(0[xb]\w+)$}{ '='.eval($1) }e;
38+
$_;
39+
}
40+
grep /./,
41+
split /\n/, $_[0]
42+
), ''
43+
}
44+
45+
my $coder = TOML::Tiny->new(
46+
no_string_guessing => 1,
47+
inflate_datetime => sub {
48+
# RFC3339 bombs out if there is no timezone, so we parse with 8601
49+
DateTime::Format::ISO8601->parse_datetime(shift)
50+
},
51+
);
52+
53+
my $parsed = $coder->decode($input);
54+
my $actual = norm($coder->encode($parsed));
55+
my $expected = norm($input);
56+
57+
is($actual, $expected, 'round trip') or do{
58+
diag 'EXPECTED:';
59+
diag Dumper($expected);
60+
61+
diag 'ACTUAL:';
62+
diag Dumper($actual);
63+
};
64+
65+
done_testing;

t/toml-test/valid/datetime/milliseconds.t

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ my $toml = do{ local $/; <$fh>; };
1818
close $fh;
1919

2020
my $expected1 = {
21-
"utc1" => "1987-07-05T17:45:56.123456Z",
22-
"utc2" => "1987-07-05T17:45:56.600000Z",
23-
"wita1" => "1987-07-05T17:45:56.123456+08:00",
24-
"wita2" => "1987-07-05T17:45:56.600000+08:00"
21+
"utc1" => "1987-07-05T17:45:56.123456000Z",
22+
"utc2" => "1987-07-05T17:45:56.600000000Z",
23+
"wita1" => "1987-07-05T17:45:56.123456000+08:00",
24+
"wita2" => "1987-07-05T17:45:56.600000000+08:00"
2525
};
2626

2727

0 commit comments

Comments
 (0)