File Coverage

blib/lib/TOML/Tiny.pm
Criterion Covered Total %
statement 35 43 81.4
branch 5 8 62.5
condition n/a
subroutine 11 13 84.6
pod 6 6 100.0
total 57 70 81.4


line stmt bran cond sub pod time code
1             package TOML::Tiny;
2             # ABSTRACT: a minimal, pure perl TOML parser and serializer
3             $TOML::Tiny::VERSION = '0.16';
4 285     285   74834547 use strict;
  285         2939  
  285         8705  
5 285     285   1682 use warnings;
  285         660  
  285         8020  
6 285     285   1416 no warnings qw(experimental);
  285         688  
  285         9630  
7 285     285   4363 use v5.18;
  285         970  
8              
9 285     285   136832 use TOML::Tiny::Parser ();
  285         909  
  285         8348  
10 285     285   124446 use TOML::Tiny::Writer ();
  285         858  
  285         7483  
11              
12 285     285   2053 use parent 'Exporter';
  285         645  
  285         1481  
13              
14             our @EXPORT = qw(
15             from_toml
16             to_toml
17             );
18              
19             #-------------------------------------------------------------------------------
20             # TOML module compatibility
21             #-------------------------------------------------------------------------------
22             sub from_toml {
23 425     425 1 482842 my ($source, %param) = @_;
24              
25             # strict was previously strict_arrays; accept both for backward
26             # compatibility.
27 425 50       2045 if (exists $param{strict_arrays}) {
28 0         0 $param{strict} = $param{strict_arrays};
29 0         0 delete $param{strict_arrays};
30             }
31              
32 425         4423 my $parser = TOML::Tiny::Parser->new(%param);
33 425         1229 my $toml = eval{ $parser->parse($source) };
  425         2051  
34              
35 425 50       2311 if (wantarray) {
36 0         0 return ($toml, $@);
37             } else {
38 425 100       5614 die $@ if $@;
39 240         2923 return $toml;
40             }
41             }
42              
43             sub to_toml {
44 104     104 1 798659 my ($data, %param) = @_;
45              
46             # strict was previously strict_arrays; accept both for backward
47             # compatibility.
48 104 50       625 if (exists $param{strict_arrays}) {
49 0         0 $param{strict} = $param{strict_arrays};
50 0         0 delete $param{strict_arrays};
51             }
52              
53 104         716 TOML::Tiny::Writer::to_toml($data, %param);
54             }
55              
56             #-------------------------------------------------------------------------------
57             # Object API
58             #-------------------------------------------------------------------------------
59             sub new {
60 2     2 1 7377 my ($class, %param) = @_;
61 2         21 bless{ %param, parser => TOML::Tiny::Parser->new(%param) }, $class;
62             }
63              
64             sub decode {
65 2     2 1 6405 my ($self, $source) = @_;
66 2         21 $self->{parser}->parse($source);
67             }
68              
69             sub encode {
70 0     0 1   my ($self, $data) = @_;
71 0           TOML::Tiny::Writer::to_toml($data, strict => $self->{strict});
72             }
73              
74             #-------------------------------------------------------------------------------
75             # For compatibility with TOML::from_toml's use of $TOML::Parser
76             #-------------------------------------------------------------------------------
77             sub parse {
78 0     0 1   goto \&decode;
79             }
80              
81             1;
82              
83             __END__
84              
85             =pod
86              
87             =encoding UTF-8
88              
89             =head1 NAME
90              
91             TOML::Tiny - a minimal, pure perl TOML parser and serializer
92              
93             =head1 VERSION
94              
95             version 0.16
96              
97             =head1 SYNOPSIS
98              
99             use TOML::Tiny qw(from_toml to_toml);
100              
101             binmode STDIN, ':encoding(UTF-8)';
102             binmode STDOUT, ':encoding(UTF-8)';
103              
104             # Decoding TOML
105             my $toml = do{ local $/; <STDIN> };
106             my ($parsed, $error) = from_toml $toml;
107              
108             # Encoding TOML
109             say to_toml({
110             stuff => {
111             about => ['other', 'stuff'],
112             },
113             });
114              
115             # Object API
116             my $parser = TOML::Tiny->new;
117             my $data = $parser->decode($toml);
118             say $parser->encode($data);
119              
120             =head1 DESCRIPTION
121              
122             =for html <p>
123             <a href="https://github.com/sysread/TOML-Tiny/actions?query=workflow%3Arun-tests">
124             <img src="https://github.com/sysread/TOML-Tiny/workflows/run-tests/badge.svg" alt="Build status" />
125             </a>
126             </p>
127              
128             C<TOML::Tiny> implements a pure-perl parser and generator for the
129             L<TOML|https://github.com/toml-lang/toml> data format. It conforms to TOML v1.0
130             (with a few caveats; see L</strict>).
131              
132             C<TOML::Tiny> strives to maintain an interface compatible to the L<TOML> and
133             L<TOML::Parser> modules, and could even be used to override C<$TOML::Parser>:
134              
135             use TOML;
136             use TOML::Tiny;
137              
138             local $TOML::Parser = TOML::Tiny->new(...);
139             say to_toml(...);
140              
141             =head1 EXPORTS
142              
143             C<TOML::Tiny> exports the following to functions for compatibility with the
144             L<TOML> module. See L<TOML/FUNCTIONS>.
145              
146             =head2 from_toml
147              
148             Parses a string of C<TOML>-formatted source and returns the resulting data
149             structure. Any arguments after the first are passed to L<TOML::Tiny::Parser>'s
150             constructor.
151              
152             If there is a syntax error in the C<TOML> source, C<from_toml> will die with
153             an explanation which includes the line number of the error.
154              
155             my $result = eval{ from_toml($toml_string) };
156              
157             Alternately, this routine may be called in list context, in which case syntax
158             errors will result in returning two values, C<undef> and an error message.
159              
160             my ($result, $error) = from_toml($toml_string);
161              
162             Additional arguments may be passed after the toml source string; see L</new>.
163              
164             =head3 GOTCHAS
165              
166             =over
167              
168             =item Big integers and floats
169              
170             C<TOML> supports integers and floats larger than what many perls support. When
171             C<TOML::Tiny> encounters a value it may not be able to represent as a number,
172             it will instead return a L<Math::BigInt> or L<Math::BigFloat>. This behavior
173             can be overridden by providing inflation routines:
174              
175             my $toml = TOML::Tiny->new(
176             inflate_float => sub{
177             return do_something_else_with_floats( $_[0] );
178             };
179             );
180              
181             =back
182              
183             =head2 to_toml
184              
185             Encodes a hash ref as a C<TOML>-formatted string.
186              
187             my $toml = to_toml({foo => {'bar' => 'bat'}});
188              
189             # [foo]
190             # bar="bat"
191              
192             =head3 mapping perl to TOML types
193              
194             =head4 table
195              
196             =over
197              
198             =item C<HASH> ref
199              
200             =back
201              
202             =head4 array
203              
204             =over
205              
206             =item C<ARRAY> ref
207              
208             =back
209              
210             =head4 boolean
211              
212             =over
213              
214             =item C<\0> or C<\1>
215              
216             =item L<JSON::PP::Boolean>
217              
218             =item L<Types::Serializer::Boolean>
219              
220             =back
221              
222             =head4 numeric types
223              
224             These are tricky in perl. When encountering a C<Math::Big[Int|Float]>,
225             that representation is used.
226              
227             If the value is a defined (non-ref) scalar with the C<SVf_IOK> or C<SVf_NOK>
228             flags set, the value will be emitted unchanged. This is in line with most
229             other packages, so the normal hinting hacks for typed output apply:
230              
231             number => 0 + $number,
232             string => "" . $string,
233              
234             =over
235              
236             =item L<Math::BigInt>
237              
238             =item L<Math::BigFloat>
239              
240             =item numerical scalars
241              
242             =back
243              
244             =head4 datetime
245              
246             =over
247              
248             =item RFC3339-formatted string
249              
250             e.g., C<"1985-04-12T23:20:50.52Z">
251              
252             =item L<DateTime>
253              
254             L<DateTime>s are formatted as C<RFC3339>, as expected by C<TOML>. However,
255             C<TOML> supports the concept of a "local" time zone, which strays from
256             C<RFC3339> by allowing a datetime without a time zone offset. This is
257             represented in perl by a C<DateTime> with a B<floating time zone>.
258              
259             =back
260              
261             =head4 string
262              
263             All other non-ref scalars are treated as strings.
264              
265             =head1 OBJECT API
266              
267             =head2 new
268              
269             =over
270              
271             =item inflate_datetime
272              
273             By default, C<TOML::Tiny> treats TOML datetimes as strings in the generated
274             data structure. The C<inflate_datetime> parameter allows the caller to provide
275             a routine to intercept those as they are generated:
276              
277             use DateTime::Format::RFC3339;
278              
279             my $parser = TOML::Tiny->new(
280             inflate_datetime => sub{
281             my ($dt_string) = @_;
282             # DateTime::Format::RFC3339 will set the resulting DateTime's formatter
283             # to itself. Fallback is the DateTime default, ISO8601, with a possibly
284             # floating time zone.
285             return eval{ DateTime::Format::RFC3339->parse_datetime($dt_string) }
286             || DateTime::Format::ISO8601->parse_datetime($dt_string);
287             },
288             );
289              
290             =item inflate_boolean
291              
292             By default, boolean values in a C<TOML> document result in a C<1> or C<0>.
293             If L<Types::Serialiser> is installed, they will instead be C<Types::Serialiser::true>
294             or C<Types::Serialiser::false>.
295              
296             If you wish to override this, you can provide your own routine to generate values:
297              
298             my $parser = TOML::Tiny->new(
299             inflate_boolean => sub{
300             my $bool = shift;
301             if ($bool eq 'true') {
302             return 'The Truth';
303             } else {
304             return 'A Lie';
305             }
306             },
307             );
308              
309             =item inflate_integer
310              
311             TOML integers are 64 bit and may not match the size of the compiled perl's
312             internal integer type. By default, C<TOML::Tiny> coerces numbers that fit
313             within a perl number by adding C<0>. For bignums, a L<Math::BigInt> is
314             returned. This may be overridden by providing an inflation routine:
315              
316             my $parser = TOML::Tiny->new(
317             inflate_integer => sub{
318             my $parsed = shift;
319             return sprintf 'the number "%d"', $parsed;
320             };
321             );
322              
323             =item inflate_float
324              
325             TOML floats are 64 bit and may not match the size of the compiled perl's
326             internal float type. As with integers, floats are coerced to numbers and large
327             floats are upgraded to L<Math::BigFloat>s. The special strings C<NaN> and
328             C<inf> may also be returned. You can override this by specifying an inflation
329             routine.
330              
331             my $parser = TOML::Tiny->new(
332             inflate_float => sub{
333             my $parsed = shift;
334             return sprintf '"%0.8f" is a float', $parsed;
335             };
336             );
337              
338             =item strict
339              
340             C<strict> imposes some miscellaneous strictures on C<TOML> input, such as
341             disallowing trailing commas in inline tables and failing on invalid UTF8 input.
342              
343             B<Note:> C<strict> was previously called C<strict_arrays>. Both are accepted
344             for backward compatibility, although enforcement of homogenous arrays is no
345             longer supported as it has been dropped from the spec.
346              
347             =back
348              
349             =head2 decode
350              
351             Decodes C<TOML> and returns a hash ref. Dies on parse error.
352              
353             =head2 encode
354              
355             Encodes a perl hash ref as a C<TOML>-formatted string.
356              
357             =head2 parse
358              
359             Alias for C<decode> to provide compatibility with C<TOML::Parser> when
360             overriding the parser by setting C<$TOML::Parser>.
361              
362             =head1 DIFFERENCES FROM L<TOML> AND L<TOML::Parser>
363              
364             C<TOML::Tiny> differs in a few significant ways from the L<TOML> module,
365             particularly in adding support for newer C<TOML> features and strictness.
366              
367             L<TOML> defaults to lax parsing and provides C<strict_mode> to (slightly)
368             tighten things up. C<TOML::Tiny> defaults to (somewhat) stricter parsing,
369             enabling some extra strictures with L</strict>.
370              
371             C<TOML::Tiny> supports a number of options which do not exist in L<TOML>:
372             L</inflate_integer>, L</inflate_float>, and L</strict>.
373              
374             C<TOML::Tiny> ignores invalid surrogate pairs within basic and multiline
375             strings (L<TOML> may attempt to decode an invalid pair). Additionally, only
376             those character escapes officially supported by TOML are interpreted as such by
377             C<TOML::Tiny>.
378              
379             C<TOML::Tiny> supports stripping initial whitespace and handles lines
380             terminating with a backslash correctly in multilne strings:
381              
382             # TOML input
383             x="""
384             foo"""
385              
386             y="""\
387             how now \
388             brown \
389             bureaucrat.\
390             """
391              
392             # Perl output
393             {x => 'foo', y => 'how now brown bureaucrat.'}
394              
395             C<TOML::Tiny> includes support for integers specified in binary, octal or hex
396             as well as the special float values C<inf> and C<nan>.
397              
398             =head1 SEE ALSO
399              
400             =over
401              
402             =item L<TOML::Tiny::Grammar>
403              
404             Regexp scraps used by C<TOML::Tiny> to parse TOML source.
405              
406             =back
407              
408             =head1 ACKNOWLEDGEMENTS
409              
410             Thanks to L<ZipRecruiter|https://www.ziprecruiter.com> for encouraging their
411             employees to contribute back to the open source ecosystem. Without their
412             dedication to quality software development this distribution would not exist.
413              
414             A big thank you to those who have contributed code or bug reports:
415              
416             =over
417              
418             =item L<ijackson|https://github.com/ijackson>
419              
420             =item L<noctux|https://github.com/noctux>
421              
422             =item L<oschwald|https://github.com/oschwald>
423              
424             =item L<jjatria|https://metacpan.org/author/JJATRIA>
425              
426             =back
427              
428             =head1 AUTHOR
429              
430             Jeff Ober <sysread@fastmail.fm>
431              
432             =head1 COPYRIGHT AND LICENSE
433              
434             This software is copyright (c) 2023 by Jeff Ober.
435              
436             This is free software; you can redistribute it and/or modify it under
437             the same terms as the Perl 5 programming language system itself.
438              
439             =cut