File Coverage

blib/lib/YAML/PP/Dumper.pm
Criterion Covered Total %
statement 155 158 98.1
branch 57 64 89.0
condition 20 25 80.0
subroutine 23 24 95.8
pod 0 12 0.0
total 255 283 90.1


line stmt bran cond sub pod time code
1 35     35   141496 use strict;
  35         92  
  35         1130  
2 35     35   194 use warnings;
  35         67  
  35         1920  
3             package YAML::PP::Dumper;
4              
5             our $VERSION = '0.036_002'; # TRIAL VERSION
6              
7 35     35   221 use Scalar::Util qw/ blessed refaddr reftype /;
  35         79  
  35         1916  
8 35     35   1281 use YAML::PP;
  35         102  
  35         939  
9 35     35   18121 use YAML::PP::Emitter;
  35         116  
  35         1343  
10 35     35   15855 use YAML::PP::Representer;
  35         115  
  35         1082  
11 35     35   13850 use YAML::PP::Writer;
  35         113  
  35         1054  
12 35     35   13984 use YAML::PP::Writer::File;
  35         90  
  35         1300  
13 35         65396 use YAML::PP::Common qw/
14             YAML_PLAIN_SCALAR_STYLE YAML_SINGLE_QUOTED_SCALAR_STYLE
15             YAML_DOUBLE_QUOTED_SCALAR_STYLE
16             YAML_ANY_SCALAR_STYLE
17             YAML_LITERAL_SCALAR_STYLE YAML_FOLDED_SCALAR_STYLE
18             YAML_FLOW_SEQUENCE_STYLE YAML_FLOW_MAPPING_STYLE
19             YAML_BLOCK_MAPPING_STYLE YAML_BLOCK_SEQUENCE_STYLE
20 35     35   260 /;
  35         91  
21              
22             sub new {
23 746     746 0 3070 my ($class, %args) = @_;
24              
25 746         1442 my $header = delete $args{header};
26 746 100       1794 $header = 1 unless defined $header;
27 746         1229 my $footer = delete $args{footer};
28 746 100       1609 $footer = 0 unless defined $footer;
29 746         1158 my $version_directive = delete $args{version_directive};
30 746         1144 my $preserve = delete $args{preserve};
31              
32 746   66     1914 my $schema = delete $args{schema} || YAML::PP->default_schema(
33             boolean => 'perl',
34             );
35              
36 746   66     1738 my $emitter = delete $args{emitter} || YAML::PP::Emitter->new;
37 746 100       2338 unless (blessed($emitter)) {
38 745         3741 $emitter = YAML::PP::Emitter->new(
39             %$emitter
40             );
41             }
42              
43 746 50       2005 if (keys %args) {
44 0         0 die "Unexpected arguments: " . join ', ', sort keys %args;
45             }
46 746         2712 my $self = bless {
47             representer => YAML::PP::Representer->new(
48             schema => $schema,
49             preserve => $preserve,
50             ),
51             version_directive => $version_directive,
52             emitter => $emitter,
53             seen => {},
54             anchors => {},
55             anchor_num => 0,
56             header => $header,
57             footer => $footer,
58             }, $class;
59 746         1981 return $self;
60             }
61              
62             sub clone {
63 9     9 0 18 my ($self) = @_;
64 9         19 my $clone = {
65             representer => $self->representer->clone,
66             emitter => $self->emitter->clone,
67             version_directive => $self->version_directive,
68             seen => {},
69             anchors => {},
70             anchor_num => 0,
71             header => $self->header,
72             footer => $self->footer,
73             };
74 9         39 return bless $clone, ref $self;
75             }
76              
77             sub init {
78 1542     1542 0 2644 my ($self) = @_;
79 1542         3274 $self->{seen} = {};
80 1542         2804 $self->{anchors} = {};
81 1542         2519 $self->{anchor_num} = 0;
82             }
83              
84 16587     16587 0 58167 sub emitter { return $_[0]->{emitter} }
85 3983     3983 0 11315 sub representer { return $_[0]->{representer} }
86 0     0 0 0 sub set_representer { $_[0]->{representer} = $_[1] }
87 1487     1487 0 4686 sub header { return $_[0]->{header} }
88 1550     1550 0 3481 sub footer { return $_[0]->{footer} }
89 1551     1551 0 3634 sub version_directive { return $_[0]->{version_directive} }
90              
91             sub dump {
92 1484     1484 0 2998 my ($self, @docs) = @_;
93 1484         2608 $self->emitter->init;
94              
95 1483         2768 $self->emitter->stream_start_event({});
96              
97 1483         4612 for my $i (0 .. $#docs) {
98 1542   100     5021 my $header_implicit = ($i == 0 and not $self->header);
99 1542         4316 my %args = (
100             implicit => $header_implicit,
101             );
102 1542 100       3261 if ($self->version_directive) {
103 18         36 my ($major, $minor) = split m/\./, $self->representer->schema->yaml_version;
104 18         81 $args{version_directive} = { major => $major, minor => $minor };
105             }
106 1542         2791 $self->emitter->document_start_event( \%args );
107 1542         4130 $self->init;
108 1542         4564 $self->_check_references($docs[ $i ]);
109 1542         4592 $self->_dump_node($docs[ $i ]);
110 1541         4138 my $footer_implicit = (not $self->footer);
111 1541         3109 $self->emitter->document_end_event({ implicit => $footer_implicit });
112             }
113              
114 1482         3214 $self->emitter->stream_end_event({});
115              
116 1482         2903 my $output = $self->emitter->writer->output;
117 1482         2892 $self->emitter->finish;
118 1482         3444 return $output;
119             }
120              
121             sub _dump_node {
122 3880     3880   7328 my ($self, $value) = @_;
123 3880         8975 my $node = {
124             value => $value,
125             };
126 3880 100       8577 if (ref $value) {
127              
128 961         1680 my $seen = $self->{seen};
129 961         2076 my $refaddr = refaddr $value;
130 961 100 100     4152 if ($seen->{ $refaddr } and $seen->{ $refaddr } > 1) {
131 147         278 my $anchor = $self->{anchors}->{ $refaddr };
132 147 100       291 unless (defined $anchor) {
133 71 100       139 if ($self->representer->preserve_alias) {
134 21 100       105 if (ref $node->{value} eq 'YAML::PP::Preserve::Scalar') {
    100          
    50          
135 7 100       29 if (defined $node->{value}->alias) {
136 5         10 $node->{anchor} = $node->{value}->alias;
137 5         17 $self->{anchors}->{ $refaddr } = $node->{value}->alias;
138             }
139             }
140             elsif (reftype $node->{value} eq 'HASH') {
141 7 50       10 if (my $tied = tied %{ $node->{value} } ) {
  7         26  
142 7 100       22 if (defined $tied->{alias}) {
143 5         15 $node->{anchor} = $tied->{alias};
144 5         15 $self->{anchors}->{ $refaddr } = $node->{anchor};
145             }
146             }
147             }
148             elsif (reftype $node->{value} eq 'ARRAY') {
149 7 50       12 if (my $tied = tied @{ $node->{value} } ) {
  7         25  
150 7 100       24 if (defined $tied->{alias}) {
151 5         11 $node->{anchor} = $tied->{alias};
152 5         15 $self->{anchors}->{ $refaddr } = $node->{anchor};
153             }
154             }
155             }
156             }
157 71 100       170 unless (defined $node->{anchor}) {
158 56         95 my $num = ++$self->{anchor_num};
159 56         117 $self->{anchors}->{ $refaddr } = $num;
160 56         106 $node->{anchor} = $num;
161             }
162             }
163             else {
164 76         136 $node->{value} = $anchor;
165 76         235 $self->_emit_node([ alias => $node ]);
166 76         225 return;
167             }
168              
169             }
170             }
171 3804         7586 $node = $self->representer->represent_node($node);
172 3803         9851 $self->_emit_node($node);
173             }
174              
175             sub _emit_node {
176 3879     3879   6604 my ($self, $item) = @_;
177 3879         7256 my ($type, $node, %args) = @$item;
178 3879 100       8034 if ($type eq 'alias') {
179 76         153 $self->emitter->alias_event({ value => $node->{value} });
180 76         191 return;
181             }
182 3803 100       7187 if ($type eq 'mapping') {
183 455   100     1530 my $style = $args{style} || YAML_BLOCK_MAPPING_STYLE;
184             # TODO
185 455 50 66     1176 if ($node->{items} and @{ $node->{items} } == 0) {
  446         1324  
186             # $style = YAML_FLOW_MAPPING_STYLE;
187             }
188             $self->emitter->mapping_start_event({
189             anchor => $node->{anchor},
190             style => $style,
191             tag => $node->{tag},
192 455         986 });
193 455         711 for (@{ $node->{items} }) {
  455         1079  
194 1742         3743 $self->_dump_node($_);
195             }
196 454         1030 $self->emitter->mapping_end_event;
197 454         1745 return;
198             }
199 3348 100       6265 if ($type eq 'sequence') {
200 266   100     995 my $style = $args{style} || YAML_BLOCK_SEQUENCE_STYLE;
201 266 100       444 if (@{ $node->{items} } == 0) {
  266         639  
202             # $style = YAML_FLOW_SEQUENCE_STYLE;
203             }
204             $self->emitter->sequence_start_event({
205             anchor => $node->{anchor},
206             style => $style,
207             tag => $node->{tag},
208 266         565 });
209 266         431 for (@{ $node->{items} }) {
  266         688  
210 596         1392 $self->_dump_node($_);
211             }
212 266         685 $self->emitter->sequence_end_event;
213 266         1016 return;
214             }
215             $self->emitter->scalar_event({
216             value => $node->{items}->[0],
217             style => $node->{style},
218             anchor => $node->{anchor},
219             tag => $node->{tag},
220 3082         5944 });
221             }
222              
223              
224             sub dump_string {
225 1477     1477 0 4782 my ($self, @docs) = @_;
226 1477         4711 my $writer = YAML::PP::Writer->new;
227 1477         3500 $self->emitter->set_writer($writer);
228 1477         3709 my $output = $self->dump(@docs);
229 1476         5112 return $output;
230             }
231              
232             sub dump_file {
233 6     6 0 16 my ($self, $file, @docs) = @_;
234 6         37 my $writer = YAML::PP::Writer::File->new(output => $file);
235 6         15 $self->emitter->set_writer($writer);
236 6         17 my $output = $self->dump(@docs);
237 5         36 return $output;
238             }
239              
240             my %_reftypes = (
241             HASH => 1,
242             ARRAY => 1,
243             Regexp => 1,
244             REGEXP => 1,
245             CODE => 1,
246             SCALAR => 1,
247             REF => 1,
248             GLOB => 1,
249             );
250              
251             sub _check_references {
252 2961     2961   5257 my ($self, $doc) = @_;
253 2961 100       10727 my $reftype = reftype $doc or return;
254 893         1480 my $seen = $self->{seen};
255             # check which references are used more than once
256 893 100 100     2084 if ($reftype eq 'SCALAR' and
257 64 100       336 grep { ref $doc eq $_ } @{ $self->representer->schema->bool_class || [] }) {
  81         176  
258             # JSON::PP and boolean.pm always return the same reference for booleans
259             # Avoid printing *aliases in those case
260 64 50 33     251 if (ref $doc eq 'boolean' or ref $doc eq 'JSON::PP::Boolean') {
261 64         179 return;
262             }
263             }
264 829 100       3124 if (++$seen->{ refaddr $doc } > 1) {
265             # seen already
266 76         212 return;
267             }
268 753 50       1871 unless ($_reftypes{ $reftype }) {
269 0         0 die sprintf "Reference %s not implemented",
270             $reftype;
271             }
272 753 100       1646 if ($reftype eq 'HASH') {
    100          
    100          
273 453         2006 $self->_check_references($doc->{ $_ }) for keys %$doc;
274             }
275             elsif ($reftype eq 'ARRAY') {
276 262         712 $self->_check_references($_) for @$doc;
277             }
278             elsif ($reftype eq 'REF') {
279 8         19 $self->_check_references($$doc);
280             }
281             }
282              
283             1;