File Coverage

blib/lib/TOML/Tiny.pm
Criterion Covered Total %
statement 37 43 86.0
branch 5 8 62.5
condition n/a
subroutine 12 13 92.3
pod 6 6 100.0
total 60 70 85.7


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