From: Ian Jackson Date: Mon, 4 May 2020 00:13:41 +0000 (+0100) Subject: TOML::Tiny: Provide no_string_guessing X-Git-Tag: nailing-cargo/1.0.0~233^2~7 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=dbb0699fd1e23c2eb747935973f278b83229959d;p=nailing-cargo.git TOML::Tiny: Provide no_string_guessing Ideally, if we read a TOML file and write it back out again, we get a semantically equivalent TOML file. A necessary part of this is to avoid the string-contents-based type-guessing. Here, we provide a new `no_string_guessing` parameter which disables this format-guessing. Instead, it uses internal Perl flags to distinguish integers from strings. Right now this new feature is not likely to work for things that came from TOML::Tiny::Parser without inflate_* parameters, since those are all strings. But it now allows Perl code to generate the TOML it wants. --- diff --git a/README.pod b/README.pod index 911f6db..4b0d40c 100644 --- a/README.pod +++ b/README.pod @@ -168,6 +168,21 @@ wish to require strictly typed arrays (for C's definition of "type", anyway), C will produce an error when encountering arrays with heterogenous types. +=item no_string_guessing + +When encoding a Perl scalar it is not always clear what the TOML type +of the value is supposed to be. By default, C will, for +unblessed scalars, guess based on the scalar's appearance. Strings +that look like numbers, or like datetimes, will be encoded as such. + +With no_string_guessing, C will look at the perl innards +to find the currently stored value type. If it is a number, the +scalar will be encoded as a number. If it's a string, as a string. +Dates and times which weren't built with DateTime come out as strings. + +Specifying C, C, and +C is likely to be helpful with this option. + =back =head2 decode diff --git a/lib/TOML/Tiny.pm b/lib/TOML/Tiny.pm index 6cd88be..4597fe8 100644 --- a/lib/TOML/Tiny.pm +++ b/lib/TOML/Tiny.pm @@ -52,6 +52,7 @@ sub encode { my ($self, $data) = @_; TOML::Tiny::Writer::to_toml($data, strict_arrays => $self->{strict_arrays}, + no_string_guessing => $self->{no_string_guessing}, ); } @@ -224,6 +225,21 @@ wish to require strictly typed arrays (for C's definition of "type", anyway), C will produce an error when encountering arrays with heterogenous types. +=item no_string_guessing + +When encoding a Perl scalar it is not always clear what the TOML type +of the value is supposed to be. By default, C will, for +unblessed scalars, guess based on the scalar's appearance. Strings +that look like numbers, or like datetimes, will be encoded as such. + +With no_string_guessing, C will look at the perl innards +to find the currently stored value type. If it is a number, the +scalar will be encoded as a number. If it's a string, as a string. +Dates and times which weren't built with DateTime come out as strings. + +Specifying C, C, and +C is likely to be helpful with this option. + =back =head2 decode diff --git a/lib/TOML/Tiny/Writer.pm b/lib/TOML/Tiny/Writer.pm index 66249a8..831d2e5 100644 --- a/lib/TOML/Tiny/Writer.pm +++ b/lib/TOML/Tiny/Writer.pm @@ -12,6 +12,8 @@ use TOML::Tiny::Util qw(is_strict_array); my @KEYS; +use B qw( svref_2object SVf_IOK SVf_NOK ); + sub to_toml { my $data = shift; my %param = @_; @@ -119,6 +121,20 @@ sub to_toml { return $data->bnstr; } + when (!! $param{no_string_guessing}) { + # Thanks to ikegami on Stack Overflow for the trick! + # https://stackoverflow.com/questions/12686335/how-to-tell-apart-numeric-scalars-and-string-scalars-in-perl/12693984#12693984 + + my $sv = svref_2object(\$data); + my $svflags = $sv->FLAGS; + + if ($svflags & (SVf_IOK | SVf_NOK)) { + return $data; + } else { + return to_toml_string($data); + } + } + when ('') { for ($data) { when (looks_like_number($_)) {