summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl0/lib/YAML/Tiny.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlperl0/lib/YAML/Tiny.pm')
-rwxr-xr-xMaster/tlpkg/tlperl0/lib/YAML/Tiny.pm1132
1 files changed, 1132 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl0/lib/YAML/Tiny.pm b/Master/tlpkg/tlperl0/lib/YAML/Tiny.pm
new file mode 100755
index 00000000000..a3f36c67687
--- /dev/null
+++ b/Master/tlpkg/tlperl0/lib/YAML/Tiny.pm
@@ -0,0 +1,1132 @@
+package YAML::Tiny;
+
+use strict;
+use Carp 'croak';
+
+# UTF Support?
+sub HAVE_UTF8 () { $] >= 5.007003 }
+BEGIN {
+ if ( HAVE_UTF8 ) {
+ # The string eval helps hide this from Test::MinimumVersion
+ eval "require utf8;";
+ die "Failed to load UTF-8 support" if $@;
+ }
+
+ # Class structure
+ require 5.004;
+ require Exporter;
+ $YAML::Tiny::VERSION = '1.41';
+ @YAML::Tiny::ISA = qw{ Exporter };
+ @YAML::Tiny::EXPORT = qw{ Load Dump };
+ @YAML::Tiny::EXPORT_OK = qw{ LoadFile DumpFile freeze thaw };
+
+ # Error storage
+ $YAML::Tiny::errstr = '';
+}
+
+# The character class of all characters we need to escape
+# NOTE: Inlined, since it's only used once
+# my $RE_ESCAPE = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f\"\n]';
+
+# Printed form of the unprintable characters in the lowest range
+# of ASCII characters, listed by ASCII ordinal position.
+my @UNPRINTABLE = qw(
+ z x01 x02 x03 x04 x05 x06 a
+ x08 t n v f r x0e x0f
+ x10 x11 x12 x13 x14 x15 x16 x17
+ x18 x19 x1a e x1c x1d x1e x1f
+);
+
+# Printable characters for escapes
+my %UNESCAPES = (
+ z => "\x00", a => "\x07", t => "\x09",
+ n => "\x0a", v => "\x0b", f => "\x0c",
+ r => "\x0d", e => "\x1b", '\\' => '\\',
+);
+
+# Special magic boolean words
+my %QUOTE = map { $_ => 1 } qw{
+ null Null NULL
+ y Y yes Yes YES n N no No NO
+ true True TRUE false False FALSE
+ on On ON off Off OFF
+};
+
+
+
+
+
+#####################################################################
+# Implementation
+
+# Create an empty YAML::Tiny object
+sub new {
+ my $class = shift;
+ bless [ @_ ], $class;
+}
+
+# Create an object from a file
+sub read {
+ my $class = ref $_[0] ? ref shift : shift;
+
+ # Check the file
+ my $file = shift or return $class->_error( 'You did not specify a file name' );
+ return $class->_error( "File '$file' does not exist" ) unless -e $file;
+ return $class->_error( "'$file' is a directory, not a file" ) unless -f _;
+ return $class->_error( "Insufficient permissions to read '$file'" ) unless -r _;
+
+ # Slurp in the file
+ local $/ = undef;
+ local *CFG;
+ unless ( open(CFG, $file) ) {
+ return $class->_error("Failed to open file '$file': $!");
+ }
+ my $contents = <CFG>;
+ unless ( close(CFG) ) {
+ return $class->_error("Failed to close file '$file': $!");
+ }
+
+ $class->read_string( $contents );
+}
+
+# Create an object from a string
+sub read_string {
+ my $class = ref $_[0] ? ref shift : shift;
+ my $self = bless [], $class;
+ my $string = $_[0];
+ unless ( defined $string ) {
+ return $self->_error("Did not provide a string to load");
+ }
+
+ # Byte order marks
+ # NOTE: Keeping this here to educate maintainers
+ # my %BOM = (
+ # "\357\273\277" => 'UTF-8',
+ # "\376\377" => 'UTF-16BE',
+ # "\377\376" => 'UTF-16LE',
+ # "\377\376\0\0" => 'UTF-32LE'
+ # "\0\0\376\377" => 'UTF-32BE',
+ # );
+ if ( $string =~ /^(?:\376\377|\377\376|\377\376\0\0|\0\0\376\377)/ ) {
+ return $self->_error("Stream has a non UTF-8 BOM");
+ } else {
+ # Strip UTF-8 bom if found, we'll just ignore it
+ $string =~ s/^\357\273\277//;
+ }
+
+ # Try to decode as utf8
+ utf8::decode($string) if HAVE_UTF8;
+
+ # Check for some special cases
+ return $self unless length $string;
+ unless ( $string =~ /[\012\015]+\z/ ) {
+ return $self->_error("Stream does not end with newline character");
+ }
+
+ # Split the file into lines
+ my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
+ split /(?:\015{1,2}\012|\015|\012)/, $string;
+
+ # Strip the initial YAML header
+ @lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;
+
+ # A nibbling parser
+ while ( @lines ) {
+ # Do we have a document header?
+ if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
+ # Handle scalar documents
+ shift @lines;
+ if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
+ push @$self, $self->_read_scalar( "$1", [ undef ], \@lines );
+ next;
+ }
+ }
+
+ if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
+ # A naked document
+ push @$self, undef;
+ while ( @lines and $lines[0] !~ /^---/ ) {
+ shift @lines;
+ }
+
+ } elsif ( $lines[0] =~ /^\s*\-/ ) {
+ # An array at the root
+ my $document = [ ];
+ push @$self, $document;
+ $self->_read_array( $document, [ 0 ], \@lines );
+
+ } elsif ( $lines[0] =~ /^(\s*)\S/ ) {
+ # A hash at the root
+ my $document = { };
+ push @$self, $document;
+ $self->_read_hash( $document, [ length($1) ], \@lines );
+
+ } else {
+ croak("YAML::Tiny failed to classify the line '$lines[0]'");
+ }
+ }
+
+ $self;
+}
+
+# Deparse a scalar string to the actual scalar
+sub _read_scalar {
+ my ($self, $string, $indent, $lines) = @_;
+
+ # Trim trailing whitespace
+ $string =~ s/\s*\z//;
+
+ # Explitic null/undef
+ return undef if $string eq '~';
+
+ # Single quote
+ if ( $string =~ /^\'(.*?)\'\z/ ) {
+ return '' unless defined $1;
+ $string = $1;
+ $string =~ s/\'\'/\'/g;
+ return $string;
+ }
+
+ # Double quote.
+ # The commented out form is simpler, but overloaded the Perl regex
+ # engine due to recursion and backtracking problems on strings
+ # larger than 32,000ish characters. Keep it for reference purposes.
+ # if ( $string =~ /^\"((?:\\.|[^\"])*)\"\z/ ) {
+ if ( $string =~ /^\"([^\\"]*(?:\\.[^\\"]*)*)\"\z/ ) {
+ # Reusing the variable is a little ugly,
+ # but avoids a new variable and a string copy.
+ $string = $1;
+ $string =~ s/\\"/"/g;
+ $string =~ s/\\([never\\fartz]|x([0-9a-fA-F]{2}))/(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}/gex;
+ return $string;
+ }
+
+ # Special cases
+ if ( $string =~ /^[\'\"!&]/ ) {
+ croak("YAML::Tiny does not support a feature in line '$lines->[0]'");
+ }
+ return {} if $string eq '{}';
+ return [] if $string eq '[]';
+
+ # Regular unquoted string
+ return $string unless $string =~ /^[>|]/;
+
+ # Error
+ croak("YAML::Tiny failed to find multi-line scalar content") unless @$lines;
+
+ # Check the indent depth
+ $lines->[0] =~ /^(\s*)/;
+ $indent->[-1] = length("$1");
+ if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
+ croak("YAML::Tiny found bad indenting in line '$lines->[0]'");
+ }
+
+ # Pull the lines
+ my @multiline = ();
+ while ( @$lines ) {
+ $lines->[0] =~ /^(\s*)/;
+ last unless length($1) >= $indent->[-1];
+ push @multiline, substr(shift(@$lines), length($1));
+ }
+
+ my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
+ my $t = (substr($string, 1, 1) eq '-') ? '' : "\n";
+ return join( $j, @multiline ) . $t;
+}
+
+# Parse an array
+sub _read_array {
+ my ($self, $array, $indent, $lines) = @_;
+
+ while ( @$lines ) {
+ # Check for a new document
+ if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
+ while ( @$lines and $lines->[0] !~ /^---/ ) {
+ shift @$lines;
+ }
+ return 1;
+ }
+
+ # Check the indent level
+ $lines->[0] =~ /^(\s*)/;
+ if ( length($1) < $indent->[-1] ) {
+ return 1;
+ } elsif ( length($1) > $indent->[-1] ) {
+ croak("YAML::Tiny found bad indenting in line '$lines->[0]'");
+ }
+
+ if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
+ # Inline nested hash
+ my $indent2 = length("$1");
+ $lines->[0] =~ s/-/ /;
+ push @$array, { };
+ $self->_read_hash( $array->[-1], [ @$indent, $indent2 ], $lines );
+
+ } elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
+ # Array entry with a value
+ shift @$lines;
+ push @$array, $self->_read_scalar( "$2", [ @$indent, undef ], $lines );
+
+ } elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
+ shift @$lines;
+ unless ( @$lines ) {
+ push @$array, undef;
+ return 1;
+ }
+ if ( $lines->[0] =~ /^(\s*)\-/ ) {
+ my $indent2 = length("$1");
+ if ( $indent->[-1] == $indent2 ) {
+ # Null array entry
+ push @$array, undef;
+ } else {
+ # Naked indenter
+ push @$array, [ ];
+ $self->_read_array( $array->[-1], [ @$indent, $indent2 ], $lines );
+ }
+
+ } elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
+ push @$array, { };
+ $self->_read_hash( $array->[-1], [ @$indent, length("$1") ], $lines );
+
+ } else {
+ croak("YAML::Tiny failed to classify line '$lines->[0]'");
+ }
+
+ } elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
+ # This is probably a structure like the following...
+ # ---
+ # foo:
+ # - list
+ # bar: value
+ #
+ # ... so lets return and let the hash parser handle it
+ return 1;
+
+ } else {
+ croak("YAML::Tiny failed to classify line '$lines->[0]'");
+ }
+ }
+
+ return 1;
+}
+
+# Parse an array
+sub _read_hash {
+ my ($self, $hash, $indent, $lines) = @_;
+
+ while ( @$lines ) {
+ # Check for a new document
+ if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
+ while ( @$lines and $lines->[0] !~ /^---/ ) {
+ shift @$lines;
+ }
+ return 1;
+ }
+
+ # Check the indent level
+ $lines->[0] =~ /^(\s*)/;
+ if ( length($1) < $indent->[-1] ) {
+ return 1;
+ } elsif ( length($1) > $indent->[-1] ) {
+ croak("YAML::Tiny found bad indenting in line '$lines->[0]'");
+ }
+
+ # Get the key
+ unless ( $lines->[0] =~ s/^\s*([^\'\" ][^\n]*?)\s*:(\s+|$)// ) {
+ if ( $lines->[0] =~ /^\s*[?\'\"]/ ) {
+ croak("YAML::Tiny does not support a feature in line '$lines->[0]'");
+ }
+ croak("YAML::Tiny failed to classify line '$lines->[0]'");
+ }
+ my $key = $1;
+
+ # Do we have a value?
+ if ( length $lines->[0] ) {
+ # Yes
+ $hash->{$key} = $self->_read_scalar( shift(@$lines), [ @$indent, undef ], $lines );
+ } else {
+ # An indent
+ shift @$lines;
+ unless ( @$lines ) {
+ $hash->{$key} = undef;
+ return 1;
+ }
+ if ( $lines->[0] =~ /^(\s*)-/ ) {
+ $hash->{$key} = [];
+ $self->_read_array( $hash->{$key}, [ @$indent, length($1) ], $lines );
+ } elsif ( $lines->[0] =~ /^(\s*)./ ) {
+ my $indent2 = length("$1");
+ if ( $indent->[-1] >= $indent2 ) {
+ # Null hash entry
+ $hash->{$key} = undef;
+ } else {
+ $hash->{$key} = {};
+ $self->_read_hash( $hash->{$key}, [ @$indent, length($1) ], $lines );
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+# Save an object to a file
+sub write {
+ my $self = shift;
+ my $file = shift or return $self->_error('No file name provided');
+
+ # Write it to the file
+ open( CFG, '>' . $file ) or return $self->_error(
+ "Failed to open file '$file' for writing: $!"
+ );
+ print CFG $self->write_string;
+ close CFG;
+
+ return 1;
+}
+
+# Save an object to a string
+sub write_string {
+ my $self = shift;
+ return '' unless @$self;
+
+ # Iterate over the documents
+ my $indent = 0;
+ my @lines = ();
+ foreach my $cursor ( @$self ) {
+ push @lines, '---';
+
+ # An empty document
+ if ( ! defined $cursor ) {
+ # Do nothing
+
+ # A scalar document
+ } elsif ( ! ref $cursor ) {
+ $lines[-1] .= ' ' . $self->_write_scalar( $cursor, $indent );
+
+ # A list at the root
+ } elsif ( ref $cursor eq 'ARRAY' ) {
+ unless ( @$cursor ) {
+ $lines[-1] .= ' []';
+ next;
+ }
+ push @lines, $self->_write_array( $cursor, $indent, {} );
+
+ # A hash at the root
+ } elsif ( ref $cursor eq 'HASH' ) {
+ unless ( %$cursor ) {
+ $lines[-1] .= ' {}';
+ next;
+ }
+ push @lines, $self->_write_hash( $cursor, $indent, {} );
+
+ } else {
+ croak("Cannot serialize " . ref($cursor));
+ }
+ }
+
+ join '', map { "$_\n" } @lines;
+}
+
+sub _write_scalar {
+ my $string = $_[1];
+ return '~' unless defined $string;
+ return "''" unless length $string;
+ if ( $string =~ /[\x00-\x08\x0b-\x0d\x0e-\x1f\"\'\n]/ ) {
+ $string =~ s/\\/\\\\/g;
+ $string =~ s/"/\\"/g;
+ $string =~ s/\n/\\n/g;
+ $string =~ s/([\x00-\x1f])/\\$UNPRINTABLE[ord($1)]/g;
+ return qq|"$string"|;
+ }
+ if ( $string =~ /(?:^\W|\s)/ or $QUOTE{$string} ) {
+ return "'$string'";
+ }
+ return $string;
+}
+
+sub _write_array {
+ my ($self, $array, $indent, $seen) = @_;
+ if ( $seen->{refaddr($array)}++ ) {
+ die "YAML::Tiny does not support circular references";
+ }
+ my @lines = ();
+ foreach my $el ( @$array ) {
+ my $line = (' ' x $indent) . '-';
+ my $type = ref $el;
+ if ( ! $type ) {
+ $line .= ' ' . $self->_write_scalar( $el, $indent + 1 );
+ push @lines, $line;
+
+ } elsif ( $type eq 'ARRAY' ) {
+ if ( @$el ) {
+ push @lines, $line;
+ push @lines, $self->_write_array( $el, $indent + 1, $seen );
+ } else {
+ $line .= ' []';
+ push @lines, $line;
+ }
+
+ } elsif ( $type eq 'HASH' ) {
+ if ( keys %$el ) {
+ push @lines, $line;
+ push @lines, $self->_write_hash( $el, $indent + 1, $seen );
+ } else {
+ $line .= ' {}';
+ push @lines, $line;
+ }
+
+ } else {
+ die "YAML::Tiny does not support $type references";
+ }
+ }
+
+ @lines;
+}
+
+sub _write_hash {
+ my ($self, $hash, $indent, $seen) = @_;
+ if ( $seen->{refaddr($hash)}++ ) {
+ die "YAML::Tiny does not support circular references";
+ }
+ my @lines = ();
+ foreach my $name ( sort keys %$hash ) {
+ my $el = $hash->{$name};
+ my $line = (' ' x $indent) . "$name:";
+ my $type = ref $el;
+ if ( ! $type ) {
+ $line .= ' ' . $self->_write_scalar( $el, $indent + 1 );
+ push @lines, $line;
+
+ } elsif ( $type eq 'ARRAY' ) {
+ if ( @$el ) {
+ push @lines, $line;
+ push @lines, $self->_write_array( $el, $indent + 1, $seen );
+ } else {
+ $line .= ' []';
+ push @lines, $line;
+ }
+
+ } elsif ( $type eq 'HASH' ) {
+ if ( keys %$el ) {
+ push @lines, $line;
+ push @lines, $self->_write_hash( $el, $indent + 1, $seen );
+ } else {
+ $line .= ' {}';
+ push @lines, $line;
+ }
+
+ } else {
+ die "YAML::Tiny does not support $type references";
+ }
+ }
+
+ @lines;
+}
+
+# Set error
+sub _error {
+ $YAML::Tiny::errstr = $_[1];
+ undef;
+}
+
+# Retrieve error
+sub errstr {
+ $YAML::Tiny::errstr;
+}
+
+
+
+
+
+#####################################################################
+# YAML Compatibility
+
+sub Dump {
+ YAML::Tiny->new(@_)->write_string;
+}
+
+sub Load {
+ my $self = YAML::Tiny->read_string(@_);
+ unless ( $self ) {
+ croak("Failed to load YAML document from string");
+ }
+ if ( wantarray ) {
+ return @$self;
+ } else {
+ # To match YAML.pm, return the last document
+ return $self->[-1];
+ }
+}
+
+BEGIN {
+ *freeze = *Dump;
+ *thaw = *Load;
+}
+
+sub DumpFile {
+ my $file = shift;
+ YAML::Tiny->new(@_)->write($file);
+}
+
+sub LoadFile {
+ my $self = YAML::Tiny->read($_[0]);
+ unless ( $self ) {
+ croak("Failed to load YAML document from '" . ($_[0] || '') . "'");
+ }
+ if ( wantarray ) {
+ return @$self;
+ } else {
+ # Return only the last document to match YAML.pm,
+ return $self->[-1];
+ }
+}
+
+
+
+
+
+#####################################################################
+# Use Scalar::Util if possible, otherwise emulate it
+
+BEGIN {
+ eval {
+ require Scalar::Util;
+ };
+ if ( $@ ) {
+ # Failed to load Scalar::Util
+ eval <<'END_PERL';
+sub refaddr {
+ my $pkg = ref($_[0]) or return undef;
+ if (!!UNIVERSAL::can($_[0], 'can')) {
+ bless $_[0], 'Scalar::Util::Fake';
+ } else {
+ $pkg = undef;
+ }
+ "$_[0]" =~ /0x(\w+)/;
+ my $i = do { local $^W; hex $1 };
+ bless $_[0], $pkg if defined $pkg;
+ $i;
+}
+END_PERL
+ } else {
+ Scalar::Util->import('refaddr');
+ }
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+YAML::Tiny - Read/Write YAML files with as little code as possible
+
+=head1 PREAMBLE
+
+The YAML specification is huge. Really, B<really> huge. It contains all the
+functionality of XML, except with flexibility and choice, which makes it
+easier to read, but with a formal specification that is more complex than
+XML.
+
+The original pure-Perl implementation L<YAML> costs just over 4 megabytes of
+memory to load. Just like with Windows .ini files (3 meg to load) and CSS
+(3.5 meg to load) the situation is just asking for a B<YAML::Tiny> module, an
+incomplete but correct and usable subset of the functionality, in as little
+code as possible.
+
+Like the other C<::Tiny> modules, YAML::Tiny will have no non-core
+dependencies, not require a compiler, and be back-compatible to at least
+perl 5.005_03, and ideally 5.004.
+
+=head1 SYNOPSIS
+
+ #############################################
+ # In your file
+
+ ---
+ rootproperty: blah
+ section:
+ one: two
+ three: four
+ Foo: Bar
+ empty: ~
+
+
+
+ #############################################
+ # In your program
+
+ use YAML::Tiny;
+
+ # Create a YAML file
+ my $yaml = YAML::Tiny->new;
+
+ # Open the config
+ $yaml = YAML::Tiny->read( 'file.yml' );
+
+ # Reading properties
+ my $root = $yaml->[0]->{rootproperty};
+ my $one = $yaml->[0]->{section}->{one};
+ my $Foo = $yaml->[0]->{section}->{Foo};
+
+ # Changing data
+ $yaml->[0]->{newsection} = { this => 'that' }; # Add a section
+ $yaml->[0]->{section}->{Foo} = 'Not Bar!'; # Change a value
+ delete $yaml->[0]->{section}; # Delete a value or section
+
+ # Add an entire document
+ $yaml->[1] = [ 'foo', 'bar', 'baz' ];
+
+ # Save the file
+ $yaml->write( 'file.conf' );
+
+=head1 DESCRIPTION
+
+B<YAML::Tiny> is a perl class for reading and writing YAML-style files,
+written with as little code as possible, reducing load time and memory
+overhead.
+
+Most of the time it is accepted that Perl applications use a lot
+of memory and modules. The B<::Tiny> family of modules is specifically
+intended to provide an ultralight and zero-dependency alternative to
+many more-thorough standard modules.
+
+This module is primarily for reading human-written files (like simple
+config files) and generating very simple human-readable files. Note that
+I said B<human-readable> and not B<geek-readable>. The sort of files that
+your average manager or secretary should be able to look at and make
+sense of.
+
+L<YAML::Tiny> does not generate comments, it won't necesarily preserve the
+order of your hashes, and it will normalise if reading in and writing out
+again.
+
+It only supports a very basic subset of the full YAML specification.
+
+Usage is targetted at files like Perl's META.yml, for which a small and
+easily-embeddable module is extremely attractive.
+
+Features will only be added if they are human readable, and can be written
+in a few lines of code. Please don't be offended if your request is
+refused. Someone has to draw the line, and for YAML::Tiny that someone is me.
+
+If you need something with more power move up to L<YAML> (4 megabytes of
+memory overhead) or L<YAML::Syck> (275k, but requires libsyck and a C
+compiler).
+
+To restate, L<YAML::Tiny> does B<not> preserve your comments, whitespace, or
+the order of your YAML data. But it should round-trip from Perl structure
+to file and back again just fine.
+
+=head1 YAML TINY SPECIFICATION
+
+This section of the documentation provides a specification for "YAML Tiny",
+a subset of the YAML specification.
+
+It is based on and described comparatively to the YAML 1.1 Working Draft
+2004-12-28 specification, located at L<http://yaml.org/spec/current.html>.
+
+Terminology and chapter numbers are based on that specification.
+
+=head2 1. Introduction and Goals
+
+The purpose of the YAML Tiny specification is to describe a useful subset of
+the YAML specification that can be used for typical document-oriented
+uses such as configuration files and simple data structure dumps.
+
+Many specification elements that add flexibility or extensibility are
+intentionally removed, as is support for complex datastructures, class
+and object-orientation.
+
+In general, YAML Tiny targets only those data structures available in
+JSON, with the additional limitation that only simple keys are supported.
+
+As a result, all possible YAML Tiny documents should be able to be
+transformed into an equivalent JSON document, although the reverse is
+not necesarily true (but will be true in simple cases).
+
+As a result of these simplifications the YAML Tiny specification should
+be implementable in a relatively small amount of code in any language
+that supports Perl Compatible Regular Expressions (PCRE).
+
+=head2 2. Introduction
+
+YAML Tiny supports three data structures. These are scalars (in a variety
+of forms), block-form sequences and block-form mappings. Flow-style
+sequences and mappings are not supported, with some minor exceptions
+detailed later.
+
+The use of three dashes "---" to indicate the start of a new document is
+supported, and multiple documents per file/stream is allowed.
+
+Both line and inline comments are supported.
+
+Scalars are supported via the plain style, single quote and double quote,
+as well as literal-style and folded-style multi-line scalars.
+
+The use of tags is not supported.
+
+The use of anchors and aliases is not supported.
+
+The use of directives is supported only for the %YAML directive.
+
+=head2 3. Processing YAML Tiny Information
+
+B<Processes>
+
+The YAML specification dictates three-phase serialization and three-phase
+deserialization.
+
+The YAML Tiny specification does not mandate any particular methodology
+or mechanism for parsing.
+
+Any compliant parser is only required to parse a single document at a
+time. The ability to support streaming documents is optional and most
+likely non-typical.
+
+Because anchors and aliases are not supported, the resulting representation
+graph is thus directed but (unlike the main YAML specification) B<acyclic>.
+
+Circular references/pointers are not possible, and any YAML Tiny serializer
+detecting a circulars should error with an appropriate message.
+
+B<Presentation Stream>
+
+YAML Tiny is notionally unicode, but support for unicode is required if the
+underlying language or system being used to implement a parser does not
+support Unicode. If unicode is encountered in this case an error should be
+returned.
+
+B<Loading Failure Points>
+
+YAML Tiny parsers and emitters are not expected to recover from adapt to
+errors. The specific error modality of any implementation is not dictated
+(return codes, exceptions, etc) but is expected to be consistant.
+
+=head2 4. Syntax
+
+B<Character Set>
+
+YAML Tiny streams are implemented primarily using the ASCII character set,
+although the use of Unicode inside strings is allowed if support by the
+implementation.
+
+Specific YAML Tiny encoded document types aiming for maximum compatibility
+should restrict themselves to ASCII.
+
+The escaping and unescaping of the 8-bit YAML escapes is required.
+
+The escaping and unescaping of 16-bit and 32-bit YAML escapes is not
+required.
+
+B<Indicator Characters>
+
+Support for the "~" null/undefined indicator is required.
+
+Implementations may represent this as appropriate for the underlying
+language.
+
+Support for the "-" block sequence indicator is required.
+
+Support for the "?" mapping key indicator is B<not> required.
+
+Support for the ":" mapping value indicator is required.
+
+Support for the "," flow collection indicator is B<not> required.
+
+Support for the "[" flow sequence indicator is B<not> required, with
+one exception (detailed below).
+
+Support for the "]" flow sequence indicator is B<not> required, with
+one exception (detailed below).
+
+Support for the "{" flow mapping indicator is B<not> required, with
+one exception (detailed below).
+
+Support for the "}" flow mapping indicator is B<not> required, with
+one exception (detailed below).
+
+Support for the "#" comment indicator is required.
+
+Support for the "&" anchor indicator is B<not> required.
+
+Support for the "*" alias indicator is B<not> required.
+
+Support for the "!" tag indicator is B<not> required.
+
+Support for the "|" literal block indicator is required.
+
+Support for the ">" folded block indicator is required.
+
+Support for the "'" single quote indicator is required.
+
+Support for the """ double quote indicator is required.
+
+Support for the "%" directive indicator is required, but only
+for the special case of a %YAML version directive before the
+"---" document header, or on the same line as the document header.
+
+For example:
+
+ %YAML 1.1
+ ---
+ - A sequence with a single element
+
+Special Exception:
+
+To provide the ability to support empty sequences
+and mappings, support for the constructs [] (empty sequence) and {}
+(empty mapping) are required.
+
+For example,
+
+ %YAML 1.1
+ # A document consisting of only an empty mapping
+ --- {}
+ # A document consisting of only an empty sequence
+ --- []
+ # A document consisting of an empty mapping within a sequence
+ - foo
+ - {}
+ - bar
+
+B<Syntax Primitives>
+
+Other than the empty sequence and mapping cases described above, YAML Tiny
+supports only the indentation-based block-style group of contexts.
+
+All five scalar contexts are supported.
+
+Indentation spaces work as per the YAML specification in all cases.
+
+Comments work as per the YAML specification in all simple cases.
+Support for indented multi-line comments is B<not> required.
+
+Seperation spaces work as per the YAML specification in all cases.
+
+B<YAML Tiny Character Stream>
+
+The only directive supported by the YAML Tiny specification is the
+%YAML language/version identifier. Although detected, this directive
+will have no control over the parsing itself.
+
+The parser must recognise both the YAML 1.0 and YAML 1.1+ formatting
+of this directive (as well as the commented form, although no explicit
+code should be needed to deal with this case, being a comment anyway)
+
+That is, all of the following should be supported.
+
+ --- #YAML:1.0
+ - foo
+
+ %YAML:1.0
+ ---
+ - foo
+
+ % YAML 1.1
+ ---
+ - foo
+
+Support for the %TAG directive is B<not> required.
+
+Support for additional directives is B<not> required.
+
+Support for the document boundary marker "---" is required.
+
+Support for the document boundary market "..." is B<not> required.
+
+If necesary, a document boundary should simply by indicated with a
+"---" marker, with not preceding "..." marker.
+
+Support for empty streams (containing no documents) is required.
+
+Support for implicit document starts is required.
+
+That is, the following must be equivalent.
+
+ # Full form
+ %YAML 1.1
+ ---
+ foo: bar
+
+ # Implicit form
+ foo: bar
+
+B<Nodes>
+
+Support for nodes optional anchor and tag properties are B<not> required.
+
+Support for node anchors is B<not> required.
+
+Supprot for node tags is B<not> required.
+
+Support for alias nodes is B<not> required.
+
+Support for flow nodes is B<not> required.
+
+Support for block nodes is required.
+
+B<Scalar Styles>
+
+Support for all five scalar styles are required as per the YAML
+specification, although support for quoted scalars spanning more
+than one line is B<not> required.
+
+Support for the chomping indicators on multi-line scalar styles
+is required.
+
+B<Collection Styles>
+
+Support for block-style sequences is required.
+
+Support for flow-style sequences is B<not> required.
+
+Support for block-style mappings is required.
+
+Support for flow-style mappings is B<not> required.
+
+Both sequences and mappings should be able to be arbitrarily
+nested.
+
+Support for plain-style mapping keys is required.
+
+Support for quoted keys in mappings is B<not> required.
+
+Support for "?"-indicated explicit keys is B<not> required.
+
+Here endeth the specification.
+
+=head2 Additional Perl-Specific Notes
+
+For some Perl applications, it's important to know if you really have a
+number and not a string.
+
+That is, in some contexts is important that 3 the number is distinctive
+from "3" the string.
+
+Because even Perl itself is not trivially able to understand the difference
+(certainly without XS-based modules) Perl implementations of the YAML Tiny
+specification are not required to retain the distinctiveness of 3 vs "3".
+
+=head1 METHODS
+
+=head2 new
+
+The constructor C<new> creates and returns an empty C<YAML::Tiny> object.
+
+=head2 read $filename
+
+The C<read> constructor reads a YAML file, and returns a new
+C<YAML::Tiny> object containing the contents of the file.
+
+Returns the object on success, or C<undef> on error.
+
+When C<read> fails, C<YAML::Tiny> sets an error message internally
+you can recover via C<YAML::Tiny-E<gt>errstr>. Although in B<some>
+cases a failed C<read> will also set the operating system error
+variable C<$!>, not all errors do and you should not rely on using
+the C<$!> variable.
+
+=head2 read_string $string;
+
+The C<read_string> method takes as argument the contents of a YAML file
+(a YAML document) as a string and returns the C<YAML::Tiny> object for
+it.
+
+=head2 write $filename
+
+The C<write> method generates the file content for the properties, and
+writes it to disk to the filename specified.
+
+Returns true on success or C<undef> on error.
+
+=head2 write_string
+
+Generates the file content for the object and returns it as a string.
+
+=head2 errstr
+
+When an error occurs, you can retrieve the error message either from the
+C<$YAML::Tiny::errstr> variable, or using the C<errstr()> method.
+
+=head1 FUNCTIONS
+
+YAML::Tiny implements a number of functions to add compatibility with
+the L<YAML> API. These should be a drop-in replacement, except that
+YAML::Tiny will B<not> export functions by default, and so you will need
+to explicitly import the functions.
+
+=head2 Dump
+
+ my $string = Dump(list-of-Perl-data-structures);
+
+Turn Perl data into YAML. This function works very much like Data::Dumper::Dumper().
+
+It takes a list of Perl data strucures and dumps them into a serialized form.
+
+It returns a string containing the YAML stream.
+
+The structures can be references or plain scalars.
+
+=head2 Load
+
+ my @documents = Load(string-containing-a-YAML-stream);
+
+Turn YAML into Perl data. This is the opposite of Dump.
+
+Just like L<Storable>'s thaw() function or the eval() function in relation
+to L<Data::Dumper>.
+
+It parses a string containing a valid YAML stream into a list of Perl data
+structures.
+
+=head2 freeze() and thaw()
+
+Aliases to Dump() and Load() for L<Storable> fans. This will also allow
+YAML::Tiny to be plugged directly into modules like POE.pm, that use the
+freeze/thaw API for internal serialization.
+
+=head2 DumpFile(filepath, list)
+
+Writes the YAML stream to a file instead of just returning a string.
+
+=head2 LoadFile(filepath)
+
+Reads the YAML stream from a file instead of a string.
+
+=head1 SUPPORT
+
+Bugs should be reported via the CPAN bug tracker at
+
+L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=YAML-Tiny>
+
+=begin html
+
+For other issues, or commercial enhancement or support, please contact
+<a href="http://ali.as/">Adam Kennedy</a> directly.
+
+=end html
+
+=head1 AUTHOR
+
+Adam Kennedy E<lt>adamk@cpan.orgE<gt>
+
+=head1 SEE ALSO
+
+L<YAML>, L<YAML::Syck>, L<Config::Tiny>, L<CSS::Tiny>,
+L<http://use.perl.org/~Alias/journal/29427>, L<http://ali.as/>
+
+=head1 COPYRIGHT
+
+Copyright 2006 - 2009 Adam Kennedy.
+
+This program is free software; you can redistribute
+it and/or modify it under the same terms as Perl itself.
+
+The full text of the license can be found in the
+LICENSE file included with this module.
+
+=cut