File Coverage

blib/lib/YAML/Dumper.pm
Criterion Covered Total %
statement 300 306 98.0
branch 155 172 90.1
condition 46 57 80.7
subroutine 30 30 100.0
pod 0 5 0.0
total 531 570 93.1


line stmt bran cond sub pod time code
1             package YAML::Dumper;
2              
3 34     34   95966 use YAML::Mo;
  34         69  
  34         254  
4             extends 'YAML::Dumper::Base';
5              
6 34     34   14692 use YAML::Dumper::Base;
  34         98  
  34         1114  
7 34     34   295 use YAML::Node;
  34         66  
  34         1388  
8 34     34   12770 use YAML::Types;
  34         89  
  34         989  
9 34     34   236 use Scalar::Util qw();
  34         71  
  34         568  
10 34     34   166 use B ();
  34         62  
  34         437  
11 34     34   156 use Carp ();
  34         56  
  34         643  
12              
13             # Context constants
14 34     34   153 use constant KEY => 3;
  34         61  
  34         1874  
15 34     34   186 use constant BLESSED => 4;
  34         71  
  34         1540  
16 34     34   198 use constant FROMARRAY => 5;
  34         83  
  34         1834  
17 34     34   204 use constant VALUE => "\x07YAML\x07VALUE\x07";
  34         61  
  34         128839  
18              
19             # Common YAML character sets
20             my $ESCAPE_CHAR = '[\\x00-\\x08\\x0b-\\x0d\\x0e-\\x1f]';
21             my $LIT_CHAR = '|';
22              
23             #==============================================================================
24             # OO version of Dump. YAML->new->dump($foo);
25             sub dump {
26 160     160 0 297 my $self = shift;
27 160         503 $self->stream('');
28 160         535 $self->document(0);
29 160         436 for my $document (@_) {
30 166         275 $self->{document}++;
31 166         515 $self->transferred({});
32 166         525 $self->id_refcnt({});
33 166         475 $self->id_anchor({});
34 166         484 $self->anchor(1);
35 166         496 $self->level(0);
36 166         477 $self->offset->[0] = 0 - $self->indent_width;
37 166         546 $self->_prewalk($document);
38 166         576 $self->_emit_header($document);
39 163         385 $self->_emit_node($document);
40             }
41 157         437 return $self->stream;
42             }
43              
44             # Every YAML document in the stream must begin with a YAML header, unless
45             # there is only a single document and the user requests "no header".
46             sub _emit_header {
47 166     166   276 my $self = shift;
48 166         311 my ($node) = @_;
49 166 100 100     528 if (not $self->use_header and
50             $self->document == 1
51             ) {
52 4 100       25 $self->die('YAML_DUMP_ERR_NO_HEADER')
53             unless ref($node) =~ /^(HASH|ARRAY)$/;
54 3 100 66     16 $self->die('YAML_DUMP_ERR_NO_HEADER')
55             if ref($node) eq 'HASH' and keys(%$node) == 0;
56 2 100 66     30 $self->die('YAML_DUMP_ERR_NO_HEADER')
57             if ref($node) eq 'ARRAY' and @$node == 0;
58             # XXX Also croak if aliased, blessed, or ynode
59 1         6 $self->headless(1);
60 1         2 return;
61             }
62 162         407 $self->{stream} .= '---';
63             # XXX Consider switching to 1.1 style
64 162 50       495 if ($self->use_version) {
65             # $self->{stream} .= " #YAML:1.0";
66             }
67             }
68              
69             # Walk the tree to be dumped and keep track of its reference counts.
70             # This function is where the Dumper does all its work. All type
71             # transfers happen here.
72             sub _prewalk {
73 1499     1499   2029 my $self = shift;
74 1499         2522 my $stringify = $self->stringify;
75 1499         2984 my ($class, $type, $node_id) = $self->node_info(\$_[0], $stringify);
76              
77             # Handle typeglobs
78 1499 100       2870 if ($type eq 'GLOB') {
79 4         23 $self->transferred->{$node_id} =
80             YAML::Type::glob->yaml_dump($_[0]);
81 4         11 $self->_prewalk($self->transferred->{$node_id});
82 4         8 return;
83             }
84              
85             # Handle regexps
86 1495 100       2694 if (ref($_[0]) eq 'Regexp') {
87 11         22 return;
88             }
89              
90             # Handle Purity for scalars.
91             # XXX can't find a use case yet. Might be YAGNI.
92 1484 100       2266 if (not ref $_[0]) {
93 950 50       1925 $self->{id_refcnt}{$node_id}++ if $self->purity;
94 950         2159 return;
95             }
96              
97             # Make a copy of original
98 534         648 my $value = $_[0];
99 534         1131 ($class, $type, $node_id) = $self->node_info($value, $stringify);
100              
101             # Must be a stringified object.
102 534 100 66     1836 return if (ref($value) and not $type);
103              
104             # Look for things already transferred.
105 532 100       1139 if ($self->transferred->{$node_id}) {
106             (undef, undef, $node_id) = (ref $self->transferred->{$node_id})
107             ? $self->node_info($self->transferred->{$node_id}, $stringify)
108 11 100       29 : $self->node_info(\ $self->transferred->{$node_id}, $stringify);
109 11         32 $self->{id_refcnt}{$node_id}++;
110 11         29 return;
111             }
112              
113             # Handle code refs
114 521 100       998 if ($type eq 'CODE') {
115 9         25 $self->transferred->{$node_id} = 'placeholder';
116             YAML::Type::code->yaml_dump(
117             $self->dump_code,
118             $_[0],
119 9         31 $self->transferred->{$node_id}
120             );
121             ($class, $type, $node_id) =
122 9         40 $self->node_info(\ $self->transferred->{$node_id}, $stringify);
123 9         32 $self->{id_refcnt}{$node_id}++;
124 9         24 return;
125             }
126              
127             # Handle blessed things
128 512 100       873 if (defined $class) {
129 34 100       300 if ($value->can('yaml_dump')) {
    100          
130 5         19 $value = $value->yaml_dump;
131             }
132             elsif ($type eq 'SCALAR') {
133 7         26 $self->transferred->{$node_id} = 'placeholder';
134             YAML::Type::blessed->yaml_dump
135 7         22 ($_[0], $self->transferred->{$node_id});
136             ($class, $type, $node_id) =
137 7         34 $self->node_info(\ $self->transferred->{$node_id}, $stringify);
138 7         26 $self->{id_refcnt}{$node_id}++;
139 7         18 return;
140             }
141             else {
142 22         106 $value = YAML::Type::blessed->yaml_dump($value);
143             }
144 27         96 $self->transferred->{$node_id} = $value;
145 27         72 (undef, $type, $node_id) = $self->node_info($value, $stringify);
146             }
147              
148             # Handle YAML Blessed things
149 505         1967 require YAML;
150 505 100       1169 if (defined YAML->global_object()->{blessed_map}{$node_id}) {
151 4         10 $value = YAML->global_object()->{blessed_map}{$node_id};
152 4         10 $self->transferred->{$node_id} = $value;
153 4         10 ($class, $type, $node_id) = $self->node_info($value, $stringify);
154 4         14 $self->_prewalk($value);
155 4         6 return;
156             }
157              
158             # Handle hard refs
159 501 100 100     1721 if ($type eq 'REF' or $type eq 'SCALAR') {
    100          
160 31         98 $value = YAML::Type::ref->yaml_dump($value);
161 31         79 $self->transferred->{$node_id} = $value;
162 31         70 (undef, $type, $node_id) = $self->node_info($value, $stringify);
163             }
164              
165             # Handle ref-to-glob's
166             elsif ($type eq 'GLOB') {
167 2         13 my $ref_ynode = $self->transferred->{$node_id} =
168             YAML::Type::ref->yaml_dump($value);
169              
170 2         9 my $glob_ynode = $ref_ynode->{&VALUE} =
171             YAML::Type::glob->yaml_dump($$value);
172              
173 2         18 (undef, undef, $node_id) = $self->node_info($glob_ynode, $stringify);
174 2         8 $self->transferred->{$node_id} = $glob_ynode;
175 2         11 $self->_prewalk($glob_ynode);
176 2         4 return;
177             }
178              
179             # Increment ref count for node
180 499 100       1474 return if ++($self->{id_refcnt}{$node_id}) > 1;
181              
182             # Keep on walking
183 496 100       892 if ($type eq 'HASH') {
    50          
184             $self->_prewalk($value->{$_})
185 436         504 for keys %{$value};
  436         1941  
186 436         1066 return;
187             }
188             elsif ($type eq 'ARRAY') {
189             $self->_prewalk($_)
190 60         99 for @{$value};
  60         291  
191 60         130 return;
192             }
193              
194             # Unknown type. Need to know about it.
195 0         0 $self->warn(<<"...");
196             YAML::Dumper can't handle dumping this type of data.
197             Please report this to the author.
198              
199             id: $node_id
200             type: $type
201             class: $class
202             value: $value
203              
204             ...
205              
206 0         0 return;
207             }
208              
209             # Every data element and sub data element is a node.
210             # Everything emitted goes through this function.
211             sub _emit_node {
212 1492     1492   1831 my $self = shift;
213 1492         1775 my ($type, $node_id);
214 1492         2327 my $ref = ref($_[0]);
215 1492 100       2325 if ($ref) {
216 536 100       915 if ($ref eq 'Regexp') {
217 11         26 $self->_emit(' !!perl/regexp');
218 11         31 $self->_emit_str("$_[0]");
219 11         27 return;
220             }
221 525         1087 (undef, $type, $node_id) = $self->node_info($_[0], $self->stringify);
222             }
223             else {
224 956   50     2516 $type = $ref || 'SCALAR';
225 956         1973 (undef, undef, $node_id) = $self->node_info(\$_[0], $self->stringify);
226             }
227              
228 1481         3050 my ($ynode, $tag) = ('') x 2;
229 1481         2491 my ($value, $context) = (@_, 0);
230              
231 1481 100       2916 if (defined $self->transferred->{$node_id}) {
    100          
232 95         199 $value = $self->transferred->{$node_id};
233 95         230 $ynode = ynode($value);
234 95 100       204 if (ref $value) {
235 77 50       304 $tag = defined $ynode ? $ynode->tag->short : '';
236 77         190 (undef, $type, $node_id) =
237             $self->node_info($value, $self->stringify);
238             }
239             else {
240 18         54 $ynode = ynode($self->transferred->{$node_id});
241 18 50       93 $tag = defined $ynode ? $ynode->tag->short : '';
242 18         37 $type = 'SCALAR';
243             (undef, undef, $node_id) =
244             $self->node_info(
245 18         46 \ $self->transferred->{$node_id},
246             $self->stringify
247             );
248             }
249             }
250             elsif ($ynode = ynode($value)) {
251 5         19 $tag = $ynode->tag->short;
252             }
253              
254 1481 100       3132 if ($self->use_aliases) {
255 1476   100     5165 $self->{id_refcnt}{$node_id} ||= 0;
256 1476 100       2718 if ($self->{id_refcnt}{$node_id} > 1) {
257 20 100       50 if (defined $self->{id_anchor}{$node_id}) {
258 11         34 $self->{stream} .= ' *' . $self->{id_anchor}{$node_id} . "\n";
259 11         41 return;
260             }
261 9         40 my $anchor = $self->anchor_prefix . $self->{anchor}++;
262 9         24 $self->{stream} .= ' &' . $anchor;
263 9         25 $self->{id_anchor}{$node_id} = $anchor;
264             }
265             }
266              
267 1470 100 100     3377 return $self->_emit_str("$value") # Stringified object
268             if ref($value) and not $type;
269 1468 100 100     3526 return $self->_emit_scalar($value, $tag)
270             if $type eq 'SCALAR' and $tag;
271 1452 100       2691 return $self->_emit_str($value)
272             if $type eq 'SCALAR';
273 500 100       1438 return $self->_emit_mapping($value, $tag, $node_id, $context)
274             if $type eq 'HASH';
275 60 50       227 return $self->_emit_sequence($value, $tag)
276             if $type eq 'ARRAY';
277 0         0 $self->warn('YAML_DUMP_WARN_BAD_NODE_TYPE', $type);
278 0         0 return $self->_emit_str("$value");
279             }
280              
281             # A YAML mapping is akin to a Perl hash.
282             sub _emit_mapping {
283 440     440   630 my $self = shift;
284 440         776 my ($value, $tag, $node_id, $context) = @_;
285 440 100       763 $self->{stream} .= " !$tag" if $tag;
286              
287             # Sometimes 'keys' fails. Like on a bad tie implementation.
288 440         571 my $empty_hash = not(eval {keys %$value});
  440         907  
289 440 50       897 $self->warn('YAML_EMIT_WARN_KEYS', $@) if $@;
290 440 100       700 return ($self->{stream} .= " {}\n") if $empty_hash;
291              
292             # If CompressSeries is on (default) and legal is this context, then
293             # use it and make the indent level be 2 for this node.
294 432 100 100     1067 if ($context == FROMARRAY and
      66        
      100        
295             $self->compress_series and
296             not (defined $self->{id_anchor}{$node_id} or $tag or $empty_hash)
297             ) {
298 20         44 $self->{stream} .= ' ';
299 20         47 $self->offset->[$self->level+1] = $self->offset->[$self->level] + 2;
300             }
301             else {
302 412         555 $context = 0;
303 412 50 33     828 $self->{stream} .= "\n"
304             unless $self->headless && not($self->headless(0));
305 412         853 $self->offset->[$self->level+1] =
306             $self->offset->[$self->level] + $self->indent_width;
307             }
308              
309 432         625 $self->{level}++;
310 432         567 my @keys;
311 432 100       823 if ($self->sort_keys == 1) {
    50          
    50          
312 431 100       746 if (ynode($value)) {
313 65         191 @keys = keys %$value;
314             }
315             else {
316 366         1635 @keys = sort keys %$value;
317             }
318             }
319             elsif ($self->sort_keys == 2) {
320 0         0 @keys = sort keys %$value;
321             }
322             # XXX This is hackish but sometimes handy. Not sure whether to leave it in.
323             elsif (ref($self->sort_keys) eq 'ARRAY') {
324 1         3 my $i = 1;
325 1         3 my %order = map { ($_, $i++) } @{$self->sort_keys};
  3         10  
  1         3  
326             @keys = sort {
327 1         6 (defined $order{$a} and defined $order{$b})
328 3 50 33     17 ? ($order{$a} <=> $order{$b})
329             : ($a cmp $b);
330             } keys %$value;
331             }
332             else {
333 0         0 @keys = keys %$value;
334             }
335             # Force the YAML::VALUE ('=') key to sort last.
336 432 100       1417 if (exists $value->{&VALUE}) {
337 36         111 for (my $i = 0; $i < @keys; $i++) {
338 36 50       110 if ($keys[$i] eq &VALUE) {
339 36         79 splice(@keys, $i, 1);
340 36         90 push @keys, &VALUE;
341 36         55 last;
342             }
343             }
344             }
345              
346 432         784 for my $key (@keys) {
347 1196         2440 $self->_emit_key($key, $context);
348 1196         1379 $context = 0;
349 1196         1633 $self->{stream} .= ':';
350 1196         2747 $self->_emit_node($value->{$key});
351             }
352 432         1060 $self->{level}--;
353             }
354              
355             # A YAML series is akin to a Perl array.
356             sub _emit_sequence {
357 60     60   112 my $self = shift;
358 60         122 my ($value, $tag) = @_;
359 60 100       136 $self->{stream} .= " !$tag" if $tag;
360              
361 60 100       155 return ($self->{stream} .= " []\n") if @$value == 0;
362              
363 56 100 66     205 $self->{stream} .= "\n"
364             unless $self->headless && not($self->headless(0));
365              
366             # XXX Really crufty feature. Better implemented by ynodes.
367 56 100 100     194 if ($self->inline_series and
      100        
368             @$value <= $self->inline_series and
369 8 100       34 not (scalar grep {ref or /\n/} @$value)
370             ) {
371 2         12 $self->{stream} =~ s/\n\Z/ /;
372 2         5 $self->{stream} .= '[';
373 2         8 for (my $i = 0; $i < @$value; $i++) {
374 5         13 $self->_emit_str($value->[$i], KEY);
375 5 100       8 last if $i == $#{$value};
  5         13  
376 3         7 $self->{stream} .= ', ';
377             }
378 2         4 $self->{stream} .= "]\n";
379 2         7 return;
380             }
381              
382 54         147 $self->offset->[$self->level + 1] =
383             $self->offset->[$self->level] + $self->indent_width;
384 54         155 $self->{level}++;
385 54         125 for my $val (@$value) {
386 133         300 $self->{stream} .= ' ' x $self->offset->[$self->level];
387 133         223 $self->{stream} .= '-';
388 133         382 $self->_emit_node($val, FROMARRAY);
389             }
390 54         161 $self->{level}--;
391             }
392              
393             # Emit a mapping key
394             sub _emit_key {
395 1196     1196   1689 my $self = shift;
396 1196         1864 my ($value, $context) = @_;
397 1196 100       2850 $self->{stream} .= ' ' x $self->offset->[$self->level]
398             unless $context == FROMARRAY;
399 1196         2249 $self->_emit_str($value, KEY);
400             }
401              
402             # Emit a blessed SCALAR
403             sub _emit_scalar {
404 16     16   45 my $self = shift;
405 16         38 my ($value, $tag) = @_;
406 16         48 $self->{stream} .= " !$tag";
407 16         47 $self->_emit_str($value, BLESSED);
408             }
409              
410             sub _emit {
411 4338     4338   4913 my $self = shift;
412 4338         8748 $self->{stream} .= join '', @_;
413             }
414              
415             # Emit a string value. YAML has many scalar styles. This routine attempts to
416             # guess the best style for the text.
417             sub _emit_str {
418 2182     2182   2523 my $self = shift;
419 2182   100     3927 my $type = $_[1] || 0;
420              
421             # Use heuristics to find the best scalar emission style.
422 2182         3625 $self->offset->[$self->level + 1] =
423             $self->offset->[$self->level] + $self->indent_width;
424 2182         3068 $self->{level}++;
425              
426 2182 100       3449 my $sf = $type == KEY ? '' : ' ';
427 2182 100       3142 my $sb = $type == KEY ? '? ' : ' ';
428 2182 100       2982 my $ef = $type == KEY ? '' : "\n";
429 2182         2490 my $eb = "\n";
430              
431 2182         2481 while (1) {
432 2182 100       3311 $self->_emit($sf),
433             $self->_emit_plain($_[0]),
434             $self->_emit($ef), last
435             if not defined $_[0];
436 2178 100       3291 $self->_emit($sf, '=', $ef), last
437             if $_[0] eq VALUE;
438 2141 100       7563 $self->_emit($sf),
439             $self->_emit_double($_[0]),
440             $self->_emit($ef), last
441             if $_[0] =~ /$ESCAPE_CHAR/;
442 2140 100       4091 if ($_[0] =~ /\n/) {
443 28 100       134 $self->_emit($sb),
444             $self->_emit_block($LIT_CHAR, $_[0]),
445             $self->_emit($eb), last
446             if $self->use_block;
447 27 50       116 Carp::cluck "[YAML] \$UseFold is no longer supported"
448             if $self->use_fold;
449 27 100       92 $self->_emit($sf),
450             $self->_emit_double($_[0]),
451             $self->_emit($ef), last
452             if length $_[0] <= 30;
453 20 100       90 $self->_emit($sf),
454             $self->_emit_double($_[0]),
455             $self->_emit($ef), last
456             if $_[0] !~ /\n\s*\S/;
457 18         77 $self->_emit($sb),
458             $self->_emit_block($LIT_CHAR, $_[0]),
459             $self->_emit($eb), last;
460             }
461 2112 100       3474 $self->_emit($sf),
462             $self->_emit_number($_[0]),
463             $self->_emit($ef), last
464             if $self->is_literal_number($_[0]);
465 2048 100       3405 $self->_emit($sf),
466             $self->_emit_plain($_[0]),
467             $self->_emit($ef), last
468             if $self->is_valid_plain($_[0]);
469 49 100       174 $self->_emit($sf),
470             $self->_emit_double($_[0]),
471             $self->_emit($ef), last
472             if $_[0] =~ /'/;
473 48         142 $self->_emit($sf),
474             $self->_emit_single($_[0]),
475             $self->_emit($ef);
476 48         73 last;
477             }
478              
479 2182         3589 $self->{level}--;
480              
481 2182         4019 return;
482             }
483              
484             sub is_literal_number {
485 2115     2115 0 2523 my $self = shift;
486             # Stolen from JSON::Tiny
487 2115   66     9564 return B::svref_2object(\$_[0])->FLAGS & (B::SVp_IOK | B::SVp_NOK)
488             && 0 + $_[0] eq $_[0];
489             }
490              
491             sub _emit_number {
492 64     64   97 my $self = shift;
493 64         124 return $self->_emit_plain($_[0]);
494             }
495              
496             # Check whether or not a scalar should be emitted as an plain scalar.
497             sub is_valid_plain {
498 2048     2048 0 2254 my $self = shift;
499 2048 100       3774 return 0 unless length $_[0];
500 2042 100 100     3385 return 0 if $self->quote_numeric_strings and Scalar::Util::looks_like_number($_[0]);
501             # refer to YAML::Loader::parse_inline_simple()
502 2036 100       4676 return 0 if $_[0] =~ /^[\s\{\[\~\`\'\"\!\@\#\>\|\%\&\?\*\^]/;
503 2019 100       3554 return 0 if $_[0] =~ /[\{\[\]\},]/;
504 2010 100       3220 return 0 if $_[0] =~ /[:\-\?]\s/;
505 2006 100       3283 return 0 if $_[0] =~ /\s#/;
506 2005 50       3127 return 0 if $_[0] =~ /\:(\s|$)/;
507 2005 100       3609 return 0 if $_[0] =~ /[\s\|\>]$/;
508 2001 100       3004 return 0 if $_[0] eq '-';
509 2000 100       2654 return 0 if $_[0] eq '=';
510 1999         4185 return 1;
511             }
512              
513             sub _emit_block {
514 19     19   34 my $self = shift;
515 19         39 my ($indicator, $value) = @_;
516 19         37 $self->{stream} .= $indicator;
517 19         424 $value =~ /(\n*)\Z/;
518 19 100       94 my $chomp = length $1 ? (length $1 > 1) ? '+' : '' : '-';
    100          
519 19 50       86 $value = '~' if not defined $value;
520 19         36 $self->{stream} .= $chomp;
521 19 50       83 $self->{stream} .= $self->indent_width if $value =~ /^\s/;
522 19         124 $self->{stream} .= $self->indent($value);
523             }
524              
525             # Plain means that the scalar is unquoted.
526             sub _emit_plain {
527 2067     2067   2526 my $self = shift;
528 2067 100       4420 $self->{stream} .= defined $_[0] ? $_[0] : '~';
529             }
530              
531             # Double quoting is for single lined escaped strings.
532             sub _emit_double {
533 11     11   22 my $self = shift;
534 11         34 (my $escaped = $self->escape($_[0])) =~ s/"/\\"/g;
535 11         1510 $self->{stream} .= qq{"$escaped"};
536             }
537              
538             # Single quoting is for single lined unescaped strings.
539             sub _emit_single {
540 48     48   96 my $self = shift;
541 48         128 my $item = shift;
542 48         100 $item =~ s{'}{''}g;
543 48         187 $self->{stream} .= "'$item'";
544             }
545              
546             #==============================================================================
547             # Utility subroutines.
548             #==============================================================================
549              
550             # Indent a scalar to the current indentation level.
551             sub indent {
552 19     19 0 37 my $self = shift;
553 19         37 my ($text) = @_;
554 19 50       51 return $text unless length $text;
555 19         68 $text =~ s/\n\Z//;
556 19         54 my $indent = ' ' x $self->offset->[$self->level];
557 19         137 $text =~ s/^/$indent/gm;
558 19         47 $text = "\n$text";
559 19         73 return $text;
560             }
561              
562             # Escapes for unprintable characters
563             my @escapes = qw(\0 \x01 \x02 \x03 \x04 \x05 \x06 \a
564             \x08 \t \n \v \f \r \x0e \x0f
565             \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17
566             \x18 \x19 \x1a \e \x1c \x1d \x1e \x1f
567             );
568              
569             # Escape the unprintable characters
570             sub escape {
571 11     11 0 26 my $self = shift;
572 11         27 my ($text) = @_;
573 11         68 $text =~ s/\\/\\\\/g;
574 11         1789 $text =~ s/([\x00-\x1f])/$escapes[ord($1)]/ge;
  17         69  
575 11         10427 return $text;
576             }
577              
578             1;