chiark / gitweb /
TOML::Tiny::Faithful: Use ISO8601 for parsing
[nailing-cargo.git] / lib / TOML / Tiny / Faithful.pm
1
2 package TOML::Tiny::Faithful;
3 use parent TOML::Tiny;
4 use DateTime::Format::ISO8601;
5 use DateTime::Format::RFC3339;
6
7 use DateTime;
8 use Types::Serialiser; # ensures that Parser DTRT with booleans
9
10 our @EXPORT = qw(
11   from_toml
12   to_toml
13 );
14
15 sub _options {
16   inflate_datetime => sub {
17     # RFC3339 bombs out if there is no timezone, so we parse with 8601
18     DateTime::Format::ISO8601->parse_datetime(shift)
19   },
20   inflate_integer => sub { 
21     use bignum;
22     my $s = shift;
23     $s =~ m/^0o/
24         ? Math::BigInt->from_oct($')
25         : Math::BigInt->new($s);
26   },
27   inflate_float => sub { 0. + shift; },
28   no_string_guessing => 1,
29   datetime_formatter => TOML::Tiny::Faithful::DateTime::Formatter->new(),
30 }
31
32 sub new {
33   my ($class, %param) = @_;
34   bless TOML::Tiny->new(_options(), %param), $class;
35 }
36 sub from_toml {
37   my $source = shift;
38   TOML::Tiny::from_toml($source, _options(), @_);
39 }
40 sub to_toml {
41   my $source = shift;
42   TOML::Tiny::to_toml($source, _options(), @_);
43 }
44
45 package TOML::Tiny::Faithful::DateTime::Formatter;
46 use DateTime::Format::RFC3339;
47
48 our $base = DateTime::Format::RFC3339->new();
49
50 sub new ($) {
51     my ($class) = @_;
52     bless { }, $class;
53 }
54
55 sub format_datetime {
56     my ($self,$dt) = @_;
57     # RFC3339 always prints a timezone.  This is correct for RFC3339
58     # but in our application we sometimes have "local datetime"s
59     # where the time_zone is DateTime::TimeZone::Floating.
60     # We could use ISO8601 but it never prints the nanoseconds.
61     # It is easier to strip the timezone offset than add the ns.
62     my $r = DateTime::Format::RFC3339->new()->format_datetime($dt);
63     if ((ref $dt->time_zone()) =~ m/Floating/) {
64         $r =~ s/\+[0-9:.]+$//;
65     }
66     $r
67 }
68
69 1;
70
71 =head1 SYNOPSIS
72
73   use TOML::Tiny::Faithful qw(from_toml to_toml);
74
75   binmode STDIN,  ':encoding(UTF-8)';
76   binmode STDOUT, ':encoding(UTF-8)';
77
78   # Decoding TOML
79   my $toml = do{ local $/; <STDIN> };
80   my ($parsed, $error) = from_toml $toml;
81
82   # Encoding TOML
83   say to_toml({
84     stuff => {
85       about => ['other', 'stuff'],
86     },
87   });
88
89   # Object API
90   my $parser = TOML::Tiny::Faithful->new;
91   my $data = $parser->decode($toml);
92   say $parser->encode($data);
93
94
95 =head1 DESCRIPTION
96
97 C<TOML::Tiny::Faithful> is a trivial wrapper around C<TOML::Tiny>
98 which sets C<inflate_integer>, C<inflate_float>, C<inflate_datetime>,
99 C<no_string_guessing> and C<datetime_formatter> to try to make the
100 TOML output faithful to any input TOML.
101
102 =head1 SEE ALSO
103
104 =over
105
106 =item L<TOML::Tiny>
107
108 =back