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   119285 use YAML::Mo;
  34         72  
  34         237  
4             extends 'YAML::Dumper::Base';
5              
6 34     34   14061 use YAML::Dumper::Base;
  34         86  
  34         1062  
7 34     34   220 use YAML::Node;
  34         53  
  34         1476  
8 34     34   29160 use YAML::Types;
  34         85  
  34         1010  
9 34     34   209 use Scalar::Util qw();
  34         60  
  34         511  
10 34     34   173 use B ();
  34         65  
  34         423  
11 34     34   160 use Carp ();
  34         57  
  34         599  
12              
13             # Context constants
14 34     34   165 use constant KEY => 3;
  34         60  
  34         1857  
15 34     34   186 use constant BLESSED => 4;
  34         59  
  34         1485  
16 34     34   187 use constant FROMARRAY => 5;
  34         95  
  34         1766  
17 34     34   203 use constant VALUE => "\x07YAML\x07VALUE\x07";
  34         62  
  34         125413  
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 275 my $self = shift;
27 160         522 $self->stream('');
28 160         494 $self->document(0);
29 160         377 for my $document (@_) {
30 166         260 $self->{document}++;
31 166         524 $self->transferred({});
32 166         493 $self->id_refcnt({});
33 166         468 $self->id_anchor({});
34 166         488 $self->anchor(1);
35 166         514 $self->level(0);
36 166         467 $self->offset->[0] = 0 - $self->indent_width;
37 166         491 $self->_prewalk($document);
38 166         443 $self->_emit_header($document);
39 163         365 $self->_emit_node($document);
40             }
41 157         403 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   293 my $self = shift;
48 166         336 my ($node) = @_;
49 166 100 100     502 if (not $self->use_header and
50             $self->document == 1
51             ) {
52 4 100       26 $self->die('YAML_DUMP_ERR_NO_HEADER')
53             unless ref($node) =~ /^(HASH|ARRAY)$/;
54 3 100 66     24 $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         7 $self->headless(1);
60 1         2 return;
61             }
62 162         383 $self->{stream} .= '---';
63             # XXX Consider switching to 1.1 style
64 162 50       462 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   2012 my $self = shift;
74 1499         2437 my $stringify = $self->stringify;
75 1499         2943 my ($class, $type, $node_id) = $self->node_info(\$_[0], $stringify);
76              
77             # Handle typeglobs
78 1499 100       2825 if ($type eq 'GLOB') {
79 4         33 $self->transferred->{$node_id} =
80             YAML::Type::glob->yaml_dump($_[0]);
81 4         15 $self->_prewalk($self->transferred->{$node_id});
82 4         8 return;
83             }
84              
85             # Handle regexps
86 1495 100       2592 if (ref($_[0]) eq 'Regexp') {
87 11         24 return;
88             }
89              
90             # Handle Purity for scalars.
91             # XXX can't find a use case yet. Might be YAGNI.
92 1484 100       2246 if (not ref $_[0]) {
93 950 50       1782 $self->{id_refcnt}{$node_id}++ if $self->purity;
94 950         2083 return;
95             }
96              
97             # Make a copy of original
98 534         630 my $value = $_[0];
99 534         1025 ($class, $type, $node_id) = $self->node_info($value, $stringify);
100              
101             # Must be a stringified object.
102 534 100 66     1795 return if (ref($value) and not $type);
103              
104             # Look for things already transferred.
105 532 100       1183 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       24 : $self->node_info(\ $self->transferred->{$node_id}, $stringify);
109 11         29 $self->{id_refcnt}{$node_id}++;
110 11         32 return;
111             }
112              
113             # Handle code refs
114 521 100       1003 if ($type eq 'CODE') {
115 9         22 $self->transferred->{$node_id} = 'placeholder';
116             YAML::Type::code->yaml_dump(
117             $self->dump_code,
118             $_[0],
119 9         30 $self->transferred->{$node_id}
120             );
121             ($class, $type, $node_id) =
122 9         30 $self->node_info(\ $self->transferred->{$node_id}, $stringify);
123 9         63 $self->{id_refcnt}{$node_id}++;
124 9         27 return;
125             }
126              
127             # Handle blessed things
128 512 100       850 if (defined $class) {
129 34 100       280 if ($value->can('yaml_dump')) {
    100          
130 5         17 $value = $value->yaml_dump;
131             }
132             elsif ($type eq 'SCALAR') {
133 7         24 $self->transferred->{$node_id} = 'placeholder';
134             YAML::Type::blessed->yaml_dump
135 7         25 ($_[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         17 return;
140             }
141             else {
142 22         99 $value = YAML::Type::blessed->yaml_dump($value);
143             }
144 27         85 $self->transferred->{$node_id} = $value;
145 27         91 (undef, $type, $node_id) = $self->node_info($value, $stringify);
146             }
147              
148             # Handle YAML Blessed things
149 505         1812 require YAML;
150 505 100       1150 if (defined YAML->global_object()->{blessed_map}{$node_id}) {
151 4         10 $value = YAML->global_object()->{blessed_map}{$node_id};
152 4         8 $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         8 return;
156             }
157              
158             # Handle hard refs
159 501 100 100     1654 if ($type eq 'REF' or $type eq 'SCALAR') {
    100          
160 31         98 $value = YAML::Type::ref->yaml_dump($value);
161 31         74 $self->transferred->{$node_id} = $value;
162 31         72 (undef, $type, $node_id) = $self->node_info($value, $stringify);
163             }
164              
165             # Handle ref-to-glob's
166             elsif ($type eq 'GLOB') {
167 2         11 my $ref_ynode = $self->transferred->{$node_id} =
168             YAML::Type::ref->yaml_dump($value);
169              
170 2         7 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         5 return;
177             }
178              
179             # Increment ref count for node
180 499 100       1495 return if ++($self->{id_refcnt}{$node_id}) > 1;
181              
182             # Keep on walking
183 496 100       836 if ($type eq 'HASH') {
    50          
184             $self->_prewalk($value->{$_})
185 436         483 for keys %{$value};
  436         1869  
186 436         1026 return;
187             }
188             elsif ($type eq 'ARRAY') {
189             $self->_prewalk($_)
190 60         101 for @{$value};
  60         281  
191 60         124 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   1874 my $self = shift;
213 1492         1776 my ($type, $node_id);
214 1492         2329 my $ref = ref($_[0]);
215 1492 100       2324 if ($ref) {
216 536 100       889 if ($ref eq 'Regexp') {
217 11         22 $self->_emit(' !!perl/regexp');
218 11         30 $self->_emit_str("$_[0]");
219 11         26 return;
220             }
221 525         1034 (undef, $type, $node_id) = $self->node_info($_[0], $self->stringify);
222             }
223             else {
224 956   50     2411 $type = $ref || 'SCALAR';
225 956         1864 (undef, undef, $node_id) = $self->node_info(\$_[0], $self->stringify);
226             }
227              
228 1481         3092 my ($ynode, $tag) = ('') x 2;
229 1481         2481 my ($value, $context) = (@_, 0);
230              
231 1481 100       2877 if (defined $self->transferred->{$node_id}) {
    100          
232 95         188 $value = $self->transferred->{$node_id};
233 95         224 $ynode = ynode($value);
234 95 100       198 if (ref $value) {
235 77 50       287 $tag = defined $ynode ? $ynode->tag->short : '';
236 77         177 (undef, $type, $node_id) =
237             $self->node_info($value, $self->stringify);
238             }
239             else {
240 18         51 $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         45 \ $self->transferred->{$node_id},
246             $self->stringify
247             );
248             }
249             }
250             elsif ($ynode = ynode($value)) {
251 5         22 $tag = $ynode->tag->short;
252             }
253              
254 1481 100       2872 if ($self->use_aliases) {
255 1476   100     5088 $self->{id_refcnt}{$node_id} ||= 0;
256 1476 100       2822 if ($self->{id_refcnt}{$node_id} > 1) {
257 20 100       49 if (defined $self->{id_anchor}{$node_id}) {
258 11         28 $self->{stream} .= ' *' . $self->{id_anchor}{$node_id} . "\n";
259 11         44 return;
260             }
261 9         36 my $anchor = $self->anchor_prefix . $self->{anchor}++;
262 9         22 $self->{stream} .= ' &' . $anchor;
263 9         25 $self->{id_anchor}{$node_id} = $anchor;
264             }
265             }
266              
267 1470 100 100     3277 return $self->_emit_str("$value") # Stringified object
268             if ref($value) and not $type;
269 1468 100 100     3420 return $self->_emit_scalar($value, $tag)
270             if $type eq 'SCALAR' and $tag;
271 1452 100       2797 return $self->_emit_str($value)
272             if $type eq 'SCALAR';
273 500 100       1402 return $self->_emit_mapping($value, $tag, $node_id, $context)
274             if $type eq 'HASH';
275 60 50       216 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   585 my $self = shift;
284 440         779 my ($value, $tag, $node_id, $context) = @_;
285 440 100       753 $self->{stream} .= " !$tag" if $tag;
286              
287             # Sometimes 'keys' fails. Like on a bad tie implementation.
288 440         542 my $empty_hash = not(eval {keys %$value});
  440         942  
289 440 50       815 $self->warn('YAML_EMIT_WARN_KEYS', $@) if $@;
290 440 100       763 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     1072 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         41 $self->{stream} .= ' ';
299 20         39 $self->offset->[$self->level+1] = $self->offset->[$self->level] + 2;
300             }
301             else {
302 412         559 $context = 0;
303 412 50 33     752 $self->{stream} .= "\n"
304             unless $self->headless && not($self->headless(0));
305 412         827 $self->offset->[$self->level+1] =
306             $self->offset->[$self->level] + $self->indent_width;
307             }
308              
309 432         693 $self->{level}++;
310 432         536 my @keys;
311 432 100       781 if ($self->sort_keys == 1) {
    50          
    50          
312 431 100       746 if (ynode($value)) {
313 65         181 @keys = keys %$value;
314             }
315             else {
316 366         1574 @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         2 my %order = map { ($_, $i++) } @{$self->sort_keys};
  3         9  
  1         4  
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       1377 if (exists $value->{&VALUE}) {
337 36         110 for (my $i = 0; $i < @keys; $i++) {
338 36 50       105 if ($keys[$i] eq &VALUE) {
339 36         69 splice(@keys, $i, 1);
340 36         82 push @keys, &VALUE;
341 36         72 last;
342             }
343             }
344             }
345              
346 432         741 for my $key (@keys) {
347 1196         2320 $self->_emit_key($key, $context);
348 1196         1369 $context = 0;
349 1196         1523 $self->{stream} .= ':';
350 1196         2583 $self->_emit_node($value->{$key});
351             }
352 432         1089 $self->{level}--;
353             }
354              
355             # A YAML series is akin to a Perl array.
356             sub _emit_sequence {
357 60     60   97 my $self = shift;
358 60         124 my ($value, $tag) = @_;
359 60 100       146 $self->{stream} .= " !$tag" if $tag;
360              
361 60 100       159 return ($self->{stream} .= " []\n") if @$value == 0;
362              
363 56 100 66     180 $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     181 if ($self->inline_series and
      100        
368             @$value <= $self->inline_series and
369 8 100       33 not (scalar grep {ref or /\n/} @$value)
370             ) {
371 2         10 $self->{stream} =~ s/\n\Z/ /;
372 2         6 $self->{stream} .= '[';
373 2         7 for (my $i = 0; $i < @$value; $i++) {
374 5         12 $self->_emit_str($value->[$i], KEY);
375 5 100       7 last if $i == $#{$value};
  5         15  
376 3         7 $self->{stream} .= ', ';
377             }
378 2         5 $self->{stream} .= "]\n";
379 2         6 return;
380             }
381              
382 54         127 $self->offset->[$self->level + 1] =
383             $self->offset->[$self->level] + $self->indent_width;
384 54         113 $self->{level}++;
385 54         168 for my $val (@$value) {
386 133         304 $self->{stream} .= ' ' x $self->offset->[$self->level];
387 133         223 $self->{stream} .= '-';
388 133         375 $self->_emit_node($val, FROMARRAY);
389             }
390 54         151 $self->{level}--;
391             }
392              
393             # Emit a mapping key
394             sub _emit_key {
395 1196     1196   1420 my $self = shift;
396 1196         1736 my ($value, $context) = @_;
397 1196 100       2802 $self->{stream} .= ' ' x $self->offset->[$self->level]
398             unless $context == FROMARRAY;
399 1196         2246 $self->_emit_str($value, KEY);
400             }
401              
402             # Emit a blessed SCALAR
403             sub _emit_scalar {
404 16     16   35 my $self = shift;
405 16         44 my ($value, $tag) = @_;
406 16         47 $self->{stream} .= " !$tag";
407 16         44 $self->_emit_str($value, BLESSED);
408             }
409              
410             sub _emit {
411 4338     4338   4817 my $self = shift;
412 4338         8983 $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   2537 my $self = shift;
419 2182   100     3854 my $type = $_[1] || 0;
420              
421             # Use heuristics to find the best scalar emission style.
422 2182         3366 $self->offset->[$self->level + 1] =
423             $self->offset->[$self->level] + $self->indent_width;
424 2182         2960 $self->{level}++;
425              
426 2182 100       3285 my $sf = $type == KEY ? '' : ' ';
427 2182 100       2875 my $sb = $type == KEY ? '? ' : ' ';
428 2182 100       2940 my $ef = $type == KEY ? '' : "\n";
429 2182         2272 my $eb = "\n";
430              
431 2182         2554 while (1) {
432 2182 100       3221 $self->_emit($sf),
433             $self->_emit_plain($_[0]),
434             $self->_emit($ef), last
435             if not defined $_[0];
436 2178 100       3293 $self->_emit($sf, '=', $ef), last
437             if $_[0] eq VALUE;
438 2141 100       7232 $self->_emit($sf),
439             $self->_emit_double($_[0]),
440             $self->_emit($ef), last
441             if $_[0] =~ /$ESCAPE_CHAR/;
442 2140 100       3896 if ($_[0] =~ /\n/) {
443 28 100       131 $self->_emit($sb),
444             $self->_emit_block($LIT_CHAR, $_[0]),
445             $self->_emit($eb), last
446             if $self->use_block;
447 27 50       112 Carp::cluck "[YAML] \$UseFold is no longer supported"
448             if $self->use_fold;
449 27 100       97 $self->_emit($sf),
450             $self->_emit_double($_[0]),
451             $self->_emit($ef), last
452             if length $_[0] <= 30;
453 20 100       91 $self->_emit($sf),
454             $self->_emit_double($_[0]),
455             $self->_emit($ef), last
456             if $_[0] !~ /\n\s*\S/;
457 18         54 $self->_emit($sb),
458             $self->_emit_block($LIT_CHAR, $_[0]),
459             $self->_emit($eb), last;
460             }
461 2112 100       3431 $self->_emit($sf),
462             $self->_emit_number($_[0]),
463             $self->_emit($ef), last
464             if $self->is_literal_number($_[0]);
465 2048 100       3853 $self->_emit($sf),
466             $self->_emit_plain($_[0]),
467             $self->_emit($ef), last
468             if $self->is_valid_plain($_[0]);
469 49 100       170 $self->_emit($sf),
470             $self->_emit_double($_[0]),
471             $self->_emit($ef), last
472             if $_[0] =~ /'/;
473 48         125 $self->_emit($sf),
474             $self->_emit_single($_[0]),
475             $self->_emit($ef);
476 48         73 last;
477             }
478              
479 2182         3273 $self->{level}--;
480              
481 2182         4049 return;
482             }
483              
484             sub is_literal_number {
485 2115     2115 0 2538 my $self = shift;
486             # Stolen from JSON::Tiny
487 2115   66     9415 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   95 my $self = shift;
493 64         119 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 2299 my $self = shift;
499 2048 100       3880 return 0 unless length $_[0];
500 2042 100 100     3545 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       4516 return 0 if $_[0] =~ /^[\s\{\[\~\`\'\"\!\@\#\>\|\%\&\?\*\^]/;
503 2019 100       3477 return 0 if $_[0] =~ /[\{\[\]\},]/;
504 2010 100       3163 return 0 if $_[0] =~ /[:\-\?]\s/;
505 2006 100       3009 return 0 if $_[0] =~ /\s#/;
506 2005 50       3015 return 0 if $_[0] =~ /\:(\s|$)/;
507 2005 100       3503 return 0 if $_[0] =~ /[\s\|\>]$/;
508 2001 100       2935 return 0 if $_[0] eq '-';
509 2000 100       2592 return 0 if $_[0] eq '=';
510 1999         4182 return 1;
511             }
512              
513             sub _emit_block {
514 19     19   33 my $self = shift;
515 19         53 my ($indicator, $value) = @_;
516 19         36 $self->{stream} .= $indicator;
517 19         399 $value =~ /(\n*)\Z/;
518 19 100       93 my $chomp = length $1 ? (length $1 > 1) ? '+' : '' : '-';
    100          
519 19 50       48 $value = '~' if not defined $value;
520 19         36 $self->{stream} .= $chomp;
521 19 50       68 $self->{stream} .= $self->indent_width if $value =~ /^\s/;
522 19         113 $self->{stream} .= $self->indent($value);
523             }
524              
525             # Plain means that the scalar is unquoted.
526             sub _emit_plain {
527 2067     2067   2472 my $self = shift;
528 2067 100       4154 $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         37 (my $escaped = $self->escape($_[0])) =~ s/"/\\"/g;
535 11         1708 $self->{stream} .= qq{"$escaped"};
536             }
537              
538             # Single quoting is for single lined unescaped strings.
539             sub _emit_single {
540 48     48   82 my $self = shift;
541 48         133 my $item = shift;
542 48         96 $item =~ s{'}{''}g;
543 48         176 $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 32 my $self = shift;
553 19         37 my ($text) = @_;
554 19 50       46 return $text unless length $text;
555 19         104 $text =~ s/\n\Z//;
556 19         57 my $indent = ' ' x $self->offset->[$self->level];
557 19         148 $text =~ s/^/$indent/gm;
558 19         51 $text = "\n$text";
559 19         84 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 21 my $self = shift;
572 11         25 my ($text) = @_;
573 11         68 $text =~ s/\\/\\\\/g;
574 11         1812 $text =~ s/([\x00-\x1f])/$escapes[ord($1)]/ge;
  17         70  
575 11         10603 return $text;
576             }
577              
578             1;