Subversion Repositories camp_sysinfo_client_3

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
90 rodolico 1
use 5.008001; # sane UTF-8 support
2
use strict;
3
use warnings;
4
package YAML::Tiny; # git description: v1.72-7-g8682f63
5
# XXX-INGY is 5.8.1 too old/broken for utf8?
6
# XXX-XDG Lancaster consensus was that it was sufficient until
7
# proven otherwise
8
 
9
our $VERSION = '1.73';
10
 
11
#####################################################################
12
# The YAML::Tiny API.
13
#
14
# These are the currently documented API functions/methods and
15
# exports:
16
 
17
use Exporter;
18
our @ISA       = qw{ Exporter  };
19
our @EXPORT    = qw{ Load Dump };
20
our @EXPORT_OK = qw{ LoadFile DumpFile freeze thaw };
21
 
22
###
23
# Functional/Export API:
24
 
25
sub Dump {
26
    return YAML::Tiny->new(@_)->_dump_string;
27
}
28
 
29
# XXX-INGY Returning last document seems a bad behavior.
30
# XXX-XDG I think first would seem more natural, but I don't know
31
# that it's worth changing now
32
sub Load {
33
    my $self = YAML::Tiny->_load_string(@_);
34
    if ( wantarray ) {
35
        return @$self;
36
    } else {
37
        # To match YAML.pm, return the last document
38
        return $self->[-1];
39
    }
40
}
41
 
42
# XXX-INGY Do we really need freeze and thaw?
43
# XXX-XDG I don't think so.  I'd support deprecating them.
44
BEGIN {
45
    *freeze = \&Dump;
46
    *thaw   = \&Load;
47
}
48
 
49
sub DumpFile {
50
    my $file = shift;
51
    return YAML::Tiny->new(@_)->_dump_file($file);
52
}
53
 
54
sub LoadFile {
55
    my $file = shift;
56
    my $self = YAML::Tiny->_load_file($file);
57
    if ( wantarray ) {
58
        return @$self;
59
    } else {
60
        # Return only the last document to match YAML.pm,
61
        return $self->[-1];
62
    }
63
}
64
 
65
 
66
###
67
# Object Oriented API:
68
 
69
# Create an empty YAML::Tiny object
70
# XXX-INGY Why do we use ARRAY object?
71
# NOTE: I get it now, but I think it's confusing and not needed.
72
# Will change it on a branch later, for review.
73
#
74
# XXX-XDG I don't support changing it yet.  It's a very well-documented
75
# "API" of YAML::Tiny.  I'd support deprecating it, but Adam suggested
76
# we not change it until YAML.pm's own OO API is established so that
77
# users only have one API change to digest, not two
78
sub new {
79
    my $class = shift;
80
    bless [ @_ ], $class;
81
}
82
 
83
# XXX-INGY It probably doesn't matter, and it's probably too late to
84
# change, but 'read/write' are the wrong names. Read and Write
85
# are actions that take data from storage to memory
86
# characters/strings. These take the data to/from storage to native
87
# Perl objects, which the terms dump and load are meant. As long as
88
# this is a legacy quirk to YAML::Tiny it's ok, but I'd prefer not
89
# to add new {read,write}_* methods to this API.
90
 
91
sub read_string {
92
    my $self = shift;
93
    $self->_load_string(@_);
94
}
95
 
96
sub write_string {
97
    my $self = shift;
98
    $self->_dump_string(@_);
99
}
100
 
101
sub read {
102
    my $self = shift;
103
    $self->_load_file(@_);
104
}
105
 
106
sub write {
107
    my $self = shift;
108
    $self->_dump_file(@_);
109
}
110
 
111
 
112
 
113
 
114
#####################################################################
115
# Constants
116
 
117
# Printed form of the unprintable characters in the lowest range
118
# of ASCII characters, listed by ASCII ordinal position.
119
my @UNPRINTABLE = qw(
120
 
121
    b    t    n    v    f    r    x0E  x0F
122
    x10  x11  x12  x13  x14  x15  x16  x17
123
    x18  x19  x1A  e    x1C  x1D  x1E  x1F
124
);
125
 
126
# Printable characters for escapes
127
my %UNESCAPES = (
128
 
129
    a => "\x07", b => "\x08", t    => "\x09",
130
    n => "\x0a", v => "\x0b", f    => "\x0c",
131
    r => "\x0d", e => "\x1b", '\\' => '\\',
132
);
133
 
134
# XXX-INGY
135
# I(ngy) need to decide if these values should be quoted in
136
# YAML::Tiny or not. Probably yes.
137
 
138
# These 3 values have special meaning when unquoted and using the
139
# default YAML schema. They need quotes if they are strings.
140
my %QUOTE = map { $_ => 1 } qw{
141
    null true false
142
};
143
 
144
# The commented out form is simpler, but overloaded the Perl regex
145
# engine due to recursion and backtracking problems on strings
146
# larger than 32,000ish characters. Keep it for reference purposes.
147
# qr/\"((?:\\.|[^\"])*)\"/
148
my $re_capture_double_quoted = qr/\"([^\\"]*(?:\\.[^\\"]*)*)\"/;
149
my $re_capture_single_quoted = qr/\'([^\']*(?:\'\'[^\']*)*)\'/;
150
# unquoted re gets trailing space that needs to be stripped
151
my $re_capture_unquoted_key  = qr/([^:]+(?::+\S(?:[^:]*|.*?(?=:)))*)(?=\s*\:(?:\s+|$))/;
152
my $re_trailing_comment      = qr/(?:\s+\#.*)?/;
153
my $re_key_value_separator   = qr/\s*:(?:\s+(?:\#.*)?|$)/;
154
 
155
 
156
 
157
 
158
 
159
#####################################################################
160
# YAML::Tiny Implementation.
161
#
162
# These are the private methods that do all the work. They may change
163
# at any time.
164
 
165
 
166
###
167
# Loader functions:
168
 
169
# Create an object from a file
170
sub _load_file {
171
    my $class = ref $_[0] ? ref shift : shift;
172
 
173
    # Check the file
174
    my $file = shift or $class->_error( 'You did not specify a file name' );
175
    $class->_error( "File '$file' does not exist" )
176
        unless -e $file;
177
    $class->_error( "'$file' is a directory, not a file" )
178
        unless -f _;
179
    $class->_error( "Insufficient permissions to read '$file'" )
180
        unless -r _;
181
 
182
    # Open unbuffered with strict UTF-8 decoding and no translation layers
183
    open( my $fh, "<:unix:encoding(UTF-8)", $file );
184
    unless ( $fh ) {
185
        $class->_error("Failed to open file '$file': $!");
186
    }
187
 
188
    # flock if available (or warn if not possible for OS-specific reasons)
189
    if ( _can_flock() ) {
190
        flock( $fh, Fcntl::LOCK_SH() )
191
            or warn "Couldn't lock '$file' for reading: $!";
192
    }
193
 
194
    # slurp the contents
195
    my $contents = eval {
196
        use warnings FATAL => 'utf8';
197
        local $/;
198
        <$fh>
199
    };
200
    if ( my $err = $@ ) {
201
        $class->_error("Error reading from file '$file': $err");
202
    }
203
 
204
    # close the file (release the lock)
205
    unless ( close $fh ) {
206
        $class->_error("Failed to close file '$file': $!");
207
    }
208
 
209
    $class->_load_string( $contents );
210
}
211
 
212
# Create an object from a string
213
sub _load_string {
214
    my $class  = ref $_[0] ? ref shift : shift;
215
    my $self   = bless [], $class;
216
    my $string = $_[0];
217
    eval {
218
        unless ( defined $string ) {
219
            die \"Did not provide a string to load";
220
        }
221
 
222
        # Check if Perl has it marked as characters, but it's internally
223
        # inconsistent.  E.g. maybe latin1 got read on a :utf8 layer
224
        if ( utf8::is_utf8($string) && ! utf8::valid($string) ) {
225
            die \<<'...';
226
Read an invalid UTF-8 string (maybe mixed UTF-8 and 8-bit character set).
227
Did you decode with lax ":utf8" instead of strict ":encoding(UTF-8)"?
228
...
229
        }
230
 
231
        # Ensure Unicode character semantics, even for 0x80-0xff
232
        utf8::upgrade($string);
233
 
234
        # Check for and strip any leading UTF-8 BOM
235
        $string =~ s/^\x{FEFF}//;
236
 
237
        # Check for some special cases
238
        return $self unless length $string;
239
 
240
        # Split the file into lines
241
        my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
242
                split /(?:\015{1,2}\012|\015|\012)/, $string;
243
 
244
        # Strip the initial YAML header
245
        @lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;
246
 
247
        # A nibbling parser
248
        my $in_document = 0;
249
        while ( @lines ) {
250
            # Do we have a document header?
251
            if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
252
                # Handle scalar documents
253
                shift @lines;
254
                if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
255
                    push @$self,
256
                        $self->_load_scalar( "$1", [ undef ], \@lines );
257
                    next;
258
                }
259
                $in_document = 1;
260
            }
261
 
262
            if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
263
                # A naked document
264
                push @$self, undef;
265
                while ( @lines and $lines[0] !~ /^---/ ) {
266
                    shift @lines;
267
                }
268
                $in_document = 0;
269
 
270
            # XXX The final '-+$' is to look for -- which ends up being an
271
            # error later.
272
            } elsif ( ! $in_document && @$self ) {
273
                # only the first document can be explicit
274
                die \"YAML::Tiny failed to classify the line '$lines[0]'";
275
            } elsif ( $lines[0] =~ /^\s*\-(?:\s|$|-+$)/ ) {
276
                # An array at the root
277
                my $document = [ ];
278
                push @$self, $document;
279
                $self->_load_array( $document, [ 0 ], \@lines );
280
 
281
            } elsif ( $lines[0] =~ /^(\s*)\S/ ) {
282
                # A hash at the root
283
                my $document = { };
284
                push @$self, $document;
285
                $self->_load_hash( $document, [ length($1) ], \@lines );
286
 
287
            } else {
288
                # Shouldn't get here.  @lines have whitespace-only lines
289
                # stripped, and previous match is a line with any
290
                # non-whitespace.  So this clause should only be reachable via
291
                # a perlbug where \s is not symmetric with \S
292
 
293
                # uncoverable statement
294
                die \"YAML::Tiny failed to classify the line '$lines[0]'";
295
            }
296
        }
297
    };
298
    my $err = $@;
299
    if ( ref $err eq 'SCALAR' ) {
300
        $self->_error(${$err});
301
    } elsif ( $err ) {
302
        $self->_error($err);
303
    }
304
 
305
    return $self;
306
}
307
 
308
sub _unquote_single {
309
    my ($self, $string) = @_;
310
    return '' unless length $string;
311
    $string =~ s/\'\'/\'/g;
312
    return $string;
313
}
314
 
315
sub _unquote_double {
316
    my ($self, $string) = @_;
317
    return '' unless length $string;
318
    $string =~ s/\\"/"/g;
319
    $string =~
320
        s{\\([Nnever\\fartz0b]|x([0-9a-fA-F]{2}))}
321
         {(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}}gex;
322
    return $string;
323
}
324
 
325
# Load a YAML scalar string to the actual Perl scalar
326
sub _load_scalar {
327
    my ($self, $string, $indent, $lines) = @_;
328
 
329
    # Trim trailing whitespace
330
    $string =~ s/\s*\z//;
331
 
332
    # Explitic null/undef
333
    return undef if $string eq '~';
334
 
335
    # Single quote
336
    if ( $string =~ /^$re_capture_single_quoted$re_trailing_comment\z/ ) {
337
        return $self->_unquote_single($1);
338
    }
339
 
340
    # Double quote.
341
    if ( $string =~ /^$re_capture_double_quoted$re_trailing_comment\z/ ) {
342
        return $self->_unquote_double($1);
343
    }
344
 
345
    # Special cases
346
    if ( $string =~ /^[\'\"!&]/ ) {
347
        die \"YAML::Tiny does not support a feature in line '$string'";
348
    }
349
    return {} if $string =~ /^{}(?:\s+\#.*)?\z/;
350
    return [] if $string =~ /^\[\](?:\s+\#.*)?\z/;
351
 
352
    # Regular unquoted string
353
    if ( $string !~ /^[>|]/ ) {
354
        die \"YAML::Tiny found illegal characters in plain scalar: '$string'"
355
            if $string =~ /^(?:-(?:\s|$)|[\@\%\`])/ or
356
                $string =~ /:(?:\s|$)/;
357
        $string =~ s/\s+#.*\z//;
358
        return $string;
359
    }
360
 
361
    # Error
362
    die \"YAML::Tiny failed to find multi-line scalar content" unless @$lines;
363
 
364
    # Check the indent depth
365
    $lines->[0]   =~ /^(\s*)/;
366
    $indent->[-1] = length("$1");
367
    if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
368
        die \"YAML::Tiny found bad indenting in line '$lines->[0]'";
369
    }
370
 
371
    # Pull the lines
372
    my @multiline = ();
373
    while ( @$lines ) {
374
        $lines->[0] =~ /^(\s*)/;
375
        last unless length($1) >= $indent->[-1];
376
        push @multiline, substr(shift(@$lines), $indent->[-1]);
377
    }
378
 
379
    my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
380
    my $t = (substr($string, 1, 1) eq '-') ? ''  : "\n";
381
    return join( $j, @multiline ) . $t;
382
}
383
 
384
# Load an array
385
sub _load_array {
386
    my ($self, $array, $indent, $lines) = @_;
387
 
388
    while ( @$lines ) {
389
        # Check for a new document
390
        if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
391
            while ( @$lines and $lines->[0] !~ /^---/ ) {
392
                shift @$lines;
393
            }
394
            return 1;
395
        }
396
 
397
        # Check the indent level
398
        $lines->[0] =~ /^(\s*)/;
399
        if ( length($1) < $indent->[-1] ) {
400
            return 1;
401
        } elsif ( length($1) > $indent->[-1] ) {
402
            die \"YAML::Tiny found bad indenting in line '$lines->[0]'";
403
        }
404
 
405
        if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
406
            # Inline nested hash
407
            my $indent2 = length("$1");
408
            $lines->[0] =~ s/-/ /;
409
            push @$array, { };
410
            $self->_load_hash( $array->[-1], [ @$indent, $indent2 ], $lines );
411
 
412
        } elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
413
            shift @$lines;
414
            unless ( @$lines ) {
415
                push @$array, undef;
416
                return 1;
417
            }
418
            if ( $lines->[0] =~ /^(\s*)\-/ ) {
419
                my $indent2 = length("$1");
420
                if ( $indent->[-1] == $indent2 ) {
421
                    # Null array entry
422
                    push @$array, undef;
423
                } else {
424
                    # Naked indenter
425
                    push @$array, [ ];
426
                    $self->_load_array(
427
                        $array->[-1], [ @$indent, $indent2 ], $lines
428
                    );
429
                }
430
 
431
            } elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
432
                push @$array, { };
433
                $self->_load_hash(
434
                    $array->[-1], [ @$indent, length("$1") ], $lines
435
                );
436
 
437
            } else {
438
                die \"YAML::Tiny failed to classify line '$lines->[0]'";
439
            }
440
 
441
        } elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
442
            # Array entry with a value
443
            shift @$lines;
444
            push @$array, $self->_load_scalar(
445
                "$2", [ @$indent, undef ], $lines
446
            );
447
 
448
        } elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
449
            # This is probably a structure like the following...
450
            # ---
451
            # foo:
452
            # - list
453
            # bar: value
454
            #
455
            # ... so lets return and let the hash parser handle it
456
            return 1;
457
 
458
        } else {
459
            die \"YAML::Tiny failed to classify line '$lines->[0]'";
460
        }
461
    }
462
 
463
    return 1;
464
}
465
 
466
# Load a hash
467
sub _load_hash {
468
    my ($self, $hash, $indent, $lines) = @_;
469
 
470
    while ( @$lines ) {
471
        # Check for a new document
472
        if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
473
            while ( @$lines and $lines->[0] !~ /^---/ ) {
474
                shift @$lines;
475
            }
476
            return 1;
477
        }
478
 
479
        # Check the indent level
480
        $lines->[0] =~ /^(\s*)/;
481
        if ( length($1) < $indent->[-1] ) {
482
            return 1;
483
        } elsif ( length($1) > $indent->[-1] ) {
484
            die \"YAML::Tiny found bad indenting in line '$lines->[0]'";
485
        }
486
 
487
        # Find the key
488
        my $key;
489
 
490
        # Quoted keys
491
        if ( $lines->[0] =~
492
            s/^\s*$re_capture_single_quoted$re_key_value_separator//
493
        ) {
494
            $key = $self->_unquote_single($1);
495
        }
496
        elsif ( $lines->[0] =~
497
            s/^\s*$re_capture_double_quoted$re_key_value_separator//
498
        ) {
499
            $key = $self->_unquote_double($1);
500
        }
501
        elsif ( $lines->[0] =~
502
            s/^\s*$re_capture_unquoted_key$re_key_value_separator//
503
        ) {
504
            $key = $1;
505
            $key =~ s/\s+$//;
506
        }
507
        elsif ( $lines->[0] =~ /^\s*\?/ ) {
508
            die \"YAML::Tiny does not support a feature in line '$lines->[0]'";
509
        }
510
        else {
511
            die \"YAML::Tiny failed to classify line '$lines->[0]'";
512
        }
513
 
514
        if ( exists $hash->{$key} ) {
515
            warn "YAML::Tiny found a duplicate key '$key' in line '$lines->[0]'";
516
        }
517
 
518
        # Do we have a value?
519
        if ( length $lines->[0] ) {
520
            # Yes
521
            $hash->{$key} = $self->_load_scalar(
522
                shift(@$lines), [ @$indent, undef ], $lines
523
            );
524
        } else {
525
            # An indent
526
            shift @$lines;
527
            unless ( @$lines ) {
528
                $hash->{$key} = undef;
529
                return 1;
530
            }
531
            if ( $lines->[0] =~ /^(\s*)-/ ) {
532
                $hash->{$key} = [];
533
                $self->_load_array(
534
                    $hash->{$key}, [ @$indent, length($1) ], $lines
535
                );
536
            } elsif ( $lines->[0] =~ /^(\s*)./ ) {
537
                my $indent2 = length("$1");
538
                if ( $indent->[-1] >= $indent2 ) {
539
                    # Null hash entry
540
                    $hash->{$key} = undef;
541
                } else {
542
                    $hash->{$key} = {};
543
                    $self->_load_hash(
544
                        $hash->{$key}, [ @$indent, length($1) ], $lines
545
                    );
546
                }
547
            }
548
        }
549
    }
550
 
551
    return 1;
552
}
553
 
554
 
555
###
556
# Dumper functions:
557
 
558
# Save an object to a file
559
sub _dump_file {
560
    my $self = shift;
561
 
562
    require Fcntl;
563
 
564
    # Check the file
565
    my $file = shift or $self->_error( 'You did not specify a file name' );
566
 
567
    my $fh;
568
    # flock if available (or warn if not possible for OS-specific reasons)
569
    if ( _can_flock() ) {
570
        # Open without truncation (truncate comes after lock)
571
        my $flags = Fcntl::O_WRONLY()|Fcntl::O_CREAT();
572
        sysopen( $fh, $file, $flags )
573
            or $self->_error("Failed to open file '$file' for writing: $!");
574
 
575
        # Use no translation and strict UTF-8
576
        binmode( $fh, ":raw:encoding(UTF-8)");
577
 
578
        flock( $fh, Fcntl::LOCK_EX() )
579
            or warn "Couldn't lock '$file' for reading: $!";
580
 
581
        # truncate and spew contents
582
        truncate $fh, 0;
583
        seek $fh, 0, 0;
584
    }
585
    else {
586
        open $fh, ">:unix:encoding(UTF-8)", $file;
587
    }
588
 
589
    # serialize and spew to the handle
590
    print {$fh} $self->_dump_string;
591
 
592
    # close the file (release the lock)
593
    unless ( close $fh ) {
594
        $self->_error("Failed to close file '$file': $!");
595
    }
596
 
597
    return 1;
598
}
599
 
600
# Save an object to a string
601
sub _dump_string {
602
    my $self = shift;
603
    return '' unless ref $self && @$self;
604
 
605
    # Iterate over the documents
606
    my $indent = 0;
607
    my @lines  = ();
608
 
609
    eval {
610
        foreach my $cursor ( @$self ) {
611
            push @lines, '---';
612
 
613
            # An empty document
614
            if ( ! defined $cursor ) {
615
                # Do nothing
616
 
617
            # A scalar document
618
            } elsif ( ! ref $cursor ) {
619
                $lines[-1] .= ' ' . $self->_dump_scalar( $cursor );
620
 
621
            # A list at the root
622
            } elsif ( ref $cursor eq 'ARRAY' ) {
623
                unless ( @$cursor ) {
624
                    $lines[-1] .= ' []';
625
                    next;
626
                }
627
                push @lines, $self->_dump_array( $cursor, $indent, {} );
628
 
629
            # A hash at the root
630
            } elsif ( ref $cursor eq 'HASH' ) {
631
                unless ( %$cursor ) {
632
                    $lines[-1] .= ' {}';
633
                    next;
634
                }
635
                push @lines, $self->_dump_hash( $cursor, $indent, {} );
636
 
637
            } else {
638
                die \("Cannot serialize " . ref($cursor));
639
            }
640
        }
641
    };
642
    if ( ref $@ eq 'SCALAR' ) {
643
        $self->_error(${$@});
644
    } elsif ( $@ ) {
645
        $self->_error($@);
646
    }
647
 
648
    join '', map { "$_\n" } @lines;
649
}
650
 
651
sub _has_internal_string_value {
652
    my $value = shift;
653
    my $b_obj = B::svref_2object(\$value);  # for round trip problem
654
    return $b_obj->FLAGS & B::SVf_POK();
655
}
656
 
657
sub _dump_scalar {
658
    my $string = $_[1];
659
    my $is_key = $_[2];
660
    # Check this before checking length or it winds up looking like a string!
661
    my $has_string_flag = _has_internal_string_value($string);
662
    return '~'  unless defined $string;
663
    return "''" unless length  $string;
664
    if (Scalar::Util::looks_like_number($string)) {
665
        # keys and values that have been used as strings get quoted
666
        if ( $is_key || $has_string_flag ) {
667
            return qq['$string'];
668
        }
669
        else {
670
            return $string;
671
        }
672
    }
673
    if ( $string =~ /[\x00-\x09\x0b-\x0d\x0e-\x1f\x7f-\x9f\'\n]/ ) {
674
        $string =~ s/\\/\\\\/g;
675
        $string =~ s/"/\\"/g;
676
        $string =~ s/\n/\\n/g;
677
        $string =~ s/[\x85]/\\N/g;
678
        $string =~ s/([\x00-\x1f])/\\$UNPRINTABLE[ord($1)]/g;
679
        $string =~ s/([\x7f-\x9f])/'\x' . sprintf("%X",ord($1))/ge;
680
        return qq|"$string"|;
681
    }
682
    if ( $string =~ /(?:^[~!@#%&*|>?:,'"`{}\[\]]|^-+$|\s|:\z)/ or
683
        $QUOTE{$string}
684
    ) {
685
        return "'$string'";
686
    }
687
    return $string;
688
}
689
 
690
sub _dump_array {
691
    my ($self, $array, $indent, $seen) = @_;
692
    if ( $seen->{refaddr($array)}++ ) {
693
        die \"YAML::Tiny does not support circular references";
694
    }
695
    my @lines  = ();
696
    foreach my $el ( @$array ) {
697
        my $line = ('  ' x $indent) . '-';
698
        my $type = ref $el;
699
        if ( ! $type ) {
700
            $line .= ' ' . $self->_dump_scalar( $el );
701
            push @lines, $line;
702
 
703
        } elsif ( $type eq 'ARRAY' ) {
704
            if ( @$el ) {
705
                push @lines, $line;
706
                push @lines, $self->_dump_array( $el, $indent + 1, $seen );
707
            } else {
708
                $line .= ' []';
709
                push @lines, $line;
710
            }
711
 
712
        } elsif ( $type eq 'HASH' ) {
713
            if ( keys %$el ) {
714
                push @lines, $line;
715
                push @lines, $self->_dump_hash( $el, $indent + 1, $seen );
716
            } else {
717
                $line .= ' {}';
718
                push @lines, $line;
719
            }
720
 
721
        } else {
722
            die \"YAML::Tiny does not support $type references";
723
        }
724
    }
725
 
726
    @lines;
727
}
728
 
729
sub _dump_hash {
730
    my ($self, $hash, $indent, $seen) = @_;
731
    if ( $seen->{refaddr($hash)}++ ) {
732
        die \"YAML::Tiny does not support circular references";
733
    }
734
    my @lines  = ();
735
    foreach my $name ( sort keys %$hash ) {
736
        my $el   = $hash->{$name};
737
        my $line = ('  ' x $indent) . $self->_dump_scalar($name, 1) . ":";
738
        my $type = ref $el;
739
        if ( ! $type ) {
740
            $line .= ' ' . $self->_dump_scalar( $el );
741
            push @lines, $line;
742
 
743
        } elsif ( $type eq 'ARRAY' ) {
744
            if ( @$el ) {
745
                push @lines, $line;
746
                push @lines, $self->_dump_array( $el, $indent + 1, $seen );
747
            } else {
748
                $line .= ' []';
749
                push @lines, $line;
750
            }
751
 
752
        } elsif ( $type eq 'HASH' ) {
753
            if ( keys %$el ) {
754
                push @lines, $line;
755
                push @lines, $self->_dump_hash( $el, $indent + 1, $seen );
756
            } else {
757
                $line .= ' {}';
758
                push @lines, $line;
759
            }
760
 
761
        } else {
762
            die \"YAML::Tiny does not support $type references";
763
        }
764
    }
765
 
766
    @lines;
767
}
768
 
769
 
770
 
771
#####################################################################
772
# DEPRECATED API methods:
773
 
774
# Error storage (DEPRECATED as of 1.57)
775
our $errstr    = '';
776
 
777
# Set error
778
sub _error {
779
    require Carp;
780
    $errstr = $_[1];
781
    $errstr =~ s/ at \S+ line \d+.*//;
782
    Carp::croak( $errstr );
783
}
784
 
785
# Retrieve error
786
my $errstr_warned;
787
sub errstr {
788
    require Carp;
789
    Carp::carp( "YAML::Tiny->errstr and \$YAML::Tiny::errstr is deprecated" )
790
        unless $errstr_warned++;
791
    $errstr;
792
}
793
 
794
 
795
 
796
 
797
#####################################################################
798
# Helper functions. Possibly not needed.
799
 
800
 
801
# Use to detect nv or iv
802
use B;
803
 
804
# XXX-INGY Is flock YAML::Tiny's responsibility?
805
# Some platforms can't flock :-(
806
# XXX-XDG I think it is.  When reading and writing files, we ought
807
# to be locking whenever possible.  People (foolishly) use YAML
808
# files for things like session storage, which has race issues.
809
my $HAS_FLOCK;
810
sub _can_flock {
811
    if ( defined $HAS_FLOCK ) {
812
        return $HAS_FLOCK;
813
    }
814
    else {
815
        require Config;
816
        my $c = \%Config::Config;
817
        $HAS_FLOCK = grep { $c->{$_} } qw/d_flock d_fcntl_can_lock d_lockf/;
818
        require Fcntl if $HAS_FLOCK;
819
        return $HAS_FLOCK;
820
    }
821
}
822
 
823
 
824
# XXX-INGY Is this core in 5.8.1? Can we remove this?
825
# XXX-XDG Scalar::Util 1.18 didn't land until 5.8.8, so we need this
826
#####################################################################
827
# Use Scalar::Util if possible, otherwise emulate it
828
 
829
use Scalar::Util ();
830
BEGIN {
831
    local $@;
832
    if ( eval { Scalar::Util->VERSION(1.18); } ) {
833
        *refaddr = *Scalar::Util::refaddr;
834
    }
835
    else {
836
        eval <<'END_PERL';
837
# Scalar::Util failed to load or too old
838
sub refaddr {
839
    my $pkg = ref($_[0]) or return undef;
840
    if ( !! UNIVERSAL::can($_[0], 'can') ) {
841
        bless $_[0], 'Scalar::Util::Fake';
842
    } else {
843
        $pkg = undef;
844
    }
845
    "$_[0]" =~ /0x(\w+)/;
846
    my $i = do { no warnings 'portable'; hex $1 };
847
    bless $_[0], $pkg if defined $pkg;
848
    $i;
849
}
850
END_PERL
851
    }
852
}
853
 
854
delete $YAML::Tiny::{refaddr};
855
 
856
1;
857
 
858
# XXX-INGY Doc notes I'm putting up here. Changing the doc when it's wrong
859
# but leaving grey area stuff up here.
860
#
861
# I would like to change Read/Write to Load/Dump below without
862
# changing the actual API names.
863
#
864
# It might be better to put Load/Dump API in the SYNOPSIS instead of the
865
# dubious OO API.
866
#
867
# null and bool explanations may be outdated.
868
 
869
__END__
870
 
871
=pod
872
 
873
=head1 NAME
874
 
875
YAML::Tiny - Read/Write YAML files with as little code as possible
876
 
877
=head1 VERSION
878
 
879
version 1.73
880
 
881
=head1 PREAMBLE
882
 
883
The YAML specification is huge. Really, B<really> huge. It contains all the
884
functionality of XML, except with flexibility and choice, which makes it
885
easier to read, but with a formal specification that is more complex than
886
XML.
887
 
888
The original pure-Perl implementation L<YAML> costs just over 4 megabytes
889
of memory to load. Just like with Windows F<.ini> files (3 meg to load) and
890
CSS (3.5 meg to load) the situation is just asking for a B<YAML::Tiny>
891
module, an incomplete but correct and usable subset of the functionality,
892
in as little code as possible.
893
 
894
Like the other C<::Tiny> modules, YAML::Tiny has no non-core dependencies,
895
does not require a compiler to install, is back-compatible to Perl v5.8.1,
896
and can be inlined into other modules if needed.
897
 
898
In exchange for this adding this extreme flexibility, it provides support
899
for only a limited subset of YAML. But the subset supported contains most
900
of the features for the more common uses of YAML.
901
 
902
=head1 SYNOPSIS
903
 
904
Assuming F<file.yml> like this:
905
 
906
    ---
907
    rootproperty: blah
908
    section:
909
      one: two
910
      three: four
911
      Foo: Bar
912
      empty: ~
913
 
914
 
915
Read and write F<file.yml> like this:
916
 
917
    use YAML::Tiny;
918
 
919
    # Open the config
920
    my $yaml = YAML::Tiny->read( 'file.yml' );
921
 
922
    # Get a reference to the first document
923
    my $config = $yaml->[0];
924
 
925
    # Or read properties directly
926
    my $root = $yaml->[0]->{rootproperty};
927
    my $one  = $yaml->[0]->{section}->{one};
928
    my $Foo  = $yaml->[0]->{section}->{Foo};
929
 
930
    # Change data directly
931
    $yaml->[0]->{newsection} = { this => 'that' }; # Add a section
932
    $yaml->[0]->{section}->{Foo} = 'Not Bar!';     # Change a value
933
    delete $yaml->[0]->{section};                  # Delete a value
934
 
935
    # Save the document back to the file
936
    $yaml->write( 'file.yml' );
937
 
938
To create a new YAML file from scratch:
939
 
940
    # Create a new object with a single hashref document
941
    my $yaml = YAML::Tiny->new( { wibble => "wobble" } );
942
 
943
    # Add an arrayref document
944
    push @$yaml, [ 'foo', 'bar', 'baz' ];
945
 
946
    # Save both documents to a file
947
    $yaml->write( 'data.yml' );
948
 
949
Then F<data.yml> will contain:
950
 
951
    ---
952
    wibble: wobble
953
    ---
954
    - foo
955
    - bar
956
    - baz
957
 
958
=head1 DESCRIPTION
959
 
960
B<YAML::Tiny> is a perl class for reading and writing YAML-style files,
961
written with as little code as possible, reducing load time and memory
962
overhead.
963
 
964
Most of the time it is accepted that Perl applications use a lot
965
of memory and modules. The B<::Tiny> family of modules is specifically
966
intended to provide an ultralight and zero-dependency alternative to
967
many more-thorough standard modules.
968
 
969
This module is primarily for reading human-written files (like simple
970
config files) and generating very simple human-readable files. Note that
971
I said B<human-readable> and not B<geek-readable>. The sort of files that
972
your average manager or secretary should be able to look at and make
973
sense of.
974
 
975
=for stopwords normalise
976
 
977
L<YAML::Tiny> does not generate comments, it won't necessarily preserve the
978
order of your hashes, and it will normalise if reading in and writing out
979
again.
980
 
981
It only supports a very basic subset of the full YAML specification.
982
 
983
=for stopwords embeddable
984
 
985
Usage is targeted at files like Perl's META.yml, for which a small and
986
easily-embeddable module is extremely attractive.
987
 
988
Features will only be added if they are human readable, and can be written
989
in a few lines of code. Please don't be offended if your request is
990
refused. Someone has to draw the line, and for YAML::Tiny that someone
991
is me.
992
 
993
If you need something with more power move up to L<YAML> (7 megabytes of
994
memory overhead) or L<YAML::XS> (6 megabytes memory overhead and requires
995
a C compiler).
996
 
997
To restate, L<YAML::Tiny> does B<not> preserve your comments, whitespace,
998
or the order of your YAML data. But it should round-trip from Perl
999
structure to file and back again just fine.
1000
 
1001
=head1 METHODS
1002
 
1003
=for Pod::Coverage HAVE_UTF8 refaddr
1004
 
1005
=head2 new
1006
 
1007
The constructor C<new> creates a C<YAML::Tiny> object as a blessed array
1008
reference.  Any arguments provided are taken as separate documents
1009
to be serialized.
1010
 
1011
=head2 read $filename
1012
 
1013
The C<read> constructor reads a YAML file from a file name,
1014
and returns a new C<YAML::Tiny> object containing the parsed content.
1015
 
1016
Returns the object on success or throws an error on failure.
1017
 
1018
=head2 read_string $string;
1019
 
1020
The C<read_string> constructor reads YAML data from a character string, and
1021
returns a new C<YAML::Tiny> object containing the parsed content.  If you have
1022
read the string from a file yourself, be sure that you have correctly decoded
1023
it into characters first.
1024
 
1025
Returns the object on success or throws an error on failure.
1026
 
1027
=head2 write $filename
1028
 
1029
The C<write> method generates the file content for the properties, and
1030
writes it to disk using UTF-8 encoding to the filename specified.
1031
 
1032
Returns true on success or throws an error on failure.
1033
 
1034
=head2 write_string
1035
 
1036
Generates the file content for the object and returns it as a character
1037
string.  This may contain non-ASCII characters and should be encoded
1038
before writing it to a file.
1039
 
1040
Returns true on success or throws an error on failure.
1041
 
1042
=for stopwords errstr
1043
 
1044
=head2 errstr (DEPRECATED)
1045
 
1046
Prior to version 1.57, some errors were fatal and others were available only
1047
via the C<$YAML::Tiny::errstr> variable, which could be accessed via the
1048
C<errstr()> method.
1049
 
1050
Starting with version 1.57, all errors are fatal and throw exceptions.
1051
 
1052
The C<$errstr> variable is still set when exceptions are thrown, but
1053
C<$errstr> and the C<errstr()> method are deprecated and may be removed in a
1054
future release.  The first use of C<errstr()> will issue a deprecation
1055
warning.
1056
 
1057
=head1 FUNCTIONS
1058
 
1059
YAML::Tiny implements a number of functions to add compatibility with
1060
the L<YAML> API. These should be a drop-in replacement.
1061
 
1062
=head2 Dump
1063
 
1064
  my $string = Dump(list-of-Perl-data-structures);
1065
 
1066
Turn Perl data into YAML. This function works very much like
1067
Data::Dumper::Dumper().
1068
 
1069
It takes a list of Perl data structures and dumps them into a serialized
1070
form.
1071
 
1072
It returns a character string containing the YAML stream.  Be sure to encode
1073
it as UTF-8 before serializing to a file or socket.
1074
 
1075
The structures can be references or plain scalars.
1076
 
1077
Dies on any error.
1078
 
1079
=head2 Load
1080
 
1081
  my @data_structures = Load(string-containing-a-YAML-stream);
1082
 
1083
Turn YAML into Perl data. This is the opposite of Dump.
1084
 
1085
Just like L<Storable>'s thaw() function or the eval() function in relation
1086
to L<Data::Dumper>.
1087
 
1088
It parses a character string containing a valid YAML stream into a list of
1089
Perl data structures representing the individual YAML documents.  Be sure to
1090
decode the character string  correctly if the string came from a file or
1091
socket.
1092
 
1093
  my $last_data_structure = Load(string-containing-a-YAML-stream);
1094
 
1095
For consistency with YAML.pm, when Load is called in scalar context, it
1096
returns the data structure corresponding to the last of the YAML documents
1097
found in the input stream.
1098
 
1099
Dies on any error.
1100
 
1101
=head2 freeze() and thaw()
1102
 
1103
Aliases to Dump() and Load() for L<Storable> fans. This will also allow
1104
YAML::Tiny to be plugged directly into modules like POE.pm, that use the
1105
freeze/thaw API for internal serialization.
1106
 
1107
=head2 DumpFile(filepath, list)
1108
 
1109
Writes the YAML stream to a file with UTF-8 encoding instead of just
1110
returning a string.
1111
 
1112
Dies on any error.
1113
 
1114
=head2 LoadFile(filepath)
1115
 
1116
Reads the YAML stream from a UTF-8 encoded file instead of a string.
1117
 
1118
Dies on any error.
1119
 
1120
=head1 YAML TINY SPECIFICATION
1121
 
1122
This section of the documentation provides a specification for "YAML Tiny",
1123
a subset of the YAML specification.
1124
 
1125
It is based on and described comparatively to the YAML 1.1 Working Draft
1126
2004-12-28 specification, located at L<http://yaml.org/spec/current.html>.
1127
 
1128
Terminology and chapter numbers are based on that specification.
1129
 
1130
=head2 1. Introduction and Goals
1131
 
1132
The purpose of the YAML Tiny specification is to describe a useful subset
1133
of the YAML specification that can be used for typical document-oriented
1134
use cases such as configuration files and simple data structure dumps.
1135
 
1136
=for stopwords extensibility
1137
 
1138
Many specification elements that add flexibility or extensibility are
1139
intentionally removed, as is support for complex data structures, class
1140
and object-orientation.
1141
 
1142
In general, the YAML Tiny language targets only those data structures
1143
available in JSON, with the additional limitation that only simple keys
1144
are supported.
1145
 
1146
As a result, all possible YAML Tiny documents should be able to be
1147
transformed into an equivalent JSON document, although the reverse is
1148
not necessarily true (but will be true in simple cases).
1149
 
1150
=for stopwords PCRE
1151
 
1152
As a result of these simplifications the YAML Tiny specification should
1153
be implementable in a (relatively) small amount of code in any language
1154
that supports Perl Compatible Regular Expressions (PCRE).
1155
 
1156
=head2 2. Introduction
1157
 
1158
YAML Tiny supports three data structures. These are scalars (in a variety
1159
of forms), block-form sequences and block-form mappings. Flow-style
1160
sequences and mappings are not supported, with some minor exceptions
1161
detailed later.
1162
 
1163
The use of three dashes "---" to indicate the start of a new document is
1164
supported, and multiple documents per file/stream is allowed.
1165
 
1166
Both line and inline comments are supported.
1167
 
1168
Scalars are supported via the plain style, single quote and double quote,
1169
as well as literal-style and folded-style multi-line scalars.
1170
 
1171
The use of explicit tags is not supported.
1172
 
1173
The use of "null" type scalars is supported via the ~ character.
1174
 
1175
The use of "bool" type scalars is not supported.
1176
 
1177
=for stopwords serializer
1178
 
1179
However, serializer implementations should take care to explicitly escape
1180
strings that match a "bool" keyword in the following set to prevent other
1181
implementations that do support "bool" accidentally reading a string as a
1182
boolean
1183
 
1184
  y|Y|yes|Yes|YES|n|N|no|No|NO
1185
  |true|True|TRUE|false|False|FALSE
1186
  |on|On|ON|off|Off|OFF
1187
 
1188
The use of anchors and aliases is not supported.
1189
 
1190
The use of directives is supported only for the %YAML directive.
1191
 
1192
=head2 3. Processing YAML Tiny Information
1193
 
1194
B<Processes>
1195
 
1196
=for stopwords deserialization
1197
 
1198
The YAML specification dictates three-phase serialization and three-phase
1199
deserialization.
1200
 
1201
The YAML Tiny specification does not mandate any particular methodology
1202
or mechanism for parsing.
1203
 
1204
Any compliant parser is only required to parse a single document at a
1205
time. The ability to support streaming documents is optional and most
1206
likely non-typical.
1207
 
1208
=for stopwords acyclic
1209
 
1210
Because anchors and aliases are not supported, the resulting representation
1211
graph is thus directed but (unlike the main YAML specification) B<acyclic>.
1212
 
1213
Circular references/pointers are not possible, and any YAML Tiny serializer
1214
detecting a circular reference should error with an appropriate message.
1215
 
1216
B<Presentation Stream>
1217
 
1218
=for stopwords unicode
1219
 
1220
YAML Tiny reads and write UTF-8 encoded files.  Operations on strings expect
1221
or produce Unicode characters not UTF-8 encoded bytes.
1222
 
1223
B<Loading Failure Points>
1224
 
1225
=for stopwords modality
1226
 
1227
=for stopwords parsers
1228
 
1229
YAML Tiny parsers and emitters are not expected to recover from, or
1230
adapt to, errors. The specific error modality of any implementation is
1231
not dictated (return codes, exceptions, etc.) but is expected to be
1232
consistent.
1233
 
1234
=head2 4. Syntax
1235
 
1236
B<Character Set>
1237
 
1238
YAML Tiny streams are processed in memory as Unicode characters and
1239
read/written with UTF-8 encoding.
1240
 
1241
The escaping and unescaping of the 8-bit YAML escapes is required.
1242
 
1243
The escaping and unescaping of 16-bit and 32-bit YAML escapes is not
1244
required.
1245
 
1246
B<Indicator Characters>
1247
 
1248
Support for the "~" null/undefined indicator is required.
1249
 
1250
Implementations may represent this as appropriate for the underlying
1251
language.
1252
 
1253
Support for the "-" block sequence indicator is required.
1254
 
1255
Support for the "?" mapping key indicator is B<not> required.
1256
 
1257
Support for the ":" mapping value indicator is required.
1258
 
1259
Support for the "," flow collection indicator is B<not> required.
1260
 
1261
Support for the "[" flow sequence indicator is B<not> required, with
1262
one exception (detailed below).
1263
 
1264
Support for the "]" flow sequence indicator is B<not> required, with
1265
one exception (detailed below).
1266
 
1267
Support for the "{" flow mapping indicator is B<not> required, with
1268
one exception (detailed below).
1269
 
1270
Support for the "}" flow mapping indicator is B<not> required, with
1271
one exception (detailed below).
1272
 
1273
Support for the "#" comment indicator is required.
1274
 
1275
Support for the "&" anchor indicator is B<not> required.
1276
 
1277
Support for the "*" alias indicator is B<not> required.
1278
 
1279
Support for the "!" tag indicator is B<not> required.
1280
 
1281
Support for the "|" literal block indicator is required.
1282
 
1283
Support for the ">" folded block indicator is required.
1284
 
1285
Support for the "'" single quote indicator is required.
1286
 
1287
Support for the """ double quote indicator is required.
1288
 
1289
Support for the "%" directive indicator is required, but only
1290
for the special case of a %YAML version directive before the
1291
"---" document header, or on the same line as the document header.
1292
 
1293
For example:
1294
 
1295
  %YAML 1.1
1296
  ---
1297
  - A sequence with a single element
1298
 
1299
Special Exception:
1300
 
1301
To provide the ability to support empty sequences
1302
and mappings, support for the constructs [] (empty sequence) and {}
1303
(empty mapping) are required.
1304
 
1305
For example,
1306
 
1307
  %YAML 1.1
1308
  # A document consisting of only an empty mapping
1309
  --- {}
1310
  # A document consisting of only an empty sequence
1311
  --- []
1312
  # A document consisting of an empty mapping within a sequence
1313
  - foo
1314
  - {}
1315
  - bar
1316
 
1317
B<Syntax Primitives>
1318
 
1319
Other than the empty sequence and mapping cases described above, YAML Tiny
1320
supports only the indentation-based block-style group of contexts.
1321
 
1322
All five scalar contexts are supported.
1323
 
1324
Indentation spaces work as per the YAML specification in all cases.
1325
 
1326
Comments work as per the YAML specification in all simple cases.
1327
Support for indented multi-line comments is B<not> required.
1328
 
1329
Separation spaces work as per the YAML specification in all cases.
1330
 
1331
B<YAML Tiny Character Stream>
1332
 
1333
The only directive supported by the YAML Tiny specification is the
1334
%YAML language/version identifier. Although detected, this directive
1335
will have no control over the parsing itself.
1336
 
1337
=for stopwords recognise
1338
 
1339
The parser must recognise both the YAML 1.0 and YAML 1.1+ formatting
1340
of this directive (as well as the commented form, although no explicit
1341
code should be needed to deal with this case, being a comment anyway)
1342
 
1343
That is, all of the following should be supported.
1344
 
1345
  --- #YAML:1.0
1346
  - foo
1347
 
1348
  %YAML:1.0
1349
  ---
1350
  - foo
1351
 
1352
  % YAML 1.1
1353
  ---
1354
  - foo
1355
 
1356
Support for the %TAG directive is B<not> required.
1357
 
1358
Support for additional directives is B<not> required.
1359
 
1360
Support for the document boundary marker "---" is required.
1361
 
1362
Support for the document boundary market "..." is B<not> required.
1363
 
1364
If necessary, a document boundary should simply by indicated with a
1365
"---" marker, with not preceding "..." marker.
1366
 
1367
Support for empty streams (containing no documents) is required.
1368
 
1369
Support for implicit document starts is required.
1370
 
1371
That is, the following must be equivalent.
1372
 
1373
 # Full form
1374
 %YAML 1.1
1375
 ---
1376
 foo: bar
1377
 
1378
 # Implicit form
1379
 foo: bar
1380
 
1381
B<Nodes>
1382
 
1383
Support for nodes optional anchor and tag properties is B<not> required.
1384
 
1385
Support for node anchors is B<not> required.
1386
 
1387
Support for node tags is B<not> required.
1388
 
1389
Support for alias nodes is B<not> required.
1390
 
1391
Support for flow nodes is B<not> required.
1392
 
1393
Support for block nodes is required.
1394
 
1395
B<Scalar Styles>
1396
 
1397
Support for all five scalar styles is required as per the YAML
1398
specification, although support for quoted scalars spanning more
1399
than one line is B<not> required.
1400
 
1401
Support for multi-line scalar documents starting on the header
1402
is not required.
1403
 
1404
Support for the chomping indicators on multi-line scalar styles
1405
is required.
1406
 
1407
B<Collection Styles>
1408
 
1409
Support for block-style sequences is required.
1410
 
1411
Support for flow-style sequences is B<not> required.
1412
 
1413
Support for block-style mappings is required.
1414
 
1415
Support for flow-style mappings is B<not> required.
1416
 
1417
Both sequences and mappings should be able to be arbitrarily
1418
nested.
1419
 
1420
Support for plain-style mapping keys is required.
1421
 
1422
Support for quoted keys in mappings is B<not> required.
1423
 
1424
Support for "?"-indicated explicit keys is B<not> required.
1425
 
1426
=for stopwords endeth
1427
 
1428
Here endeth the specification.
1429
 
1430
=head2 Additional Perl-Specific Notes
1431
 
1432
For some Perl applications, it's important to know if you really have a
1433
number and not a string.
1434
 
1435
That is, in some contexts is important that 3 the number is distinctive
1436
from "3" the string.
1437
 
1438
Because even Perl itself is not trivially able to understand the difference
1439
(certainly without XS-based modules) Perl implementations of the YAML Tiny
1440
specification are not required to retain the distinctiveness of 3 vs "3".
1441
 
1442
=head1 SUPPORT
1443
 
1444
Bugs should be reported via the CPAN bug tracker at
1445
 
1446
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=YAML-Tiny>
1447
 
1448
=begin html
1449
 
1450
For other issues, or commercial enhancement or support, please contact
1451
<a href="http://ali.as/">Adam Kennedy</a> directly.
1452
 
1453
=end html
1454
 
1455
=head1 AUTHOR
1456
 
1457
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
1458
 
1459
=head1 SEE ALSO
1460
 
1461
=over 4
1462
 
1463
=item * L<YAML>
1464
 
1465
=item * L<YAML::Syck>
1466
 
1467
=item * L<Config::Tiny>
1468
 
1469
=item * L<CSS::Tiny>
1470
 
1471
=item * L<http://use.perl.org/use.perl.org/_Alias/journal/29427.html>
1472
 
1473
=item * L<http://ali.as/>
1474
 
1475
=back
1476
 
1477
=head1 COPYRIGHT
1478
 
1479
Copyright 2006 - 2013 Adam Kennedy.
1480
 
1481
This program is free software; you can redistribute
1482
it and/or modify it under the same terms as Perl itself.
1483
 
1484
The full text of the license can be found in the
1485
LICENSE file included with this module.
1486
 
1487
=cut