Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / YAML / Tiny.pm
1 package YAML::Tiny;
2
3 use strict;
4 use Carp 'croak';
5
6 # UTF Support?
7 sub HAVE_UTF8 () { $] >= 5.007003 }
8 BEGIN {
9         if ( HAVE_UTF8 ) {
10                 # The string eval helps hide this from Test::MinimumVersion
11                 eval "require utf8;";
12                 die "Failed to load UTF-8 support" if $@;
13         }
14
15         # Class structure
16         require 5.004;
17         require Exporter;
18         $YAML::Tiny::VERSION   = '1.40';
19         @YAML::Tiny::ISA       = qw{ Exporter  };
20         @YAML::Tiny::EXPORT    = qw{ Load Dump };
21         @YAML::Tiny::EXPORT_OK = qw{ LoadFile DumpFile freeze thaw };
22
23         # Error storage
24         $YAML::Tiny::errstr    = '';
25 }
26
27 # The character class of all characters we need to escape
28 # NOTE: Inlined, since it's only used once
29 # my $RE_ESCAPE   = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f\"\n]';
30
31 # Printed form of the unprintable characters in the lowest range
32 # of ASCII characters, listed by ASCII ordinal position.
33 my @UNPRINTABLE = qw(
34         z    x01  x02  x03  x04  x05  x06  a
35         x08  t    n    v    f    r    x0e  x0f
36         x10  x11  x12  x13  x14  x15  x16  x17
37         x18  x19  x1a  e    x1c  x1d  x1e  x1f
38 );
39
40 # Printable characters for escapes
41 my %UNESCAPES = (
42         z => "\x00", a => "\x07", t    => "\x09",
43         n => "\x0a", v => "\x0b", f    => "\x0c",
44         r => "\x0d", e => "\x1b", '\\' => '\\',
45 );
46
47 # Special magic boolean words
48 my %QUOTE = map { $_ => 1 } qw{
49         null Null NULL
50         y Y yes Yes YES n N no No NO
51         true True TRUE false False FALSE
52         on On ON off Off OFF
53 };
54
55
56
57
58
59 #####################################################################
60 # Implementation
61
62 # Create an empty YAML::Tiny object
63 sub new {
64         my $class = shift;
65         bless [ @_ ], $class;
66 }
67
68 # Create an object from a file
69 sub read {
70         my $class = ref $_[0] ? ref shift : shift;
71
72         # Check the file
73         my $file = shift or return $class->_error( 'You did not specify a file name' );
74         return $class->_error( "File '$file' does not exist" )              unless -e $file;
75         return $class->_error( "'$file' is a directory, not a file" )       unless -f _;
76         return $class->_error( "Insufficient permissions to read '$file'" ) unless -r _;
77
78         # Slurp in the file
79         local $/ = undef;
80         local *CFG;
81         unless ( open(CFG, $file) ) {
82                 return $class->_error("Failed to open file '$file': $!");
83         }
84         my $contents = <CFG>;
85         unless ( close(CFG) ) {
86                 return $class->_error("Failed to close file '$file': $!");
87         }
88
89         $class->read_string( $contents );
90 }
91
92 # Create an object from a string
93 sub read_string {
94         my $class  = ref $_[0] ? ref shift : shift;
95         my $self   = bless [], $class;
96         my $string = $_[0];
97         unless ( defined $string ) {
98                 return $self->_error("Did not provide a string to load");
99         }
100
101         # Byte order marks
102         # NOTE: Keeping this here to educate maintainers
103         # my %BOM = (
104         #     "\357\273\277" => 'UTF-8',
105         #     "\376\377"     => 'UTF-16BE',
106         #     "\377\376"     => 'UTF-16LE',
107         #     "\377\376\0\0" => 'UTF-32LE'
108         #     "\0\0\376\377" => 'UTF-32BE',
109         # );
110         if ( $string =~ /^(?:\376\377|\377\376|\377\376\0\0|\0\0\376\377)/ ) {
111                 return $self->_error("Stream has a non UTF-8 BOM");
112         } else {
113                 # Strip UTF-8 bom if found, we'll just ignore it
114                 $string =~ s/^\357\273\277//;
115         }
116
117         # Try to decode as utf8
118         utf8::decode($string) if HAVE_UTF8;
119
120         # Check for some special cases
121         return $self unless length $string;
122         unless ( $string =~ /[\012\015]+\z/ ) {
123                 return $self->_error("Stream does not end with newline character");
124         }
125
126         # Split the file into lines
127         my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
128                     split /(?:\015{1,2}\012|\015|\012)/, $string;
129
130         # Strip the initial YAML header
131         @lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;
132
133         # A nibbling parser
134         while ( @lines ) {
135                 # Do we have a document header?
136                 if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
137                         # Handle scalar documents
138                         shift @lines;
139                         if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
140                                 push @$self, $self->_read_scalar( "$1", [ undef ], \@lines );
141                                 next;
142                         }
143                 }
144
145                 if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
146                         # A naked document
147                         push @$self, undef;
148                         while ( @lines and $lines[0] !~ /^---/ ) {
149                                 shift @lines;
150                         }
151
152                 } elsif ( $lines[0] =~ /^\s*\-/ ) {
153                         # An array at the root
154                         my $document = [ ];
155                         push @$self, $document;
156                         $self->_read_array( $document, [ 0 ], \@lines );
157
158                 } elsif ( $lines[0] =~ /^(\s*)\S/ ) {
159                         # A hash at the root
160                         my $document = { };
161                         push @$self, $document;
162                         $self->_read_hash( $document, [ length($1) ], \@lines );
163
164                 } else {
165                         croak("YAML::Tiny failed to classify the line '$lines[0]'");
166                 }
167         }
168
169         $self;
170 }
171
172 # Deparse a scalar string to the actual scalar
173 sub _read_scalar {
174         my ($self, $string, $indent, $lines) = @_;
175
176         # Trim trailing whitespace
177         $string =~ s/\s*\z//;
178
179         # Explitic null/undef
180         return undef if $string eq '~';
181
182         # Quotes
183         if ( $string =~ /^\'(.*?)\'\z/ ) {
184                 return '' unless defined $1;
185                 $string = $1;
186                 $string =~ s/\'\'/\'/g;
187                 return $string;
188         }
189         if ( $string =~ /^\"((?:\\.|[^\"])*)\"\z/ ) {
190                 # Reusing the variable is a little ugly,
191                 # but avoids a new variable and a string copy.
192                 $string = $1;
193                 $string =~ s/\\"/"/g;
194                 $string =~ s/\\([never\\fartz]|x([0-9a-fA-F]{2}))/(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}/gex;
195                 return $string;
196         }
197
198         # Special cases
199         if ( $string =~ /^[\'\"!&]/ ) {
200                 croak("YAML::Tiny does not support a feature in line '$lines->[0]'");
201         }
202         return {} if $string eq '{}';
203         return [] if $string eq '[]';
204
205         # Regular unquoted string
206         return $string unless $string =~ /^[>|]/;
207
208         # Error
209         croak("YAML::Tiny failed to find multi-line scalar content") unless @$lines;
210
211         # Check the indent depth
212         $lines->[0]   =~ /^(\s*)/;
213         $indent->[-1] = length("$1");
214         if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
215                 croak("YAML::Tiny found bad indenting in line '$lines->[0]'");
216         }
217
218         # Pull the lines
219         my @multiline = ();
220         while ( @$lines ) {
221                 $lines->[0] =~ /^(\s*)/;
222                 last unless length($1) >= $indent->[-1];
223                 push @multiline, substr(shift(@$lines), length($1));
224         }
225
226         my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
227         my $t = (substr($string, 1, 1) eq '-') ? ''  : "\n";
228         return join( $j, @multiline ) . $t;
229 }
230
231 # Parse an array
232 sub _read_array {
233         my ($self, $array, $indent, $lines) = @_;
234
235         while ( @$lines ) {
236                 # Check for a new document
237                 if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
238                         while ( @$lines and $lines->[0] !~ /^---/ ) {
239                                 shift @$lines;
240                         }
241                         return 1;
242                 }
243
244                 # Check the indent level
245                 $lines->[0] =~ /^(\s*)/;
246                 if ( length($1) < $indent->[-1] ) {
247                         return 1;
248                 } elsif ( length($1) > $indent->[-1] ) {
249                         croak("YAML::Tiny found bad indenting in line '$lines->[0]'");
250                 }
251
252                 if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
253                         # Inline nested hash
254                         my $indent2 = length("$1");
255                         $lines->[0] =~ s/-/ /;
256                         push @$array, { };
257                         $self->_read_hash( $array->[-1], [ @$indent, $indent2 ], $lines );
258
259                 } elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
260                         # Array entry with a value
261                         shift @$lines;
262                         push @$array, $self->_read_scalar( "$2", [ @$indent, undef ], $lines );
263
264                 } elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
265                         shift @$lines;
266                         unless ( @$lines ) {
267                                 push @$array, undef;
268                                 return 1;
269                         }
270                         if ( $lines->[0] =~ /^(\s*)\-/ ) {
271                                 my $indent2 = length("$1");
272                                 if ( $indent->[-1] == $indent2 ) {
273                                         # Null array entry
274                                         push @$array, undef;
275                                 } else {
276                                         # Naked indenter
277                                         push @$array, [ ];
278                                         $self->_read_array( $array->[-1], [ @$indent, $indent2 ], $lines );
279                                 }
280
281                         } elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
282                                 push @$array, { };
283                                 $self->_read_hash( $array->[-1], [ @$indent, length("$1") ], $lines );
284
285                         } else {
286                                 croak("YAML::Tiny failed to classify line '$lines->[0]'");
287                         }
288
289                 } elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
290                         # This is probably a structure like the following...
291                         # ---
292                         # foo:
293                         # - list
294                         # bar: value
295                         #
296                         # ... so lets return and let the hash parser handle it
297                         return 1;
298
299                 } else {
300                         croak("YAML::Tiny failed to classify line '$lines->[0]'");
301                 }
302         }
303
304         return 1;
305 }
306
307 # Parse an array
308 sub _read_hash {
309         my ($self, $hash, $indent, $lines) = @_;
310
311         while ( @$lines ) {
312                 # Check for a new document
313                 if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
314                         while ( @$lines and $lines->[0] !~ /^---/ ) {
315                                 shift @$lines;
316                         }
317                         return 1;
318                 }
319
320                 # Check the indent level
321                 $lines->[0] =~ /^(\s*)/;
322                 if ( length($1) < $indent->[-1] ) {
323                         return 1;
324                 } elsif ( length($1) > $indent->[-1] ) {
325                         croak("YAML::Tiny found bad indenting in line '$lines->[0]'");
326                 }
327
328                 # Get the key
329                 unless ( $lines->[0] =~ s/^\s*([^\'\" ][^\n]*?)\s*:(\s+|$)// ) {
330                         if ( $lines->[0] =~ /^\s*[?\'\"]/ ) {
331                                 croak("YAML::Tiny does not support a feature in line '$lines->[0]'");
332                         }
333                         croak("YAML::Tiny failed to classify line '$lines->[0]'");
334                 }
335                 my $key = $1;
336
337                 # Do we have a value?
338                 if ( length $lines->[0] ) {
339                         # Yes
340                         $hash->{$key} = $self->_read_scalar( shift(@$lines), [ @$indent, undef ], $lines );
341                 } else {
342                         # An indent
343                         shift @$lines;
344                         unless ( @$lines ) {
345                                 $hash->{$key} = undef;
346                                 return 1;
347                         }
348                         if ( $lines->[0] =~ /^(\s*)-/ ) {
349                                 $hash->{$key} = [];
350                                 $self->_read_array( $hash->{$key}, [ @$indent, length($1) ], $lines );
351                         } elsif ( $lines->[0] =~ /^(\s*)./ ) {
352                                 my $indent2 = length("$1");
353                                 if ( $indent->[-1] >= $indent2 ) {
354                                         # Null hash entry
355                                         $hash->{$key} = undef;
356                                 } else {
357                                         $hash->{$key} = {};
358                                         $self->_read_hash( $hash->{$key}, [ @$indent, length($1) ], $lines );
359                                 }
360                         }
361                 }
362         }
363
364         return 1;
365 }
366
367 # Save an object to a file
368 sub write {
369         my $self = shift;
370         my $file = shift or return $self->_error('No file name provided');
371
372         # Write it to the file
373         open( CFG, '>' . $file ) or return $self->_error(
374                 "Failed to open file '$file' for writing: $!"
375                 );
376         print CFG $self->write_string;
377         close CFG;
378
379         return 1;
380 }
381
382 # Save an object to a string
383 sub write_string {
384         my $self = shift;
385         return '' unless @$self;
386
387         # Iterate over the documents
388         my $indent = 0;
389         my @lines  = ();
390         foreach my $cursor ( @$self ) {
391                 push @lines, '---';
392
393                 # An empty document
394                 if ( ! defined $cursor ) {
395                         # Do nothing
396
397                 # A scalar document
398                 } elsif ( ! ref $cursor ) {
399                         $lines[-1] .= ' ' . $self->_write_scalar( $cursor, $indent );
400
401                 # A list at the root
402                 } elsif ( ref $cursor eq 'ARRAY' ) {
403                         unless ( @$cursor ) {
404                                 $lines[-1] .= ' []';
405                                 next;
406                         }
407                         push @lines, $self->_write_array( $cursor, $indent, {} );
408
409                 # A hash at the root
410                 } elsif ( ref $cursor eq 'HASH' ) {
411                         unless ( %$cursor ) {
412                                 $lines[-1] .= ' {}';
413                                 next;
414                         }
415                         push @lines, $self->_write_hash( $cursor, $indent, {} );
416
417                 } else {
418                         croak("Cannot serialize " . ref($cursor));
419                 }
420         }
421
422         join '', map { "$_\n" } @lines;
423 }
424
425 sub _write_scalar {
426         my $string = $_[1];
427         return '~'  unless defined $string;
428         return "''" unless length  $string;
429         if ( $string =~ /[\x00-\x08\x0b-\x0d\x0e-\x1f\"\'\n]/ ) {
430                 $string =~ s/\\/\\\\/g;
431                 $string =~ s/"/\\"/g;
432                 $string =~ s/\n/\\n/g;
433                 $string =~ s/([\x00-\x1f])/\\$UNPRINTABLE[ord($1)]/g;
434                 return qq|"$string"|;
435         }
436         if ( $string =~ /(?:^\W|\s)/ or $QUOTE{$string} ) {
437                 return "'$string'";
438         }
439         return $string;
440 }
441
442 sub _write_array {
443         my ($self, $array, $indent, $seen) = @_;
444         if ( $seen->{refaddr($array)}++ ) {
445                 die "YAML::Tiny does not support circular references";
446         }
447         my @lines  = ();
448         foreach my $el ( @$array ) {
449                 my $line = ('  ' x $indent) . '-';
450                 my $type = ref $el;
451                 if ( ! $type ) {
452                         $line .= ' ' . $self->_write_scalar( $el, $indent + 1 );
453                         push @lines, $line;
454
455                 } elsif ( $type eq 'ARRAY' ) {
456                         if ( @$el ) {
457                                 push @lines, $line;
458                                 push @lines, $self->_write_array( $el, $indent + 1, $seen );
459                         } else {
460                                 $line .= ' []';
461                                 push @lines, $line;
462                         }
463
464                 } elsif ( $type eq 'HASH' ) {
465                         if ( keys %$el ) {
466                                 push @lines, $line;
467                                 push @lines, $self->_write_hash( $el, $indent + 1, $seen );
468                         } else {
469                                 $line .= ' {}';
470                                 push @lines, $line;
471                         }
472
473                 } else {
474                         die "YAML::Tiny does not support $type references";
475                 }
476         }
477
478         @lines;
479 }
480
481 sub _write_hash {
482         my ($self, $hash, $indent, $seen) = @_;
483         if ( $seen->{refaddr($hash)}++ ) {
484                 die "YAML::Tiny does not support circular references";
485         }
486         my @lines  = ();
487         foreach my $name ( sort keys %$hash ) {
488                 my $el   = $hash->{$name};
489                 my $line = ('  ' x $indent) . "$name:";
490                 my $type = ref $el;
491                 if ( ! $type ) {
492                         $line .= ' ' . $self->_write_scalar( $el, $indent + 1 );
493                         push @lines, $line;
494
495                 } elsif ( $type eq 'ARRAY' ) {
496                         if ( @$el ) {
497                                 push @lines, $line;
498                                 push @lines, $self->_write_array( $el, $indent + 1, $seen );
499                         } else {
500                                 $line .= ' []';
501                                 push @lines, $line;
502                         }
503
504                 } elsif ( $type eq 'HASH' ) {
505                         if ( keys %$el ) {
506                                 push @lines, $line;
507                                 push @lines, $self->_write_hash( $el, $indent + 1, $seen );
508                         } else {
509                                 $line .= ' {}';
510                                 push @lines, $line;
511                         }
512
513                 } else {
514                         die "YAML::Tiny does not support $type references";
515                 }
516         }
517
518         @lines;
519 }
520
521 # Set error
522 sub _error {
523         $YAML::Tiny::errstr = $_[1];
524         undef;
525 }
526
527 # Retrieve error
528 sub errstr {
529         $YAML::Tiny::errstr;
530 }
531
532
533
534
535
536 #####################################################################
537 # YAML Compatibility
538
539 sub Dump {
540         YAML::Tiny->new(@_)->write_string;
541 }
542
543 sub Load {
544         my $self = YAML::Tiny->read_string(@_);
545         unless ( $self ) {
546                 croak("Failed to load YAML document from string");
547         }
548         if ( wantarray ) {
549                 return @$self;
550         } else {
551                 # To match YAML.pm, return the last document
552                 return $self->[-1];
553         }
554 }
555
556 BEGIN {
557         *freeze = *Dump;
558         *thaw   = *Load;
559 }
560
561 sub DumpFile {
562         my $file = shift;
563         YAML::Tiny->new(@_)->write($file);
564 }
565
566 sub LoadFile {
567         my $self = YAML::Tiny->read($_[0]);
568         unless ( $self ) {
569                 croak("Failed to load YAML document from '" . ($_[0] || '') . "'");
570         }
571         if ( wantarray ) {
572                 return @$self;
573         } else {
574                 # Return only the last document to match YAML.pm, 
575                 return $self->[-1];
576         }
577 }
578
579
580
581
582
583 #####################################################################
584 # Use Scalar::Util if possible, otherwise emulate it
585
586 BEGIN {
587         eval {
588                 require Scalar::Util;
589         };
590         if ( $@ ) {
591                 # Failed to load Scalar::Util
592                 eval <<'END_PERL';
593 sub refaddr {
594         my $pkg = ref($_[0]) or return undef;
595         if (!!UNIVERSAL::can($_[0], 'can')) {
596                 bless $_[0], 'Scalar::Util::Fake';
597         } else {
598                 $pkg = undef;
599         }
600         "$_[0]" =~ /0x(\w+)/;
601         my $i = do { local $^W; hex $1 };
602         bless $_[0], $pkg if defined $pkg;
603         $i;
604 }
605 END_PERL
606         } else {
607                 Scalar::Util->import('refaddr');
608         }
609 }
610
611 1;
612
613 __END__
614
615 =pod
616
617 =head1 NAME
618
619 YAML::Tiny - Read/Write YAML files with as little code as possible
620
621 =head1 PREAMBLE
622
623 The YAML specification is huge. Really, B<really> huge. It contains all the
624 functionality of XML, except with flexibility and choice, which makes it
625 easier to read, but with a formal specification that is more complex than
626 XML.
627
628 The original pure-Perl implementation L<YAML> costs just over 4 megabytes of
629 memory to load. Just like with Windows .ini files (3 meg to load) and CSS
630 (3.5 meg to load) the situation is just asking for a B<YAML::Tiny> module, an
631 incomplete but correct and usable subset of the functionality, in as little
632 code as possible.
633
634 Like the other C<::Tiny> modules, YAML::Tiny will have no non-core
635 dependencies, not require a compiler, and be back-compatible to at least
636 perl 5.005_03, and ideally 5.004.
637
638 =head1 SYNOPSIS
639
640     #############################################
641     # In your file
642     
643     ---
644     rootproperty: blah
645     section:
646       one: two
647       three: four
648       Foo: Bar
649       empty: ~
650     
651     
652     
653     #############################################
654     # In your program
655     
656     use YAML::Tiny;
657     
658     # Create a YAML file
659     my $yaml = YAML::Tiny->new;
660     
661     # Open the config
662     $yaml = YAML::Tiny->read( 'file.yml' );
663     
664     # Reading properties
665     my $root = $yaml->[0]->{rootproperty};
666     my $one  = $yaml->[0]->{section}->{one};
667     my $Foo  = $yaml->[0]->{section}->{Foo};
668     
669     # Changing data
670     $yaml->[0]->{newsection} = { this => 'that' }; # Add a section
671     $yaml->[0]->{section}->{Foo} = 'Not Bar!';     # Change a value
672     delete $yaml->[0]->{section};                  # Delete a value or section
673     
674     # Add an entire document
675     $yaml->[1] = [ 'foo', 'bar', 'baz' ];
676     
677     # Save the file
678     $yaml->write( 'file.conf' );
679
680 =head1 DESCRIPTION
681
682 B<YAML::Tiny> is a perl class for reading and writing YAML-style files,
683 written with as little code as possible, reducing load time and memory
684 overhead.
685
686 Most of the time it is accepted that Perl applications use a lot
687 of memory and modules. The B<::Tiny> family of modules is specifically
688 intended to provide an ultralight and zero-dependency alternative to
689 many more-thorough standard modules.
690
691 This module is primarily for reading human-written files (like simple
692 config files) and generating very simple human-readable files. Note that
693 I said B<human-readable> and not B<geek-readable>. The sort of files that
694 your average manager or secretary should be able to look at and make
695 sense of.
696
697 L<YAML::Tiny> does not generate comments, it won't necesarily preserve the
698 order of your hashes, and it will normalise if reading in and writing out
699 again.
700
701 It only supports a very basic subset of the full YAML specification.
702
703 Usage is targetted at files like Perl's META.yml, for which a small and
704 easily-embeddable module is extremely attractive.
705
706 Features will only be added if they are human readable, and can be written
707 in a few lines of code. Please don't be offended if your request is
708 refused. Someone has to draw the line, and for YAML::Tiny that someone is me.
709
710 If you need something with more power move up to L<YAML> (4 megabytes of
711 memory overhead) or L<YAML::Syck> (275k, but requires libsyck and a C
712 compiler).
713
714 To restate, L<YAML::Tiny> does B<not> preserve your comments, whitespace, or
715 the order of your YAML data. But it should round-trip from Perl structure
716 to file and back again just fine.
717
718 =head1 YAML TINY SPECIFICATION
719
720 This section of the documentation provides a specification for "YAML Tiny",
721 a subset of the YAML specification.
722
723 It is based on and described comparatively to the YAML 1.1  Working Draft
724 2004-12-28 specification, located at L<http://yaml.org/spec/current.html>.
725
726 Terminology and chapter numbers are based on that specification.
727
728 =head2 1. Introduction and Goals
729
730 The purpose of the YAML Tiny specification is to describe a useful subset of
731 the YAML specification that can be used for typical document-oriented
732 uses such as configuration files and simple data structure dumps.
733
734 Many specification elements that add flexibility or extensibility are
735 intentionally removed, as is support for complex datastructures, class
736 and object-orientation.
737
738 In general, YAML Tiny targets only those data structures available in
739 JSON, with the additional limitation that only simple keys are supported.
740
741 As a result, all possible YAML Tiny documents should be able to be
742 transformed into an equivalent JSON document, although the reverse is
743 not necesarily true (but will be true in simple cases).
744
745 As a result of these simplifications the YAML Tiny specification should
746 be implementable in a relatively small amount of code in any language
747 that supports Perl Compatible Regular Expressions (PCRE).
748
749 =head2 2. Introduction
750
751 YAML Tiny supports three data structures. These are scalars (in a variety
752 of forms), block-form sequences and block-form mappings. Flow-style
753 sequences and mappings are not supported, with some minor exceptions
754 detailed later.
755
756 The use of three dashes "---" to indicate the start of a new document is
757 supported, and multiple documents per file/stream is allowed.
758
759 Both line and inline comments are supported.
760
761 Scalars are supported via the plain style, single quote and double quote,
762 as well as literal-style and folded-style multi-line scalars.
763
764 The use of tags is not supported.
765
766 The use of anchors and aliases is not supported.
767
768 The use of directives is supported only for the %YAML directive.
769
770 =head2 3. Processing YAML Tiny Information
771
772 B<Processes>
773
774 The YAML specification dictates three-phase serialization and three-phase
775 deserialization.
776
777 The YAML Tiny specification does not mandate any particular methodology
778 or mechanism for parsing.
779
780 Any compliant parser is only required to parse a single document at a
781 time. The ability to support streaming documents is optional and most
782 likely non-typical.
783
784 Because anchors and aliases are not supported, the resulting representation
785 graph is thus directed but (unlike the main YAML specification) B<acyclic>.
786
787 Circular references/pointers are not possible, and any YAML Tiny serializer
788 detecting a circulars should error with an appropriate message.
789
790 B<Presentation Stream>
791
792 YAML Tiny is notionally unicode, but support for unicode is required if the
793 underlying language or system being used to implement a parser does not
794 support Unicode. If unicode is encountered in this case an error should be
795 returned.
796
797 B<Loading Failure Points>
798
799 YAML Tiny parsers and emitters are not expected to recover from adapt to
800 errors. The specific error modality of any implementation is not dictated
801 (return codes, exceptions, etc) but is expected to be consistant.
802
803 =head2 4. Syntax
804
805 B<Character Set>
806
807 YAML Tiny streams are implemented primarily using the ASCII character set,
808 although the use of Unicode inside strings is allowed if support by the
809 implementation.
810
811 Specific YAML Tiny encoded document types aiming for maximum compatibility
812 should restrict themselves to ASCII.
813
814 The escaping and unescaping of the 8-bit YAML escapes is required.
815
816 The escaping and unescaping of 16-bit and 32-bit YAML escapes is not
817 required.
818
819 B<Indicator Characters>
820
821 Support for the "~" null/undefined indicator is required.
822
823 Implementations may represent this as appropriate for the underlying
824 language.
825
826 Support for the "-" block sequence indicator is required.
827
828 Support for the "?" mapping key indicator is B<not> required.
829
830 Support for the ":" mapping value indicator is required.
831
832 Support for the "," flow collection indicator is B<not> required.
833
834 Support for the "[" flow sequence indicator is B<not> required, with
835 one exception (detailed below).
836
837 Support for the "]" flow sequence indicator is B<not> required, with
838 one exception (detailed below).
839
840 Support for the "{" flow mapping indicator is B<not> required, with
841 one exception (detailed below).
842
843 Support for the "}" flow mapping indicator is B<not> required, with
844 one exception (detailed below).
845
846 Support for the "#" comment indicator is required.
847
848 Support for the "&" anchor indicator is B<not> required.
849
850 Support for the "*" alias indicator is B<not> required.
851
852 Support for the "!" tag indicator is B<not> required.
853
854 Support for the "|" literal block indicator is required.
855
856 Support for the ">" folded block indicator is required.
857
858 Support for the "'" single quote indicator is required.
859
860 Support for the """ double quote indicator is required.
861
862 Support for the "%" directive indicator is required, but only
863 for the special case of a %YAML version directive before the
864 "---" document header, or on the same line as the document header.
865
866 For example:
867
868   %YAML 1.1
869   ---
870   - A sequence with a single element
871
872 Special Exception:
873
874 To provide the ability to support empty sequences
875 and mappings, support for the constructs [] (empty sequence) and {}
876 (empty mapping) are required.
877
878 For example, 
879   
880   %YAML 1.1
881   # A document consisting of only an empty mapping
882   --- {}
883   # A document consisting of only an empty sequence
884   --- []
885   # A document consisting of an empty mapping within a sequence
886   - foo
887   - {}
888   - bar
889
890 B<Syntax Primitives>
891
892 Other than the empty sequence and mapping cases described above, YAML Tiny
893 supports only the indentation-based block-style group of contexts.
894
895 All five scalar contexts are supported.
896
897 Indentation spaces work as per the YAML specification in all cases.
898
899 Comments work as per the YAML specification in all simple cases.
900 Support for indented multi-line comments is B<not> required.
901
902 Seperation spaces work as per the YAML specification in all cases.
903
904 B<YAML Tiny Character Stream>
905
906 The only directive supported by the YAML Tiny specification is the
907 %YAML language/version identifier. Although detected, this directive
908 will have no control over the parsing itself.
909
910 The parser must recognise both the YAML 1.0 and YAML 1.1+ formatting
911 of this directive (as well as the commented form, although no explicit
912 code should be needed to deal with this case, being a comment anyway)
913
914 That is, all of the following should be supported.
915
916   --- #YAML:1.0
917   - foo
918
919   %YAML:1.0
920   ---
921   - foo
922
923   % YAML 1.1
924   ---
925   - foo
926
927 Support for the %TAG directive is B<not> required.
928
929 Support for additional directives is B<not> required.
930
931 Support for the document boundary marker "---" is required.
932
933 Support for the document boundary market "..." is B<not> required.
934
935 If necesary, a document boundary should simply by indicated with a
936 "---" marker, with not preceding "..." marker.
937
938 Support for empty streams (containing no documents) is required.
939
940 Support for implicit document starts is required.
941
942 That is, the following must be equivalent.
943
944  # Full form
945  %YAML 1.1
946  ---
947  foo: bar
948
949  # Implicit form
950  foo: bar
951
952 B<Nodes>
953
954 Support for nodes optional anchor and tag properties are B<not> required.
955
956 Support for node anchors is B<not> required.
957
958 Supprot for node tags is B<not> required.
959
960 Support for alias nodes is B<not> required.
961
962 Support for flow nodes is B<not> required.
963
964 Support for block nodes is required.
965
966 B<Scalar Styles>
967
968 Support for all five scalar styles are required as per the YAML
969 specification, although support for quoted scalars spanning more
970 than one line is B<not> required.
971
972 Support for the chomping indicators on multi-line scalar styles
973 is required.
974
975 B<Collection Styles>
976
977 Support for block-style sequences is required.
978
979 Support for flow-style sequences is B<not> required.
980
981 Support for block-style mappings is required.
982
983 Support for flow-style mappings is B<not> required.
984
985 Both sequences and mappings should be able to be arbitrarily
986 nested.
987
988 Support for plain-style mapping keys is required.
989
990 Support for quoted keys in mappings is B<not> required.
991
992 Support for "?"-indicated explicit keys is B<not> required.
993
994 Here endeth the specification.
995
996 =head2 Additional Perl-Specific Notes
997
998 For some Perl applications, it's important to know if you really have a
999 number and not a string.
1000
1001 That is, in some contexts is important that 3 the number is distinctive
1002 from "3" the string.
1003
1004 Because even Perl itself is not trivially able to understand the difference
1005 (certainly without XS-based modules) Perl implementations of the YAML Tiny
1006 specification are not required to retain the distinctiveness of 3 vs "3".
1007
1008 =head1 METHODS
1009
1010 =head2 new
1011
1012 The constructor C<new> creates and returns an empty C<YAML::Tiny> object.
1013
1014 =head2 read $filename
1015
1016 The C<read> constructor reads a YAML file, and returns a new
1017 C<YAML::Tiny> object containing the contents of the file. 
1018
1019 Returns the object on success, or C<undef> on error.
1020
1021 When C<read> fails, C<YAML::Tiny> sets an error message internally
1022 you can recover via C<YAML::Tiny-E<gt>errstr>. Although in B<some>
1023 cases a failed C<read> will also set the operating system error
1024 variable C<$!>, not all errors do and you should not rely on using
1025 the C<$!> variable.
1026
1027 =head2 read_string $string;
1028
1029 The C<read_string> method takes as argument the contents of a YAML file
1030 (a YAML document) as a string and returns the C<YAML::Tiny> object for
1031 it.
1032
1033 =head2 write $filename
1034
1035 The C<write> method generates the file content for the properties, and
1036 writes it to disk to the filename specified.
1037
1038 Returns true on success or C<undef> on error.
1039
1040 =head2 write_string
1041
1042 Generates the file content for the object and returns it as a string.
1043
1044 =head2 errstr
1045
1046 When an error occurs, you can retrieve the error message either from the
1047 C<$YAML::Tiny::errstr> variable, or using the C<errstr()> method.
1048
1049 =head1 FUNCTIONS
1050
1051 YAML::Tiny implements a number of functions to add compatibility with
1052 the L<YAML> API. These should be a drop-in replacement, except that
1053 YAML::Tiny will B<not> export functions by default, and so you will need
1054 to explicitly import the functions.
1055
1056 =head2 Dump
1057
1058   my $string = Dump(list-of-Perl-data-structures);
1059
1060 Turn Perl data into YAML. This function works very much like Data::Dumper::Dumper().
1061
1062 It takes a list of Perl data strucures and dumps them into a serialized form.
1063
1064 It returns a string containing the YAML stream.
1065
1066 The structures can be references or plain scalars.
1067
1068 =head2 Load
1069
1070   my @documents = Load(string-containing-a-YAML-stream);
1071
1072 Turn YAML into Perl data. This is the opposite of Dump.
1073
1074 Just like L<Storable>'s thaw() function or the eval() function in relation
1075 to L<Data::Dumper>.
1076
1077 It parses a string containing a valid YAML stream into a list of Perl data
1078 structures.
1079
1080 =head2 freeze() and thaw()
1081
1082 Aliases to Dump() and Load() for L<Storable> fans. This will also allow
1083 YAML::Tiny to be plugged directly into modules like POE.pm, that use the
1084 freeze/thaw API for internal serialization.
1085
1086 =head2 DumpFile(filepath, list)
1087
1088 Writes the YAML stream to a file instead of just returning a string.
1089
1090 =head2 LoadFile(filepath)
1091
1092 Reads the YAML stream from a file instead of a string.
1093
1094 =head1 SUPPORT
1095
1096 Bugs should be reported via the CPAN bug tracker at
1097
1098 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=YAML-Tiny>
1099
1100 =begin html
1101
1102 For other issues, or commercial enhancement or support, please contact
1103 <a href="http://ali.as/">Adam Kennedy</a> directly.
1104
1105 =end html
1106
1107 =head1 AUTHOR
1108
1109 Adam Kennedy E<lt>adamk@cpan.orgE<gt>
1110
1111 =head1 SEE ALSO
1112
1113 L<YAML>, L<YAML::Syck>, L<Config::Tiny>, L<CSS::Tiny>,
1114 L<http://use.perl.org/~Alias/journal/29427>, L<http://ali.as/>
1115
1116 =head1 COPYRIGHT
1117
1118 Copyright 2006 - 2009 Adam Kennedy.
1119
1120 This program is free software; you can redistribute
1121 it and/or modify it under the same terms as Perl itself.
1122
1123 The full text of the license can be found in the
1124 LICENSE file included with this module.
1125
1126 =cut