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.14';
4 284     284   74728138 use strict;
  284         2348  
  284         8774  
5 284     284   1502 use warnings;
  284         576  
  284         8442  
6 284     284   1377 no warnings qw(experimental);
  284         529  
  284         9930  
7 284     284   4260 use v5.18;
  284         990  
8              
9 284     284   142477 use TOML::Tiny::Parser;
  284         984  
  284         12213  
10 284     284   137081 use TOML::Tiny::Writer;
  284         873  
  284         10864  
11              
12 284     284   2462 use parent 'Exporter';
  284         611  
  284         2094  
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 484836 my ($source, %param) = @_;
24              
25             # strict was previously strict_arrays; accept both for backward
26             # compatibility.
27 425 50       2118 if (exists $param{strict_arrays}) {
28 0         0 $param{strict} = $param{strict_arrays};
29 0         0 delete $param{strict_arrays};
30             }
31              
32 425         4436 my $parser = TOML::Tiny::Parser->new(%param);
33 425         1140 my $toml = eval{ $parser->parse($source) };
  425         2119  
34              
35 425 50       2638 if (wantarray) {
36 0         0 return ($toml, $@);
37             } else {
38 425 100       5459 die $@ if $@;
39 240         2683 return $toml;
40             }
41             }
42              
43             sub to_toml {
44 102     102 1 806935 my ($data, %param) = @_;
45              
46             # strict was previously strict_arrays; accept both for backward
47             # compatibility.
48 102 50       723 if (exists $param{strict_arrays}) {
49 0         0 $param{strict} = $param{strict_arrays};
50 0         0 delete $param{strict_arrays};
51             }
52              
53 102         795 TOML::Tiny::Writer::to_toml($data, %param);
54             }
55              
56             #-------------------------------------------------------------------------------
57             # Object API
58             #-------------------------------------------------------------------------------
59             sub new {
60 2     2 1 2777 my ($class, %param) = @_;
61 2         20 bless{ %param, parser => TOML::Tiny::Parser->new(%param) }, $class;
62             }
63              
64             sub decode {
65 2     2 1 5021 my ($self, $source) = @_;
66 2         18 $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.14
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 (somehwat) 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) 2021 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