File Coverage

blib/lib/YAML/PP/Representer.pm
Criterion Covered Total %
statement 140 146 95.8
branch 80 96 83.3
condition 32 43 74.4
subroutine 16 16 100.0
pod 0 8 0.0
total 268 309 86.7


line stmt bran cond sub pod time code
1 49     49   154575 use strict;
  49         79  
  49         1492  
2 49     49   171 use warnings;
  49         60  
  49         2993  
3             package YAML::PP::Representer;
4              
5             our $VERSION = 'v0.41.1'; # TRIAL VERSION
6              
7 49     49   204 use Scalar::Util qw/ reftype blessed refaddr /;
  49         147  
  49         3411  
8              
9 49         3048 use YAML::PP::Common qw/
10             YAML_PLAIN_SCALAR_STYLE YAML_SINGLE_QUOTED_SCALAR_STYLE
11             YAML_DOUBLE_QUOTED_SCALAR_STYLE
12             YAML_ANY_SCALAR_STYLE
13             YAML_LITERAL_SCALAR_STYLE YAML_FOLDED_SCALAR_STYLE
14             YAML_FLOW_SEQUENCE_STYLE YAML_FLOW_MAPPING_STYLE
15             YAML_BLOCK_MAPPING_STYLE YAML_BLOCK_SEQUENCE_STYLE
16             PRESERVE_ORDER PRESERVE_SCALAR_STYLE PRESERVE_FLOW_STYLE PRESERVE_ALIAS
17 49     49   564 /;
  49         97  
18 49     49   319 use B;
  49         141  
  49         65558  
19              
20             sub new {
21 764     764 0 1855 my ($class, %args) = @_;
22 764   100     2170 my $preserve = delete $args{preserve} || 0;
23 764 100       1431 if ($preserve == 1) {
24 1         3 $preserve = PRESERVE_ORDER | PRESERVE_SCALAR_STYLE | PRESERVE_FLOW_STYLE | PRESERVE_ALIAS;
25             }
26             my $self = bless {
27             schema => delete $args{schema},
28 764         1803 preserve => $preserve,
29             }, $class;
30 764 50       1358 if (keys %args) {
31 0         0 die "Unexpected arguments: " . join ', ', sort keys %args;
32             }
33 764         4026 return $self;
34             }
35              
36             sub clone {
37 9     9 0 11 my ($self) = @_;
38             my $clone = {
39             schema => $self->schema,
40             preserve => $self->{preserve},
41 9         18 };
42 9         26 return bless $clone, ref $self;
43             }
44              
45 3959     3959 0 10651 sub schema { return $_[0]->{schema} }
46 458     458 0 1790 sub preserve_order { return $_[0]->{preserve} & PRESERVE_ORDER }
47 3817     3817 0 5811 sub preserve_scalar_style { return $_[0]->{preserve} & PRESERVE_SCALAR_STYLE }
48 724     724 0 1890 sub preserve_flow_style { return $_[0]->{preserve} & PRESERVE_FLOW_STYLE }
49 3888     3888 0 6278 sub preserve_alias { return $_[0]->{preserve} & PRESERVE_ALIAS }
50              
51             sub represent_node {
52 3817     3817 0 5293 my ($self, $node) = @_;
53              
54 3817         6504 my $preserve_alias = $self->preserve_alias;
55 3817         6278 my $preserve_style = $self->preserve_scalar_style;
56 3817 100 100     10008 if ($preserve_style or $preserve_alias) {
57 131 100       257 if (ref $node->{value} eq 'YAML::PP::Preserve::Scalar') {
58 87         201 my $value = $node->{value}->value;
59 87 100       151 if ($preserve_style) {
60 21         41 $node->{style} = $node->{value}->style;
61             }
62             # $node->{tag} = $node->{value}->tag;
63 87         130 $node->{value} = $value;
64             }
65             }
66 3817         7325 $node->{reftype} = reftype($node->{value});
67 3817 100 100     12233 if (not $node->{reftype} and reftype(\$node->{value}) eq 'GLOB') {
68 6         13 $node->{reftype} = 'GLOB';
69             }
70              
71 3817 100       6850 if ($node->{reftype}) {
72 807         1856 $self->_represent_noderef($node);
73             }
74             else {
75 3010         5803 $self->_represent_node_nonref($node);
76             }
77 3817   100     10115 $node->{reftype} = (reftype $node->{data}) || '';
78              
79 3817 100 100     7681 if ($node->{reftype} eq 'HASH' and my $tied = tied(%{ $node->{data} })) {
  458         1514  
80 34         60 my $representers = $self->schema->representers;
81 34         62 $tied = ref $tied;
82 34 50       87 if (my $def = $representers->{tied_equals}->{ $tied }) {
83 0         0 my $code = $def->{code};
84 0         0 my $done = $code->($self, $node);
85             }
86             }
87              
88 3817 100       9735 if ($node->{reftype} eq 'HASH') {
    100          
    100          
89 458 50       1135 unless (defined $node->{items}) {
90             # by default we sort hash keys
91 458         531 my @keys;
92 458 100       874 if ($self->preserve_order) {
93 24         27 @keys = keys %{ $node->{data} };
  24         93  
94             }
95             else {
96 434         599 @keys = sort keys %{ $node->{data} };
  434         1803  
97             }
98 458         1053 for my $key (@keys) {
99 876         980 push @{ $node->{items} }, $key, $node->{data}->{ $key };
  876         2510  
100             }
101             }
102 458         668 my %args;
103 458 100 66     907 if ($self->preserve_flow_style and reftype $node->{value} eq 'HASH') {
104 19 100       41 if (my $tied = tied %{ $node->{value} } ) {
  19         51  
105 18         44 $args{style} = $tied->{style};
106             }
107             }
108 458         1489 return [ mapping => $node, %args ];
109             }
110             elsif ($node->{reftype} eq 'ARRAY') {
111 266 50       585 unless (defined $node->{items}) {
112 266         343 @{ $node->{items} } = @{ $node->{data} };
  266         787  
  266         516  
113             }
114 266         417 my %args;
115 266 100 66     508 if ($self->preserve_flow_style and reftype $node->{value} eq 'ARRAY') {
116 10 50       11 if (my $tied = tied @{ $node->{value} } ) {
  10         26  
117 10         21 $args{style} = $tied->{style};
118             }
119             }
120 266         859 return [ sequence => $node, %args ];
121             }
122             elsif ($node->{reftype}) {
123 1         12 die "Cannot handle reftype '$node->{reftype}' (you might want to enable YAML::PP::Schema::Perl)";
124             }
125             else {
126 3092 100       5541 unless (defined $node->{items}) {
127 3026         6463 $node->{items} = [$node->{data}];
128             }
129 3092         7601 return [ scalar => $node ];
130             }
131              
132             }
133              
134             my $bool_code = <<'EOM';
135             sub {
136             my ($x) = @_;
137             use experimental qw/ builtin /;
138             builtin::is_bool($x);
139             }
140             EOM
141             my $is_bool;
142              
143             sub _represent_node_nonref {
144 3010     3010   4244 my ($self, $node) = @_;
145 3010         5042 my $representers = $self->schema->representers;
146              
147 3010 100       5894 if (not defined $node->{value}) {
148 110 50       305 if (my $undef = $representers->{undef}) {
149 110 50       353 return 1 if $undef->($self, $node);
150             }
151             else {
152 0         0 $node->{style} = YAML_SINGLE_QUOTED_SCALAR_STYLE;
153 0         0 $node->{data} = '';
154 0         0 return 1;
155             }
156             }
157 2900 100 66     9977 if ($] >= 5.036000 and my $rep = $representers->{bool}) {
158 748   66 15   2838 $is_bool ||= eval $bool_code;
  15         6837  
  15         19351  
  15         184  
159 748 100       17341 if ($is_bool->($node->{value})) {
160 2         5 return $rep->{code}->($self, $node);
161             }
162             }
163 2898         3290 for my $rep (@{ $representers->{flags} }) {
  2898         5547  
164 4969         6647 my $check_flags = $rep->{flags};
165 4969         15195 my $flags = B::svref_2object(\$node->{value})->FLAGS;
166 4969 100       10485 if ($flags & $check_flags) {
167 517 100       1514 return 1 if $rep->{code}->($self, $node);
168             }
169              
170             }
171 2392 100       6690 if (my $rep = $representers->{equals}->{ $node->{value} }) {
172 138 50       473 return 1 if $rep->{code}->($self, $node);
173             }
174 2254         2527 for my $rep (@{ $representers->{regex} }) {
  2254         3698  
175 2050 100       17683 if ($node->{value} =~ $rep->{regex}) {
176 101 100       363 return 1 if $rep->{code}->($self, $node);
177             }
178             }
179 2159 50       4464 unless (defined $node->{data}) {
180 2159         3879 $node->{data} = $node->{value};
181             }
182 2159 100       3943 unless (defined $node->{style}) {
183 2143         3216 $node->{style} = YAML_ANY_SCALAR_STYLE;
184 2143         4079 $node->{style} = "";
185             }
186             }
187              
188             sub _represent_noderef {
189 807     807   1355 my ($self, $node) = @_;
190 807         1501 my $representers = $self->schema->representers;
191              
192 807 100       1962 if (my $classname = blessed($node->{value})) {
193 112 100       332 if (my $def = $representers->{class_equals}->{ $classname }) {
194 66         125 my $code = $def->{code};
195 66 50       194 return 1 if $code->($self, $node);
196             }
197 46         55 for my $matches (@{ $representers->{class_matches} }) {
  46         121  
198 43         85 my ($re, $code) = @$matches;
199 43 50 33     168 if (ref $re and $classname =~ $re or $re) {
      33        
200 43 100       103 return 1 if $code->($self, $node);
201             }
202             }
203 4         5 for my $isa (@{ $representers->{class_isa} }) {
  4         8  
204 3         6 my ($class_name, $code) = @$isa;
205 3 100       16 if ($node->{ value }->isa($class_name)) {
206 2 50       5 return 1 if $code->($self, $node);
207             }
208             }
209             }
210 697 100 100     1681 if ($node->{reftype} eq 'SCALAR' and my $scalarref = $representers->{scalarref}) {
211 4         8 my $code = $scalarref->{code};
212 4 50       16 return 1 if $code->($self, $node);
213             }
214 693 100 66     1535 if ($node->{reftype} eq 'REF' and my $refref = $representers->{refref}) {
215 4         7 my $code = $refref->{code};
216 4 50       13 return 1 if $code->($self, $node);
217             }
218 689 100 66     1625 if ($node->{reftype} eq 'CODE' and my $coderef = $representers->{coderef}) {
219 5         11 my $code = $coderef->{code};
220 5 50       18 return 1 if $code->($self, $node);
221             }
222 684 100 66     1514 if ($node->{reftype} eq 'GLOB' and my $glob = $representers->{glob}) {
223 6         12 my $code = $glob->{code};
224 6 50       17 return 1 if $code->($self, $node);
225             }
226 678         1332 $node->{data} = $node->{value};
227              
228             }
229              
230             1;