chiark / gitweb /
TOML::Tiny: Try to be more faithful for small decimals
[nailing-cargo.git] / lib / TOML / Tiny.pm
1 package TOML::Tiny;
2 # ABSTRACT: a minimal, pure perl TOML parser and serializer
3
4 use strict;
5 use warnings;
6 no warnings qw(experimental);
7 use v5.18;
8
9 use TOML::Tiny::Parser;
10 use TOML::Tiny::Writer;
11
12 use parent 'Exporter';
13
14 our @EXPORT = qw(
15   from_toml
16   to_toml
17 );
18
19 #-------------------------------------------------------------------------------
20 # TOML module compatibility
21 #-------------------------------------------------------------------------------
22 sub from_toml {
23   my $source = shift;
24   my $parser = TOML::Tiny::Parser->new(@_);
25   my $toml = eval{ $parser->parse($source) };
26   if (wantarray) {
27     return ($toml, $@);
28   } else {
29     die $@ if $@;
30     return $toml;
31   }
32 }
33
34 sub to_toml {
35   goto \&TOML::Tiny::Writer::to_toml;
36 }
37
38 #-------------------------------------------------------------------------------
39 # Object API
40 #-------------------------------------------------------------------------------
41 sub new {
42   my ($class, %param) = @_;
43   bless{ %param, parser => TOML::Tiny::Parser->new(%param) }, $class;
44 }
45
46 sub decode {
47   my ($self, $source) = @_;
48   $self->{parser}->parse($source);
49 }
50
51 sub encode {
52   my ($self, $data) = @_;
53   TOML::Tiny::Writer::to_toml($data,
54     strict_arrays => $self->{strict_arrays},
55     no_string_guessing => $self->{no_string_guessing},
56   );
57 }
58
59 #-------------------------------------------------------------------------------
60 # For compatibility with TOML::from_toml's use of $TOML::Parser
61 #-------------------------------------------------------------------------------
62 sub parse {
63   goto \&decode;
64 }
65
66 1;
67
68 =head1 SYNOPSIS
69
70   use TOML::Tiny qw(from_toml to_toml);
71
72   binmode STDIN,  ':encoding(UTF-8)';
73   binmode STDOUT, ':encoding(UTF-8)';
74
75   # Decoding TOML
76   my $toml = do{ local $/; <STDIN> };
77   my ($parsed, $error) = from_toml $toml;
78
79   # Encoding TOML
80   say to_toml({
81     stuff => {
82       about => ['other', 'stuff'],
83     },
84   });
85
86   # Object API
87   my $parser = TOML::Tiny->new;
88   my $data = $parser->decode($toml);
89   say $parser->encode($data);
90
91
92 =head1 DESCRIPTION
93
94 C<TOML::Tiny> implements a pure-perl parser and generator for the
95 L<TOML|https://github.com/toml-lang/toml> data format. It conforms to TOML v5
96 (with a few caveats; see L</strict_arrays>) with support for more recent
97 changes in pursuit of v6.
98
99 C<TOML::Tiny> strives to maintain an interface compatible to the L<TOML> and
100 L<TOML::Parser> modules, and could even be used to override C<$TOML::Parser>:
101
102   use TOML;
103   use TOML::Tiny;
104
105   local $TOML::Parser = TOML::Tiny->new(...);
106   say to_toml(...);
107
108
109 =head1 EXPORTS
110
111 C<TOML::Tiny> exports the following to functions for compatibility with the
112 L<TOML> module. See L<TOML/FUNCTIONS>.
113
114 =head2 from_toml
115
116 Parses a string of C<TOML>-formatted source and returns the resulting data
117 structure. Any arguments after the first are passed to L<TOML::Tiny::Parser>'s
118 constructor.
119
120 If there is a syntax error in the C<TOML> source, C<from_toml> will die with
121 an explanation which includes the line number of the error.
122
123   my $result = eval{ from_toml($toml_string) };
124
125 Alternately, this routine may be called in list context, in which case syntax
126 errors will result in returning two values, C<undef> and an error message.
127
128   my ($result, $error) = from_toml($toml_string);
129
130 Homogenous array strictures are enabled by passing C<strict_arrays>:
131
132   # Croaks
133   my $result = from_toml(q{mixed=[1, 2, "three"]})
134
135 Additional arguments may be passed after the toml source string; see L</new>.
136
137 =head2 to_toml
138
139 Encodes a hash ref as a C<TOML>-formatted string.
140
141   my $toml = to_toml({foo => {'bar' => 'bat'}});
142
143   # [foo]
144   # bar="bat"
145
146 Homogenous array strictures are enabled by passing C<strict_arrays>:
147
148   # Croaks
149   my $toml = to_toml({mixed => [1, 2, "three"]}, strict_arrays => 1);
150
151 =head1 OBJECT API
152
153 =head2 new
154
155 =over
156
157 =item inflate_datetime
158
159 By default, C<TOML::Tiny> treats TOML datetimes as strings in the generated
160 data structure. The C<inflate_datetime> parameter allows the caller to provide
161 a routine to intercept those as they are generated:
162
163   use DateTime::Format::RFC3339;
164
165   my $parser = TOML::Tiny->new(
166     inflate_datetime => sub{
167       my $dt_string = shift;
168       return DateTime::Format::RFC3339->parse_datetime($dt_string);
169     },
170   );
171
172 =item inflate_boolean
173
174 By default, boolean values in a C<TOML> document result in a C<1> or C<0>.
175 If L<Types::Serialiser> is installed, they will instead be C<Types::Serialiser::true>
176 or C<Types::Serialiser::false>.
177
178 If you wish to override this, you can provide your own routine to generate values:
179
180   my $parser = TOML::Tiny->new(
181     inflate_boolean => sub{
182       my $bool = shift;
183       if ($bool eq 'true') {
184         return 'The Truth';
185       } else {
186         return 'A Lie';
187       }
188     },
189   );
190
191 =item inflate_integer
192
193 TOML integers are 64 bit and may not match the size of the compiled perl's
194 internal integer type. By default, integers other than smallish
195 decimal integers are left as-is as perl strings which may be upgraded
196 as needed by the caller.
197
198   my $parser = TOML::Tiny->new(
199     inflate_integer => sub{
200       use bignum;
201       return 0 + shift;
202     }
203   );
204
205 =item inflate_float
206
207 TOML floats are 64 bit and may not match the size of the compiled perl's
208 internal float type. By default, integers are left as-is as perl strings which
209 may be upgraded as needed by the caller.
210
211   my $parser = TOML::Tiny->new(
212     inflate_float => sub{
213       use bignum;
214       return 0 + shift;
215     }
216   );
217
218 =item strict_arrays
219
220 C<TOML v5> specified homogenous arrays. This has since been removed and will no
221 longer be part of the standard as of C<v6> (as of the time of writing; the
222 author of C<TOML> has gone back and forth on the issue, so no guarantees).
223
224 By default, C<TOML::Tiny> is flexible and supports heterogenous arrays. If you
225 wish to require strictly typed arrays (for C<TOML>'s definition of "type",
226 anyway), C<strict_arrays> will produce an error when encountering arrays with
227 heterogenous types.
228
229 =item no_string_guessing
230
231 When encoding a Perl scalar it is not always clear what the TOML type
232 of the value is supposed to be.  By default, C<TOML::Tiny> will, for
233 unblessed scalars, guess based on the scalar's appearance.  Strings
234 that look like numbers, or like datetimes, will be encoded as such.
235
236 With no_string_guessing, C<TOML::Tiny> will look at the perl innards
237 to find the currently stored value type.  If it is a number, the
238 scalar will be encoded as a number.  If it's a string, as a string.
239 Dates and times which weren't built with DateTime come out as strings.
240
241 Specifying C<inflate_float>, C<inflate_integer>, and
242 C<inflate_datetime> is likely to be helpful with this option.
243
244 =back
245
246 =head2 decode
247
248 Decodes C<TOML> and returns a hash ref. Dies on parse error.
249
250 =head2 encode
251
252 Encodes a perl hash ref as a C<TOML>-formatted string. Dies when encountering
253 an array of mixed types if C<strict_arrays> was set.
254
255 =head2 parse
256
257 Alias for C<decode> to provide compatibility with C<TOML::Parser> when
258 overriding the parser by setting C<$TOML::Parser>.
259
260
261 =head1 DIFFERENCES FROM L<TOML> AND L<TOML::Parser>
262
263 C<TOML::Tiny> differs in a few significant ways from the L<TOML> module,
264 particularly in adding support for newer C<TOML> features and strictness.
265
266 L<TOML> defaults to lax parsing and provides C<strict_mode> to (slightly)
267 tighten things up. C<TOML::Tiny> defaults to (somehwat) stricter parsing, with
268 the exception of permitting heterogenous arrays (illegal in v4 and v5, but
269 permissible in the upcoming v6); optional enforcement of homogenous arrays is
270 supported with C<strict_arrays>.
271
272 C<TOML::Tiny> supports a number of options which do not exist in L<TOML>:
273 L</inflate_integer>, L</inflate_float>, and L</strict_arrays>.
274
275 C<TOML::Tiny> ignores invalid surrogate pairs within basic and multiline
276 strings (L<TOML> may attempt to decode an invalid pair). Additionally, only
277 those character escapes officially supported by TOML are interpreted as such by
278 C<TOML::Tiny>.
279
280 C<TOML::Tiny> supports stripping initial whitespace and handles lines
281 terminating with a backslash correctly in multilne strings:
282
283   # TOML input
284   x="""
285   foo"""
286
287   y="""\
288      how now \
289        brown \
290   bureaucrat.\
291   """
292
293   # Perl output
294   {x => 'foo', y => 'how now brown bureaucrat.'}
295
296 C<TOML::Tiny> includes support for integers specified in binary, octal or hex
297 as well as the special float values C<inf> and C<nan>.
298
299 =head1 SEE ALSO
300
301 =over
302
303 =item L<TOML::Tiny::Grammar>
304
305 Regexp scraps used by C<TOML::Tiny> to parse TOML source.
306
307 =back
308
309 =head1 ACKNOWLEDGEMENTS
310
311 Thanks to L<ZipRecruiter|https://www.ziprecruiter.com> for encouraging their
312 employees to contribute back to the open source ecosystem. Without their
313 dedication to quality software development this distribution would not exist.