App-Dex
view release on metacpan or search on metacpan
scripts/dex view on Meta::CPAN
=head1 NAME
YAML::PP - YAML 1.2 processor
=head1 SYNOPSIS
WARNING: Most of the inner API is not stable yet.
Here are a few examples of the basic load and dump methods:
use YAML::PP;
my $ypp = YAML::PP->new;
my $yaml = <<'EOM';
--- # Document one is a mapping
name: Tina
age: 29
favourite language: Perl
--- # Document two is a sequence
- plain string
- 'in single quotes'
- "in double quotes we have escapes! like \t and \n"
- | # a literal block scalar
line1
line2
- > # a folded block scalar
this is all one
single line because the
linebreaks will be folded
EOM
my @documents = $ypp->load_string($yaml);
my @documents = $ypp->load_file($filename);
my $yaml = $ypp->dump_string($data1, $data2);
$ypp->dump_file($filename, $data1, $data2);
# The loader offers JSON::PP::Boolean, boolean.pm or
# perl 1/'' (currently default) for booleans
my $ypp = YAML::PP->new(boolean => 'JSON::PP');
my $ypp = YAML::PP->new(boolean => 'boolean');
my $ypp = YAML::PP->new(boolean => 'perl');
# Enable perl data types and objects
my $ypp = YAML::PP->new(schema => [qw/ + Perl /]);
my $yaml = $yp->dump_string($data_with_perl_objects);
# Legacy interface
use YAML::PP qw/ Load Dump LoadFile DumpFile /;
my @documents = Load($yaml);
my @documents = LoadFile($filename);
my @documents = LoadFile($filehandle);
my $yaml = = Dump(@documents);
DumpFile($filename, @documents);
DumpFile($filenhandle @documents);
Some utility scripts, mostly useful for debugging:
# Load YAML into a data structure and dump with Data::Dumper
yamlpp-load < file.yaml
# Load and Dump
yamlpp-load-dump < file.yaml
# Print the events from the parser in yaml-test-suite format
yamlpp-events < file.yaml
# Parse and emit events directly without loading
yamlpp-parse-emit < file.yaml
# Create ANSI colored YAML. Can also be useful for invalid YAML, showing
# you the exact location of the error
yamlpp-highlight < file.yaml
=head1 DESCRIPTION
YAML::PP is a modular YAML processor.
It aims to support C<YAML 1.2> and C<YAML 1.1>. See L<https://yaml.org/>.
Some (rare) syntax elements are not yet supported and documented below.
YAML is a serialization language. The YAML input is called "YAML Stream".
A stream consists of one or more "Documents", separated by a line with a
document start marker C<--->. A document optionally ends with the document
end marker C<...>.
This allows one to process continuous streams additionally to a fixed input
file or string.
The YAML::PP frontend will currently load all documents, and return only
the first if called with scalar context.
The YAML backend is implemented in a modular way that allows one to add
custom handling of YAML tags, perl objects and data types. The inner API
is not yet stable. Suggestions welcome.
You can check out all current parse and load results from the
yaml-test-suite here:
L<https://perlpunk.github.io/YAML-PP-p5/test-suite.html>
=head1 METHODS
=head2 new
my $ypp = YAML::PP->new;
# load booleans via boolean.pm
my $ypp = YAML::PP->new( boolean => 'boolean' );
# load booleans via JSON::PP::true/false
my $ypp = YAML::PP->new( boolean => 'JSON::PP' );
# use YAML 1.2 Failsafe Schema
my $ypp = YAML::PP->new( schema => ['Failsafe'] );
# use YAML 1.2 JSON Schema
my $ypp = YAML::PP->new( schema => ['JSON'] );
# use YAML 1.2 Core Schema
my $ypp = YAML::PP->new( schema => ['Core'] );
scripts/dex view on Meta::CPAN
=item Line and Column Numbers
You will see line and column numbers in the error message. The column numbers
might still be wrong in some cases.
=item Error Messages
The error messages need to be improved.
=item Unicode Surrogate Pairs
Currently loaded as single characters without validating
=item Possibly more
=back
=head2 YAML::PP::Constructor
The Constructor now supports all three YAML 1.2 Schemas, Failsafe, JSON and
Core. Additionally you can choose the schema for YAML 1.1 as C<YAML1_1>.
Too see what strings are resolved as booleans, numbers, null etc. look at
L<https://perlpunk.github.io/YAML-PP-p5/schema-examples.html>.
You can choose the Schema like this:
my $ypp = YAML::PP->new(schema => ['JSON']); # default is 'Core'
The Tags C<!!seq> and C<!!map> are still ignored for now.
It supports:
=over 4
=item Handling of Anchors/Aliases
Like in modules like L<YAML>, the Constructor will use references for mappings and
sequences, but obviously not for scalars.
L<YAML::XS> uses real aliases, which allows also aliasing scalars. I might add
an option for that since aliasing is now available in pure perl.
=item Boolean Handling
You can choose between C<'perl'> (1/'', currently default), C<'JSON::PP'> and
C<'boolean'>.pm for handling boolean types. That allows you to dump the data
structure with one of the JSON modules without losing information about
booleans.
=item Numbers
Numbers are created as real numbers instead of strings, so that they are
dumped correctly by modules like L<JSON::PP> or L<JSON::XS>, for example.
=item Complex Keys
Mapping Keys in YAML can be more than just scalars. Of course, you can't load
that into a native perl structure. The Constructor will stringify those keys
with L<Data::Dumper> instead of just returning something like
C<HASH(0x55dc1b5d0178)>.
Example:
use YAML::PP;
use JSON::PP;
my $ypp = YAML::PP->new;
my $coder = JSON::PP->new->ascii->pretty->allow_nonref->canonical;
my $yaml = <<'EOM';
complex:
?
?
a: 1
c: 2
: 23
: 42
EOM
my $data = $yppl->load_string($yaml);
say $coder->encode($data);
__END__
{
"complex" : {
"{'{a => 1,c => 2}' => 23}" : 42
}
}
=back
TODO:
=over 4
=item Parse Tree
I would like to generate a complete parse tree, that allows you to manipulate
the data structure and also dump it, including all whitespaces and comments.
The spec says that this is throwaway content, but I read that many people
wish to be able to keep the comments.
=back
=head2 YAML::PP::Dumper, YAML::PP::Emitter
The Dumper should be able to dump strings correctly, adding quotes
whenever a plain scalar would look like a special string, like C<true>,
or when it contains or starts with characters that are not allowed.
Most strings will be dumped as plain scalars without quotes. If they
contain special characters or have a special meaning, they will be dumped
with single quotes. If they contain control characters, including <"\n">,
they will be dumped with double quotes.
It will recognize JSON::PP::Boolean and boolean.pm objects and dump them
correctly.
Numbers which also have a C<PV> flag will be recognized as numbers and not
as strings:
my $int = 23;
say "int: $int"; # $int will now also have a PV flag
scripts/dex view on Meta::CPAN
if (($preserve_style or $preserve_alias) and not ref $value) {
my %args = (
value => $value,
tag => $event->{tag},
);
if ($preserve_style) {
$args{style} = $event->{style};
}
if ($preserve_alias and defined $event->{anchor}) {
my $anchor = $event->{anchor};
unless (exists $self->anchors->{ $anchor }) {
# Repeated anchors cannot be preserved
$args{alias} = $event->{anchor};
}
}
$value = YAML::PP::Preserve::Scalar->new( %args );
}
if (defined (my $name = $event->{anchor})) {
$self->anchors->{ $name } = { data => \$value, finished => 1 };
}
push @{ $last->{ref} }, $value;
}
sub alias_event {
my ($self, $event) = @_;
my $value;
my $name = $event->{value};
if (my $anchor = $self->anchors->{ $name }) {
# We know this is a cyclic ref since the node hasn't
# been constructed completely yet
unless ($anchor->{finished} ) {
my $cyclic_refs = $self->cyclic_refs;
if ($cyclic_refs ne 'allow') {
if ($cyclic_refs eq 'fatal') {
die "Found cyclic ref for alias '$name'";
}
if ($cyclic_refs eq 'warn') {
$anchor = { data => \undef };
warn "Found cyclic ref for alias '$name'";
}
elsif ($cyclic_refs eq 'ignore') {
$anchor = { data => \undef };
}
}
}
$value = $anchor->{data};
}
else {
croak "No anchor defined for alias '$name'";
}
my $last = $self->stack->[-1];
push @{ $last->{ref} }, $$value;
}
sub stringify_complex {
my ($self, $data) = @_;
return $data if (
ref $data eq 'YAML::PP::Preserve::Scalar'
and ($self->preserve_scalar_style or $self->preserve_alias)
);
require Data::Dumper;
local $Data::Dumper::Quotekeys = 0;
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 0;
local $Data::Dumper::Useqq = 0;
local $Data::Dumper::Sortkeys = 1;
my $string = Data::Dumper->Dump([$data], ['data']);
$string =~ s/^\$data = //;
return $string;
}
1;
__END__
=pod
=encoding utf-8
=head1 NAME
YAML::PP::Constructor - Constructing data structure from parsing events
=head1 METHODS
=over
=item new
The Constructor constructor
my $constructor = YAML::PP::Constructor->new(
schema => $schema,
cyclic_refs => $cyclic_refs,
);
=item init
Resets any data being used during construction.
$constructor->init;
=item document_start_event, document_end_event, mapping_start_event, mapping_end_event, sequence_start_event, sequence_end_event, scalar_event, alias_event, stream_start_event, stream_end_event
These methods are called from L<YAML::PP::Parser>:
$constructor->document_start_event($event);
=item anchors, set_anchors
Helper for storing anchors during construction
=item docs, set_docs
Helper for storing resulting documents during construction
=item stack, set_stack
Helper for storing data during construction
=item cyclic_refs, set_cyclic_refs
Option for controlling the behaviour when finding circular references
=item schema, set_schema
Holds a L<YAML::PP::Schema> object
=item stringify_complex
When constructing a hash and getting a non-scalar key, this method is
used to stringify the key.
It uses a terse Data::Dumper output. Other modules, like L<YAML::XS>, use
the default stringification, C<ARRAY(0x55617c0c7398)> for example.
=back
=cut
YAML_PP_CONSTRUCTOR
$fatpacked{"YAML/PP/Dumper.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'YAML_PP_DUMPER';
use strict;
use warnings;
package YAML::PP::Dumper;
our $VERSION = '0.027'; # VERSION
use Scalar::Util qw/ blessed refaddr reftype /;
use YAML::PP;
use YAML::PP::Emitter;
use YAML::PP::Representer;
use YAML::PP::Writer;
use YAML::PP::Writer::File;
use YAML::PP::Common qw/
YAML_PLAIN_SCALAR_STYLE YAML_SINGLE_QUOTED_SCALAR_STYLE
YAML_DOUBLE_QUOTED_SCALAR_STYLE
YAML_ANY_SCALAR_STYLE
YAML_LITERAL_SCALAR_STYLE YAML_FOLDED_SCALAR_STYLE
YAML_FLOW_SEQUENCE_STYLE YAML_FLOW_MAPPING_STYLE
YAML_BLOCK_MAPPING_STYLE YAML_BLOCK_SEQUENCE_STYLE
/;
sub new {
my ($class, %args) = @_;
my $header = delete $args{header};
$header = 1 unless defined $header;
my $footer = delete $args{footer};
$footer = 0 unless defined $footer;
my $version_directive = delete $args{version_directive};
my $preserve = delete $args{preserve};
my $schema = delete $args{schema} || YAML::PP->default_schema(
boolean => 'perl',
);
my $emitter = delete $args{emitter} || YAML::PP::Emitter->new;
unless (blessed($emitter)) {
$emitter = YAML::PP::Emitter->new(
%$emitter
);
}
if (keys %args) {
die "Unexpected arguments: " . join ', ', sort keys %args;
}
my $self = bless {
representer => YAML::PP::Representer->new(
schema => $schema,
preserve => $preserve,
),
version_directive => $version_directive,
emitter => $emitter,
scripts/dex view on Meta::CPAN
sub dump_file {
my ($self, $file, @docs) = @_;
my $writer = YAML::PP::Writer::File->new(output => $file);
$self->emitter->set_writer($writer);
my $output = $self->dump(@docs);
return $output;
}
my %_reftypes = (
HASH => 1,
ARRAY => 1,
Regexp => 1,
REGEXP => 1,
CODE => 1,
SCALAR => 1,
REF => 1,
GLOB => 1,
);
sub check_references {
my ($self, $doc) = @_;
my $reftype = reftype $doc or return;
my $seen = $self->{seen};
# check which references are used more than once
if ($reftype eq 'SCALAR' and ref $doc eq $self->representer->schema->bool_class) {
# JSON::PP and boolean.pm always return the same reference for booleans
# Avoid printing *aliases in those case
if (ref $doc eq 'boolean' or ref $doc eq 'JSON::PP::Boolean') {
return;
}
}
if (++$seen->{ refaddr $doc } > 1) {
# seen already
return;
}
unless ($_reftypes{ $reftype }) {
die sprintf "Reference %s not implemented",
$reftype;
}
if ($reftype eq 'HASH') {
$self->check_references($doc->{ $_ }) for keys %$doc;
}
elsif ($reftype eq 'ARRAY') {
$self->check_references($_) for @$doc;
}
elsif ($reftype eq 'REF') {
$self->check_references($$doc);
}
}
1;
YAML_PP_DUMPER
$fatpacked{"YAML/PP/Emitter.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'YAML_PP_EMITTER';
use strict;
use warnings;
package YAML::PP::Emitter;
our $VERSION = '0.027'; # VERSION
use Data::Dumper;
use YAML::PP::Common qw/
YAML_PLAIN_SCALAR_STYLE YAML_SINGLE_QUOTED_SCALAR_STYLE
YAML_DOUBLE_QUOTED_SCALAR_STYLE
YAML_LITERAL_SCALAR_STYLE YAML_FOLDED_SCALAR_STYLE
YAML_FLOW_SEQUENCE_STYLE YAML_FLOW_MAPPING_STYLE
/;
use constant DEBUG => $ENV{YAML_PP_EMIT_DEBUG} ? 1 : 0;
use constant DEFAULT_WIDTH => 80;
sub new {
my ($class, %args) = @_;
my $self = bless {
indent => $args{indent} || 2,
writer => $args{writer},
width => $args{width} || DEFAULT_WIDTH,
}, $class;
$self->init;
return $self;
}
sub clone {
my ($self) = @_;
my $clone = {
indent => $self->indent,
};
return bless $clone, ref $self;
}
sub event_stack { return $_[0]->{event_stack} }
sub set_event_stack { $_[0]->{event_stack} = $_[1] }
sub indent { return $_[0]->{indent} }
sub width { return $_[0]->{width} }
sub line { return $_[0]->{line} }
sub column { return $_[0]->{column} }
sub set_indent { $_[0]->{indent} = $_[1] }
sub writer { $_[0]->{writer} }
sub set_writer { $_[0]->{writer} = $_[1] }
sub tagmap { return $_[0]->{tagmap} }
sub set_tagmap { $_[0]->{tagmap} = $_[1] }
sub init {
my ($self) = @_;
unless ($self->writer) {
$self->set_writer(YAML::PP::Writer->new);
}
$self->set_tagmap({
'tag:yaml.org,2002:' => '!!',
});
$self->{open_ended} = 0;
$self->{line} = 0;
$self->{column} = 0;
$self->writer->init;
}
sub mapping_start_event {
DEBUG and warn __PACKAGE__.':'.__LINE__.": +++ mapping_start_event\n";
my ($self, $info) = @_;
my $stack = $self->event_stack;
scripts/dex view on Meta::CPAN
"\x8c" => '\x8c',
"\x8d" => '\x8d',
"\x8e" => '\x8e',
"\x8f" => '\x8f',
"\x90" => '\x90',
"\x91" => '\x91',
"\x92" => '\x92',
"\x93" => '\x93',
"\x94" => '\x94',
"\x95" => '\x95',
"\x96" => '\x96',
"\x97" => '\x97',
"\x98" => '\x98',
"\x99" => '\x99',
"\x9a" => '\x9a',
"\x9b" => '\x9b',
"\x9c" => '\x9c',
"\x9d" => '\x9d',
"\x9e" => '\x9e',
"\x9f" => '\x9f',
"\x{2029}" => '\P',
"\x{2028}" => '\L',
"\x85" => '\N',
"\xa0" => '\_',
);
my $control_re = '\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x84\x86-\x9f\x{d800}-\x{dfff}\x{fffe}\x{ffff}\x{2028}\x{2029}\x85\xa0';
my %to_escape = (
"\n" => '\n',
"\t" => '\t',
"\r" => '\r',
'\\' => '\\\\',
'"' => '\\"',
%control,
);
my $escape_re = $control_re . '\n\t\r';
my $escape_re_without_lb = $control_re . '\t\r';
sub scalar_event {
DEBUG and warn __PACKAGE__.':'.__LINE__.": +++ scalar_event\n";
my ($self, $info) = @_;
my $stack = $self->event_stack;
my $last = $stack->[-1];
my $indent = $last->{indent};
my $value = $info->{value};
my $flow = $last->{flow};
my $props = '';
my $anchor = $info->{anchor};
my $tag = $info->{tag};
if (defined $anchor) {
$anchor = "&$anchor";
}
if (defined $tag) {
$tag = $self->emit_tag('scalar', $tag);
}
$props = join ' ', grep defined, ($anchor, $tag);
my $style = $info->{style};
DEBUG and local $Data::Dumper::Useqq = 1;
$value = '' unless defined $value;
my $first = substr($value, 0, 1);
if ($value eq '') {
if ($flow and $last->{type} ne 'MAPVALUE' and $last->{type} ne 'MAP') {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
elsif (not $style) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
}
# no control characters anywhere
elsif ($value =~ m/[$control_re]/) {
$style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
$style ||= YAML_PLAIN_SCALAR_STYLE;
if ($style == YAML_SINGLE_QUOTED_SCALAR_STYLE) {
if ($value =~ m/ \n/ or $value =~ m/\n / or $value =~ m/^\n/ or $value =~ m/\n$/) {
$style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
elsif ($value eq "\n") {
$style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
}
elsif ($style == YAML_LITERAL_SCALAR_STYLE or $style == YAML_FOLDED_SCALAR_STYLE) {
if ($value eq '') {
$style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
elsif ($flow) {
# no block scalars in flow
if ($value =~ tr/\n//) {
$style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
else {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
}
}
elsif ($style == YAML_PLAIN_SCALAR_STYLE) {
if (not length $value) {
}
elsif ($value =~ m/[$escape_re_without_lb]/) {
$style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
elsif ($value eq "\n") {
$style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
elsif ($value !~ tr/ //c) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
elsif ($value !~ tr/ \n//c) {
$style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
elsif ($value =~ tr/\n//) {
$style = $flow ? YAML_DOUBLE_QUOTED_SCALAR_STYLE : YAML_LITERAL_SCALAR_STYLE;
}
elsif ($forbidden_first{ $first }) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
elsif ($flow and $value =~ tr/,[]{}//) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
elsif (substr($value, 0, 3) =~ m/^(?:---|\.\.\.)/) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
elsif ($value =~ m/: /) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
elsif ($value =~ m/ #/) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
elsif ($value =~ m/[: \t]\z/) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
elsif ($value =~ m/[^\x20-\x3A\x3B-\x7E\x85\xA0-\x{D7FF}\x{E000}-\x{FEFE}\x{FF00}-\x{FFFD}\x{10000}-\x{10FFFF}]/) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
elsif ($forbidden_first_plus_space{ $first }) {
if (length ($value) == 1 or substr($value, 1, 1) =~ m/^\s/) {
$style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
}
}
}
if ($style == YAML_SINGLE_QUOTED_SCALAR_STYLE and not $info->{style}) {
if ($value =~ tr/'// and $value !~ tr/"//) {
$style = YAML_DOUBLE_QUOTED_SCALAR_STYLE;
}
}
my $open_ended = 0;
if ($style == YAML_PLAIN_SCALAR_STYLE) {
$value =~ s/\n/\n\n/g;
}
elsif ($style == YAML_SINGLE_QUOTED_SCALAR_STYLE) {
my $new_indent = $last->{indent} . (' ' x $self->indent);
$value =~ s/(\n+)/"\n" x (1 + (length $1))/eg;
my @lines = split m/\n/, $value, -1;
if (@lines > 1) {
for my $line (@lines[1 .. $#lines]) {
$line = $new_indent . $line
if length $line;
}
}
$value = join "\n", @lines;
$value =~ s/'/''/g;
$value = "'" . $value . "'";
}
elsif ($style == YAML_LITERAL_SCALAR_STYLE) {
DEBUG and warn __PACKAGE__.':'.__LINE__.$".Data::Dumper->Dump([\$value], ['value']);
my $indicators = '';
if ($value =~ m/\A\n* +/) {
$indicators .= $self->indent;
}
my $indent = $indent . ' ' x $self->indent;
if ($value !~ m/\n\z/) {
$indicators .= '-';
$value .= "\n";
}
elsif ($value =~ m/(\n|\A)\n\z/) {
$indicators .= '+';
$open_ended = 1;
}
$value =~ s/^(?=.)/$indent/gm;
$value = "|$indicators\n$value";
}
elsif ($style == YAML_FOLDED_SCALAR_STYLE) {
DEBUG and warn __PACKAGE__.':'.__LINE__.$".Data::Dumper->Dump([\$value], ['value']);
my @lines = split /\n/, $value, -1;
DEBUG and warn __PACKAGE__.':'.__LINE__.$".Data::Dumper->Dump([\@lines], ['lines']);
my $eol = 0;
my $indicators = '';
if ($value =~ m/\A\n* +/) {
$indicators .= $self->indent;
}
my $indent = $indent . ' ' x $self->indent;
if ($lines[-1] eq '') {
pop @lines;
$eol = 1;
}
else {
$indicators .= '-';
}
$value = ">$indicators\n";
for my $i (0 .. $#lines) {
my $line = $lines[ $i ];
if (length $line) {
$value .= "$indent$line\n";
}
if ($i != $#lines) {
$value .= "\n";
}
}
}
else {
$value =~ s/([$escape_re"\\])/$to_escape{ $1 } || sprintf '\\u%04x', ord($1)/eg;
$value = '"' . $value . '"';
}
DEBUG and warn __PACKAGE__.':'.__LINE__.": (@$stack)\n";
my $yaml = '';
my $pvalue = $props;
if ($props and length $value) {
$pvalue .= " $value";
}
elsif (length $value) {
$pvalue .= $value;
}
my $multiline = ($style == YAML_LITERAL_SCALAR_STYLE or $style == YAML_FOLDED_SCALAR_STYLE);
my $newline = 0;
if ($flow) {
$indent = 0;
if ($props and not length $value) {
$pvalue .= ' ';
}
if ($last->{type} eq 'SEQ') {
if ($last->{index} == 0) {
if ($self->column) {
$yaml .= ' ';
}
$yaml .= "[";
}
else {
$yaml .= ", ";
}
}
elsif ($last->{type} eq 'MAP') {
if ($last->{index} == 0) {
if ($self->column) {
$yaml .= ' ';
scripts/dex view on Meta::CPAN
TODO: Currently sequences are always zero-indented.
=item writer, set_writer
Getter/setter for the writer object. By default L<YAML::PP::Writer>.
You can pass your own writer if you want to output the resulting YAML yourself.
=item init
Initialize
=item finish
=back
=cut
YAML_PP_EMITTER
$fatpacked{"YAML/PP/Exception.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'YAML_PP_EXCEPTION';
use strict;
use warnings;
package YAML::PP::Exception;
our $VERSION = '0.027'; # VERSION
use overload '""' => \&to_string;
sub new {
my ($class, %args) = @_;
my $self = bless {
line => $args{line},
msg => $args{msg},
next => $args{next},
where => $args{where},
yaml => $args{yaml},
got => $args{got},
expected => $args{expected},
column => $args{column},
}, $class;
return $self;
}
sub to_string {
my ($self) = @_;
my $next = $self->{next};
my $line = $self->{line};
my $column = $self->{column};
my $yaml = '';
for my $token (@$next) {
last if $token->{name} eq 'EOL';
$yaml .= $token->{value};
}
$column = '???' unless defined $column;
my $remaining_yaml = $self->{yaml};
$remaining_yaml = '' unless defined $remaining_yaml;
$yaml .= $remaining_yaml;
{
local $@; # avoid bug in old Data::Dumper
require Data::Dumper;
local $Data::Dumper::Useqq = 1;
local $Data::Dumper::Terse = 1;
$yaml = Data::Dumper->Dump([$yaml], ['yaml']);
chomp $yaml;
}
my $lines = 5;
my @fields;
if ($self->{got} and $self->{expected}) {
$lines = 6;
$line = $self->{got}->{line};
$column = $self->{got}->{column} + 1;
@fields = (
"Line" => $line,
"Column" => $column,
"Expected", join(" ", @{ $self->{expected} }),
"Got", $self->{got}->{name},
"Where", $self->{where},
"YAML", $yaml,
);
}
else {
@fields = (
"Line" => $line,
"Column" => $column,
"Message", $self->{msg},
"Where", $self->{where},
"YAML", $yaml,
);
}
my $fmt = join "\n", ("%-10s: %s") x $lines;
my $string = sprintf $fmt, @fields;
return $string;
}
1;
YAML_PP_EXCEPTION
$fatpacked{"YAML/PP/Grammar.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'YAML_PP_GRAMMAR';
use strict;
use warnings;
package YAML::PP::Grammar;
our $VERSION = '0.027'; # VERSION
use base 'Exporter';
our @EXPORT_OK = qw/ $GRAMMAR /;
our $GRAMMAR = {};
# START OF GRAMMAR INLINE
# DO NOT CHANGE THIS
# This grammar is automatically generated from etc/grammar.yaml
$GRAMMAR = {
'DIRECTIVE' => {
'DOC_START' => {
'EOL' => {
'new' => 'FULLNODE'
},
scripts/dex view on Meta::CPAN
else {
if ($space < $indent) {
$self->remove_nodes($space);
}
}
my $exp = $self->events->[-1];
if ($exp eq 'SEQ0' and $next->{name} ne 'DASH') {
TRACE and $self->info("In unindented sequence");
$self->end_sequence;
$exp = $self->events->[-1];
}
if ($self->offset->[-1] != $space) {
$self->exception("Expected " . $self->events->[-1]);
}
return 1;
}
my %next_event = (
MAP => 'MAPVALUE',
MAPVALUE => 'MAP',
SEQ => 'SEQ',
SEQ0 => 'SEQ0',
DOC => 'DOC_END',
STR => 'STR',
FLOWSEQ => 'FLOWSEQ_NEXT',
FLOWSEQ_NEXT => 'FLOWSEQ',
FLOWMAP => 'FLOWMAPVALUE',
FLOWMAPVALUE => 'FLOWMAP',
);
my %event_to_method = (
MAP => 'mapping',
FLOWMAP => 'mapping',
SEQ => 'sequence',
SEQ0 => 'sequence',
FLOWSEQ => 'sequence',
DOC => 'document',
STR => 'stream',
VAL => 'scalar',
ALI => 'alias',
MAPVALUE => 'mapping',
);
#sub process_events {
# my ($self, $res) = @_;
#
# my $event_stack = $self->event_stack;
# return unless @$event_stack;
#
# if (@$event_stack == 1 and $event_stack->[0]->[0] eq 'properties') {
# return;
# }
#
# my $event_types = $self->events;
# my $properties;
# my @send_events;
# for my $event (@$event_stack) {
# TRACE and warn __PACKAGE__.':'.__LINE__.$".Data::Dumper->Dump([\$event], ['event']);
# my ($type, $info) = @$event;
# if ($type eq 'properties') {
# $properties = $info;
# }
# elsif ($type eq 'scalar') {
# $info->{name} = 'scalar_event';
# $event_types->[-1] = $next_event{ $event_types->[-1] };
# push @send_events, $info;
# }
# elsif ($type eq 'begin') {
# my $name = $info->{name};
# $info->{name} = $event_to_method{ $name } . '_start_event';
# push @{ $event_types }, $name;
# push @{ $self->offset }, $info->{offset};
# push @send_events, $info;
# }
# elsif ($type eq 'end') {
# my $name = $info->{name};
# $info->{name} = $event_to_method{ $name } . '_end_event';
# $self->$type($name, $info);
# push @send_events, $info;
# if (@$event_types) {
# $event_types->[-1] = $next_event{ $event_types->[-1] };
# }
# }
# elsif ($type eq 'alias') {
# if ($properties) {
# $self->exception("Parse error: Alias not allowed in this context");
# }
# $info->{name} = 'alias_event';
# $event_types->[-1] = $next_event{ $event_types->[-1] };
# push @send_events, $info;
# }
# }
# @$event_stack = ();
# for my $info (@send_events) {
# DEBUG and $self->debug_event( $info );
# $self->callback->($self, $info->{name}, $info);
# }
#}
my %fetch_method = (
'"' => 'fetch_quoted',
"'" => 'fetch_quoted',
'|' => 'fetch_block',
'>' => 'fetch_block',
'' => 'fetch_plain',
);
sub parse_tokens {
my ($self) = @_;
my $event_types = $self->events;
my $offsets = $self->offset;
my $tokens = $self->tokens;
my $next_tokens = $self->lexer->next_tokens;
unless ($self->lex_next_tokens) {
$self->end_document(1);
return 0;
}
unless ($self->new_node) {
if ($self->level > 0) {
my $new_rule = $nodetypes{ $event_types->[-1] }
or die "Did not find '$event_types->[-1]'";
$self->set_rule( $new_rule );
}
}
my $rule_name = $self->rule;
DEBUG and $self->info("----------------> parse_tokens($rule_name)");
my $rule = $GRAMMAR->{ $rule_name }
or die "Could not find rule $rule_name";
TRACE and $self->debug_rules($rule);
TRACE and $self->debug_yaml;
DEBUG and $self->debug_next_line;
RULE: while ($rule_name) {
DEBUG and $self->info("RULE: $rule_name");
TRACE and $self->debug_tokens($next_tokens);
unless (@$next_tokens) {
$self->exception("No more tokens");
}
TRACE and warn __PACKAGE__.':'.__LINE__.$".Data::Dumper->Dump([\$next_tokens->[0]], ['next_token']);
my $got = $next_tokens->[0]->{name};
if ($got eq 'CONTEXT') {
my $context = shift @$next_tokens;
my $indent = $offsets->[-1];
$indent++ unless $self->lexer->flowcontext;
my $method = $fetch_method{ $context->{value} };
my $partial = $self->lexer->$method($indent, $context->{value});
next RULE;
}
my $def = $rule->{ $got };
if ($def) {
push @$tokens, shift @$next_tokens;
}
elsif ($def = $rule->{DEFAULT}) {
$got = 'DEFAULT';
}
else {
$self->expected(
expected => [keys %$rule],
got => $next_tokens->[0],
);
}
DEBUG and $self->got("---got $got");
if (my $sub = $def->{match}) {
DEBUG and $self->info("CALLBACK $sub");
$self->$sub(@$tokens ? $tokens->[-1] : ());
}
my $eol = $got eq 'EOL';
my $new = $def->{new};
if ($new) {
DEBUG and $self->got("NEW: $new");
$rule_name = $new;
$self->set_rule($rule_name);
}
elsif ($eol) {
}
elsif ($def->{return}) {
$rule_name = $nodetypes{ $event_types->[-1] }
or die "Unexpected event type $event_types->[-1]";
$self->set_rule($rule_name);
}
else {
$rule_name .= " - $got"; # for debugging
$rule = $def;
next RULE;
}
if ($eol) {
unless ($self->lex_next_tokens) {
$self->end_document(1);
return 0;
}
unless ($self->new_node) {
if ($self->level > 0) {
$rule_name = $nodetypes{ $event_types->[-1] }
or die "Did not find '$event_types->[-1]'";
$self->set_rule( $rule_name );
}
}
$rule_name = $self->rule;
scripts/dex view on Meta::CPAN
sub debug_offset {
my ($self) = @_;
$self->note(
qq{OFFSET: (}
. join (' | ', map { defined $_ ? sprintf "%-3d", $_ : '?' } @{ $_[0]->offset })
. qq/) level=@{[ $_[0]->level ]}]}/
);
}
sub debug_yaml {
my ($self) = @_;
my $line = $self->lexer->line;
$self->note("LINE NUMBER: $line");
my $next_tokens = $self->lexer->next_tokens;
if (@$next_tokens) {
$self->debug_tokens($next_tokens);
}
}
sub debug_next_line {
my ($self) = @_;
my $next_line = $self->lexer->next_line || [];
my $line = $next_line->[0];
$line = '' unless defined $line;
$line =~ s/( +)$/'·' x length $1/e;
$line =~ s/\t/â¸/g;
$self->note("NEXT LINE: >>$line<<");
}
sub note {
my ($self, $msg) = @_;
$self->_colorize_warn(["yellow"], "============ $msg");
}
sub info {
my ($self, $msg) = @_;
$self->_colorize_warn(["cyan"], "============ $msg");
}
sub got {
my ($self, $msg) = @_;
$self->_colorize_warn(["green"], "============ $msg");
}
sub _colorize_warn {
my ($self, $colors, $text) = @_;
require Term::ANSIColor;
warn Term::ANSIColor::colored($colors, $text), "\n";
}
sub debug_event {
my ($self, $event) = @_;
my $str = YAML::PP::Common::event_to_test_suite($event);
require Term::ANSIColor;
warn Term::ANSIColor::colored(["magenta"], "============ $str"), "\n";
}
sub debug_rules {
my ($self, $rules) = @_;
local $Data::Dumper::Maxdepth = 2;
$self->note("RULES:");
for my $rule ($rules) {
if (ref $rule eq 'ARRAY') {
my $first = $rule->[0];
if (ref $first eq 'SCALAR') {
$self->info("-> $$first");
}
else {
if (ref $first eq 'ARRAY') {
$first = $first->[0];
}
$self->info("TYPE $first");
}
}
else {
eval {
my @keys = sort keys %$rule;
$self->info("@keys");
};
}
}
}
sub debug_tokens {
my ($self, $tokens) = @_;
$tokens ||= $self->tokens;
require Term::ANSIColor;
for my $token (@$tokens) {
my $type = Term::ANSIColor::colored(["green"],
sprintf "%-22s L %2d C %2d ",
$token->{name}, $token->{line}, $token->{column} + 1
);
local $Data::Dumper::Useqq = 1;
local $Data::Dumper::Terse = 1;
require Data::Dumper;
my $str = Data::Dumper->Dump([$token->{value}], ['str']);
chomp $str;
$str =~ s/(^.|.$)/Term::ANSIColor::colored(['blue'], $1)/ge;
warn "$type$str\n";
}
}
sub highlight_yaml {
my ($self) = @_;
require YAML::PP::Highlight;
my $tokens = $self->tokens;
my $highlighted = YAML::PP::Highlight->ansicolored($tokens);
warn $highlighted;
}
sub exception {
my ($self, $msg, %args) = @_;
my $next = $self->lexer->next_tokens;
my $line = @$next ? $next->[0]->{line} : $self->lexer->line;
my $offset = @$next ? $next->[0]->{column} : $self->lexer->offset;
$offset++;
my $next_line = $self->lexer->next_line;
my $remaining = '';
if ($next_line) {
if ($self->lexer->offset > 0) {
$remaining = $next_line->[1] . $next_line->[2];
}
else {
$remaining = join '', @$next_line;
}
}
my $caller = $args{caller} || [ caller(0) ];
my $e = YAML::PP::Exception->new(
got => $args{got},
expected => $args{expected},
line => $line,
column => $offset,
msg => $msg,
next => $next,
where => $caller->[1] . ' line ' . $caller->[2],
yaml => $remaining,
);
croak $e;
}
sub expected {
my ($self, %args) = @_;
my $expected = $args{expected};
@$expected = sort grep { m/^[A-Z_]+$/ } @$expected;
my $got = $args{got}->{name};
my @caller = caller(0);
$self->exception("Expected (@$expected), but got $got",
caller => \@caller,
expected => $expected,
got => $args{got},
);
}
sub cb_tag {
my ($self, $token) = @_;
scripts/dex view on Meta::CPAN
}
elsif ($chomp eq '-') {
$trim = 1;
}
my $string = '';
if (not $keep) {
# remove trailing empty lines
while (@$lines) {
last if $lines->[-1] ne '';
pop @$lines;
}
}
if ($folded) {
my $prev = 'START';
for my $i (0 .. $#$lines) {
my $line = $lines->[ $i ];
my $type = $line eq ''
? 'EMPTY'
: $line =~ m/\A[ \t]/
? 'MORE'
: 'CONTENT';
if ($prev eq 'MORE' and $type eq 'EMPTY') {
$type = 'MORE';
}
elsif ($prev eq 'CONTENT') {
if ($type ne 'CONTENT') {
$string .= "\n";
}
elsif ($type eq 'CONTENT') {
$string .= ' ';
}
}
elsif ($prev eq 'START' and $type eq 'EMPTY') {
$string .= "\n";
$type = 'START';
}
elsif ($prev eq 'EMPTY' and $type ne 'CONTENT') {
$string .= "\n";
}
$string .= $line;
if ($type eq 'MORE' and $i < $#$lines) {
$string .= "\n";
}
$prev = $type;
}
$string .= "\n" if @$lines and not $trim;
}
else {
for my $i (0 .. $#$lines) {
$string .= $lines->[ $i ];
$string .= "\n" if ($i != $#$lines or not $trim);
}
}
TRACE and warn __PACKAGE__.':'.__LINE__.$".Data::Dumper->Dump([\$string], ['string']);
return $string;
}
sub render_multi_val {
my ($self, $multi) = @_;
my $string = '';
my $start = 1;
for my $line (@$multi) {
if (not $start) {
if ($line eq '') {
$string .= "\n";
$start = 1;
}
else {
$string .= " $line";
}
}
else {
$string .= $line;
$start = 0;
}
}
return $string;
}
1;
YAML_PP_RENDER
$fatpacked{"YAML/PP/Representer.pm"} = '#line '.(1+__LINE__).' "'.__FILE__."\"\n".<<'YAML_PP_REPRESENTER';
use strict;
use warnings;
package YAML::PP::Representer;
our $VERSION = '0.027'; # VERSION
use Scalar::Util qw/ reftype blessed refaddr /;
use YAML::PP::Common qw/
YAML_PLAIN_SCALAR_STYLE YAML_SINGLE_QUOTED_SCALAR_STYLE
YAML_DOUBLE_QUOTED_SCALAR_STYLE
YAML_ANY_SCALAR_STYLE
YAML_LITERAL_SCALAR_STYLE YAML_FOLDED_SCALAR_STYLE
YAML_FLOW_SEQUENCE_STYLE YAML_FLOW_MAPPING_STYLE
YAML_BLOCK_MAPPING_STYLE YAML_BLOCK_SEQUENCE_STYLE
PRESERVE_ORDER PRESERVE_SCALAR_STYLE PRESERVE_FLOW_STYLE PRESERVE_ALIAS
/;
use B;
sub new {
my ($class, %args) = @_;
my $preserve = delete $args{preserve} || 0;
if ($preserve == 1) {
$preserve = PRESERVE_ORDER | PRESERVE_SCALAR_STYLE | PRESERVE_FLOW_STYLE | PRESERVE_ALIAS;
}
my $self = bless {
schema => delete $args{schema},
preserve => $preserve,
}, $class;
if (keys %args) {
( run in 2.101 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )