File Coverage

blib/lib/YAML/PP.pm
Criterion Covered Total %
statement 215 223 96.4
branch 30 36 83.3
condition 24 27 88.8
subroutine 60 61 98.3
pod 17 18 94.4
total 346 365 94.7


line stmt bran cond sub pod time code
1             # ABSTRACT: YAML 1.2 Processor
2 48     48   3498818 use strict;
  48         82  
  48         1493  
3 48     48   215 use warnings;
  48         95  
  48         3063  
4             package YAML::PP;
5              
6             our $VERSION = 'v0.41.1'; # TRIAL VERSION
7              
8 48     48   22502 use YAML::PP::Schema;
  48         105  
  48         1422  
9 48     48   19282 use YAML::PP::Schema::JSON;
  48         114  
  48         2299  
10 48     48   16184 use YAML::PP::Loader;
  48         130  
  48         1505  
11 48     48   18107 use YAML::PP::Dumper;
  48         137  
  48         1677  
12 48     48   241 use Scalar::Util qw/ blessed /;
  48         62  
  48         2067  
13 48     48   201 use Carp qw/ croak /;
  48         65  
  48         1795  
14              
15 48     48   177 use Exporter 'import';
  48         62  
  48         51336  
16             our @EXPORT_OK = qw/ Load LoadFile Dump DumpFile /;
17              
18             my %YAML_VERSIONS = ('1.1' => 1, '1.2' => 1);
19              
20              
21             sub new {
22 765     765 1 4922530 my ($class, %args) = @_;
23              
24 765         2101 my $bool = delete $args{boolean};
25 765 100       2715 $bool = 'perl' unless defined $bool;
26 765   100     2581 my $schemas = delete $args{schema} || ['+'];
27 765   100     3734 my $cyclic_refs = delete $args{cyclic_refs} || 'fatal';
28 765         1381 my $indent = delete $args{indent};
29 765         1168 my $width = delete $args{width};
30 765         1289 my $writer = delete $args{writer};
31 765         1381 my $header = delete $args{header};
32 765         1201 my $footer = delete $args{footer};
33 765         1184 my $require_footer = delete $args{require_footer};
34 765         1227 my $duplicate_keys = delete $args{duplicate_keys};
35 765         1124 my $max_depth = delete $args{max_depth};
36 765         2575 my $yaml_version = $class->_arg_yaml_version(delete $args{yaml_version});
37 765         1354 my $default_yaml_version = $yaml_version->[0];
38 765         1284 my $version_directive = delete $args{version_directive};
39 765         1060 my $preserve = delete $args{preserve};
40 765         1094 my $parser = delete $args{parser};
41             my $emitter = delete $args{emitter} || {
42 765   50     4625 indent => $indent,
43             width => $width,
44             writer => $writer,
45             };
46 765 50       1874 if (keys %args) {
47 0         0 die "Unexpected arguments: " . join ', ', sort keys %args;
48             }
49              
50 765         1163 my %schemas;
51 765         1639 for my $v (@$yaml_version) {
52 767         1078 my $schema;
53 767 50 33     2291 if (blessed($schemas) and $schemas->isa('YAML::PP::Schema')) {
54 0         0 $schema = $schemas;
55             }
56             else {
57 767         3774 $schema = YAML::PP::Schema->new(
58             boolean => $bool,
59             yaml_version => $v,
60             );
61 767         2786 $schema->load_subschemas(@$schemas);
62             }
63 766         1876 $schemas{ $v } = $schema;
64             }
65 764         1175 my $default_schema = $schemas{ $default_yaml_version };
66              
67 764         3851 my $loader = YAML::PP::Loader->new(
68             schemas => \%schemas,
69             cyclic_refs => $cyclic_refs,
70             parser => $parser,
71             default_yaml_version => $default_yaml_version,
72             preserve => $preserve,
73             duplicate_keys => $duplicate_keys,
74             require_footer => $require_footer,
75             max_depth => $max_depth,
76             );
77 763         3409 my $dumper = YAML::PP::Dumper->new(
78             schema => $default_schema,
79             emitter => $emitter,
80             header => $header,
81             footer => $footer,
82             version_directive => $version_directive,
83             preserve => $preserve,
84             );
85              
86 763         2246 my $self = bless {
87             schema => \%schemas,
88             loader => $loader,
89             dumper => $dumper,
90             }, $class;
91 763         4234 return $self;
92             }
93              
94             sub clone {
95 9     9 0 274 my ($self) = @_;
96 9         48 my $clone = {
97             schema => $self->schema,
98             loader => $self->loader->clone,
99             dumper => $self->dumper->clone,
100             };
101 9         23 return bless $clone, ref $self;
102             }
103              
104             sub _arg_yaml_version {
105 765     765   1480 my ($class, $version) = @_;
106 765         1899 my @versions = ('1.2');
107 765 100       2045 if (defined $version) {
108 5         8 @versions = ();
109 5 100       11 if (not ref $version) {
110 1         2 $version = [$version];
111             }
112 5         11 for my $v (@$version) {
113 7 50       23 unless ($YAML_VERSIONS{ $v }) {
114 0         0 croak "YAML Version '$v' not supported";
115             }
116 7         11 push @versions, $v;
117             }
118             }
119 765         2016 return \@versions;
120             }
121              
122              
123             sub loader {
124 2221 50   2221 1 5187 if (@_ > 1) {
125 0         0 $_[0]->{loader} = $_[1]
126             }
127 2221         7608 return $_[0]->{loader};
128             }
129              
130             sub dumper {
131 1494 50   1494 1 3861 if (@_ > 1) {
132 0         0 $_[0]->{dumper} = $_[1]
133             }
134 1494         5606 return $_[0]->{dumper};
135             }
136              
137             sub schema {
138 16 50   16 1 48 if (@_ > 1) { $_[0]->{schema}->{'1.2'} = $_[1] }
  0         0  
139 16         74 return $_[0]->{schema}->{'1.2'};
140             }
141              
142             sub default_schema {
143 3     3 1 33 my ($self, %args) = @_;
144             my $schema = YAML::PP::Schema->new(
145             boolean => $args{boolean},
146 3         22 );
147 3         13 $schema->load_subschemas(qw/ Core /);
148 3         16 return $schema;
149             }
150              
151             sub load_string {
152 2181     2181 1 918794 my ($self, $yaml) = @_;
153 2181         4601 return $self->loader->load_string($yaml);
154             }
155              
156             sub load_file {
157 28     28 1 59 my ($self, $file) = @_;
158 28         221 return $self->loader->load_file($file);
159             }
160              
161             sub dump {
162 1     1 1 7 my ($self, @data) = @_;
163 1         3 return $self->dumper->dump(@data);
164             }
165              
166             sub dump_string {
167 1478     1478 1 3255678 my ($self, @data) = @_;
168 1478         3586 return $self->dumper->dump_string(@data);
169             }
170              
171             sub dump_file {
172 6     6 1 15 my ($self, $file, @data) = @_;
173 6         15 return $self->dumper->dump_file($file, @data);
174             }
175              
176             # legagy interface
177             sub Load {
178 2     2 1 167609 my ($yaml) = @_;
179 2         13 YAML::PP->new->load_string($yaml);
180             }
181              
182             sub LoadFile {
183 12     12 1 1378542 my ($file) = @_;
184 12         61 YAML::PP->new->load_file($file);
185             }
186              
187             sub Dump {
188 1     1 1 1583 my (@data) = @_;
189 1         5 YAML::PP->new->dump_string(@data);
190             }
191              
192             sub DumpFile {
193 4     4 1 677 my ($file, @data) = @_;
194 4         22 YAML::PP->new->dump_file($file, @data);
195             }
196              
197             sub preserved_scalar {
198 4     4 1 4313 my ($self, $value, %args) = @_;
199 4         29 my $scalar = YAML::PP::Preserve::Scalar->new(
200             value => $value,
201             %args,
202             );
203 4         12 return $scalar;
204             }
205              
206             sub preserved_mapping {
207 4     4 1 1709 my ($self, $hash, %args) = @_;
208 4         8 my $data = {};
209 4         14 tie %$data, 'YAML::PP::Preserve::Hash';
210 4         17 %$data = %$hash;
211 4         7 my $t = tied %$data;
212 4         8 $t->{style} = $args{style};
213 4         8 $t->{alias} = $args{alias};
214 4         9 return $data;
215             }
216              
217             sub preserved_sequence {
218 4     4 1 3827 my ($self, $array, %args) = @_;
219 4         6 my $data = [];
220 4         16 tie @$data, 'YAML::PP::Preserve::Array';
221 4         13 push @$data, @$array;
222 4         7 my $t = tied @$data;
223 4         8 $t->{style} = $args{style};
224 4         6 $t->{alias} = $args{alias};
225 4         11 return $data;
226             }
227              
228             package YAML::PP::Preserve::Hash;
229             # experimental
230 48     48   20948 use Tie::Hash; # provides Tie::StdHash, our parent below
  48         34358  
  48         2173  
231             our @ISA = qw/ Tie::StdHash /;
232 48     48   248 use Scalar::Util qw/ reftype blessed /;
  48         67  
  48         23613  
233              
234             sub TIEHASH {
235 34     34   89 my ($class, %args) = @_;
236 34         192 my $self = bless {
237             keys => [keys %args],
238             data => { %args },
239             }, $class;
240             }
241              
242             sub STORE {
243 127     127   1062 my ($self, $key, $val) = @_;
244 127         166 my $keys = $self->{keys};
245 127 100       194 unless (exists $self->{data}->{ $key }) {
246 120         171 push @$keys, $key;
247             }
248 127 100 100     262 if (ref $val and not blessed($val)) {
249 39 100 100     189 if (reftype($val) eq 'HASH' and not tied %$val) {
    100 100        
250 1         2 tie %$val, 'YAML::PP::Preserve::Hash', %$val;
251             }
252             elsif (reftype($val) eq 'ARRAY' and not tied @$val) {
253 2         8 tie @$val, 'YAML::PP::Preserve::Array', @$val;
254             }
255             }
256 127         288 $self->{data}->{ $key } = $val;
257             }
258              
259             sub FIRSTKEY {
260 91     91   3178 my ($self) = @_;
261 91         313 return $self->{keys}->[0];
262             }
263              
264             sub NEXTKEY {
265 320     320   1155 my ($self, $last) = @_;
266 320         390 my $keys = $self->{keys};
267 320         502 for my $i (0 .. $#$keys) {
268 1167 100       1480 if ("$keys->[ $i ]" eq "$last") {
269 320         896 return $keys->[ $i + 1 ];
270             }
271             }
272 0         0 return;
273             }
274              
275             sub FETCH {
276 305     305   3009 my ($self, $key) = @_;
277 305         665 my $val = $self->{data}->{ $key };
278             }
279              
280             sub DELETE {
281 2     2   1704 my ($self, $key) = @_;
282 2         4 @{ $self->{keys} } = grep { "$_" ne "$key" } @{ $self->{keys} };
  2         12  
  12         17  
  2         6  
283 2         11 delete $self->{data}->{ $key };
284             }
285              
286             sub EXISTS {
287 34     34   694 my ($self, $key) = @_;
288 34         52 return exists $self->{data}->{ $key };
289             }
290              
291             sub CLEAR {
292 9     9   20 my ($self) = @_;
293 9         16 $self->{keys} = [];
294 9         30 $self->{data} = {};
295             }
296              
297             sub SCALAR {
298 3     3   1602 my ($self) = @_;
299 3         4 return scalar %{ $self->{data} };
  3         11  
300             }
301              
302             package YAML::PP::Preserve::Array;
303             # experimental
304 48     48   18647 use Tie::Array; # provides Tie::StdArray, our parent below
  48         44914  
  48         2028  
305             our @ISA = qw/ Tie::StdArray /;
306 48     48   248 use Scalar::Util qw/ reftype blessed /;
  48         67  
  48         26414  
307              
308             sub TIEARRAY {
309 16     16   28 my ($class, @items) = @_;
310 16         41 my $self = bless {
311             data => [@items],
312             }, $class;
313 16         38 return $self;
314             }
315              
316             sub FETCH {
317 99     99   138 my ($self, $i) = @_;
318 99         254 return $self->{data}->[ $i ];
319             }
320             sub FETCHSIZE {
321 101     101   691 my ($self) = @_;
322 101         98 return $#{ $self->{data} } + 1;
  101         295  
323             }
324              
325             sub _preserve {
326 42     42   62 my ($val) = @_;
327 42 100 100     131 if (ref $val and not blessed($val)) {
328 13 100 100     60 if (reftype($val) eq 'HASH' and not tied %$val) {
    100 100        
329 5         10 tie %$val, 'YAML::PP::Preserve::Hash', %$val;
330             }
331             elsif (reftype($val) eq 'ARRAY' and not tied @$val) {
332 1         3 tie @$val, 'YAML::PP::Preserve::Array', @$val;
333             }
334             }
335 42         136 return $val;
336             }
337              
338             sub STORE {
339 6     6   756 my ($self, $i, $val) = @_;
340 6         10 _preserve($val);
341 6         17 $self->{data}->[ $i ] = $val;
342             }
343             sub PUSH {
344 14     14   44 my ($self, @args) = @_;
345 14         17 push @{ $self->{data} }, map { _preserve $_ } @args;
  14         39  
  31         67  
346             }
347             sub STORESIZE {
348 1     1   7 my ($self, $i) = @_;
349 1         3 $#{ $self->{data} } = $i - 1;
  1         4  
350             }
351             sub DELETE {
352 1     1   2 my ($self, $i) = @_;
353 1         3 delete $self->{data}->[ $i ];
354             }
355             sub EXISTS {
356 2     2   6 my ($self, $i) = @_;
357 2         14 return exists $self->{data}->[ $i ];
358             }
359             sub CLEAR {
360 1     1   6 my ($self) = @_;
361 1         5 $self->{data} = [];
362             }
363             sub SHIFT {
364 1     1   3 my ($self) = @_;
365 1         2 shift @{ $self->{data} };
  1         3  
366             }
367             sub UNSHIFT {
368 2     2   7 my ($self, @args) = @_;
369 2         3 unshift @{ $self->{data} }, map { _preserve $_ } @args;
  2         4  
  2         5  
370             }
371             sub SPLICE {
372 2     2   11 my ($self, $offset, $length, @args) = @_;
373 2         3 splice @{ $self->{data} }, $offset, $length, map { _preserve $_ } @args;
  2         6  
  3         9  
374             }
375       1     sub EXTEND {}
376              
377              
378             package YAML::PP::Preserve::Scalar;
379              
380             use overload
381 48         532 fallback => 1,
382             '+' => \&value,
383             '""' => \&value,
384             'bool' => \&value,
385 48     48   321 ;
  48         60  
386             sub new {
387 87     87   303 my ($class, %args) = @_;
388 87         280 my $self = {
389             %args,
390             };
391 87         349 bless $self, $class;
392             }
393 2218     2218   6974 sub value { $_[0]->{value} }
394 0     0   0 sub tag { $_[0]->{tag} }
395 21 100   21   51 sub style { $_[0]->{style} || 0 }
396 17     17   38 sub alias { $_[0]->{alias} }
397              
398             1;
399              
400             __END__