File Coverage

blib/lib/YAML/Perl/Constructor.pm
Criterion Covered Total %
statement 99 122 81.1
branch 32 54 59.2
condition 2 2 100.0
subroutine 14 15 93.3
pod 0 9 0.0
total 147 202 72.7


line stmt bran cond sub pod time code
1             package YAML::Perl::Constructor;
2 5     5   1860 use strict;
  5         11  
  5         205  
3 5     5   31 use warnings;
  5         9  
  5         170  
4              
5 5     5   2250 use YAML::Perl::Error;
  5         13  
  5         34  
6              
7             package YAML::Perl::Error::Constructor;
8 5     5   32 use YAML::Perl::Error::Marked -base;
  5         10  
  5         51  
9              
10             package YAML::Perl::Constructor;
11 5     5   1071 use YAML::Perl::Processor -base;
  5         11  
  5         49  
12              
13             {
14 5     5   33 no warnings 'once';
  5         11  
  5         8372  
15             $YAML::Perl::Constructor::yaml_constructors = {};
16             $YAML::Perl::Constructor::yaml_multi_constructors = {};
17             }
18              
19             field 'next_layer' => 'composer';
20              
21             field 'composer_class', -init => '"YAML::Perl::Composer"';
22             field 'composer', -init => '$self->create("composer")';
23              
24             field 'yaml_constructors' =>
25             -init =>'$YAML::Perl::Constructor::yaml_constructors';
26             field 'yaml_multi_constructors' =>
27             -init =>'$YAML::Perl::Constructor::yaml_multi_constructors';
28             field 'constructed_objects' => {};
29             field 'recursive_objects' => {};
30             field 'state_generators' => [];
31             field 'deep_construct' => False;
32              
33             sub construct {
34 9     9 0 56 my $self = shift;
35 9 50       24 if (wantarray) {
36 9         19 my @data = ();
37 9         25 while ($self->check_data()) {
38 9         36 push @data, $self->get_data();
39             }
40 9         354 return @data;
41             }
42             else {
43 0 0       0 return $self->check_data() ? $self->get_data() : ();
44             }
45             }
46              
47             sub check_data {
48 36     36 0 60 my $self = shift;
49 36         928 return $self->composer->check_node();
50             }
51              
52             sub get_data {
53 18     18 0 28 my $self = shift;
54 18 50       1217 if ($self->composer->check_node()) {
55 18         515 return $self->construct_document($self->composer->get_node());
56             }
57             else {
58 0         0 return ();
59             }
60             }
61              
62 0     0 0 0 sub get_single_data {
63             # We won't port this. We allow scalar construction of a single node in a
64             # multi document stream.
65             }
66              
67             sub construct_document {
68 18     18 0 34 my $self = shift;
69 18         71 my $node = shift;
70              
71 18         87 my $data = $self->construct_object($node);
72 18         28 while (@{$self->state_generators}) {
  18         524  
73 0         0 my $state_generators = $self->state_generators();
74 0         0 $self->state_generators([]);
75 0         0 for my $generator (@$state_generators) {
76 0         0 for my $dummy (@$generator) { }
77             }
78             }
79 18         457 $self->constructed_objects({});
80 18         443 $self->recursive_objects({});
81 18         479 $self->deep_construct(False);
82 18         644 return $data;
83             }
84              
85             sub construct_object {
86 72     72 0 96 my $self = shift;
87 72         86 my $node = shift;
88 72 100       165 my $deep = @_ ? shift : False;
89              
90 72         75 my $old_deep;
91 72 50       145 if ($deep) {
92 0         0 $old_deep = $self->deep_construct();
93 0         0 $self->deep_construct(True);
94             }
95 72 100       1768 if ($self->constructed_objects->{$node}) {
96 2         53 return $self->constructed_objects->{$node};
97             }
98 70 50       1774 if ($self->recursive_objects->{$node}) {
99 0         0 throw YAML::Perl::Error::Constructor(
100             undef,
101             undef,
102             "found unconstructable recursive node",
103             $node->start_mark
104             );
105             }
106 70         1741 $self->recursive_objects->{$node} = undef;
107 70         132 my $constructor = undef;
108 70         87 my $tag_suffix = undef;
109 70 50 100     1752 if ($self->yaml_constructors->{$node->tag || ''}) {
110 0         0 $constructor = $self->yaml_constructors->{$node->tag};
111             }
112             else {
113 70         95 LOOP1: while (1) {
114 70         82 for my $tag_prefix (keys %{$self->yaml_multi_constructors}) {
  70         1684  
115 0 0       0 if ($node->tag =~ /^\Q$tag_prefix\E(.*)/) {
116 0         0 $tag_suffix = $1;
117 0         0 $constructor = $self->yaml_multi_constructors->{$tag_prefix};
118 0         0 last LOOP1;
119             }
120             }
121 70 50       1858 if ($self->yaml_multi_constructors->{''}) {
    50          
    100          
    100          
    50          
122 0         0 $tag_suffix = $node->tag;
123 0         0 $constructor = $self->yaml_multi_constructors->{''};
124             }
125             elsif ($self->yaml_constructors->{''}) {
126 0         0 $constructor = $self->yaml_constructors->{''};
127             }
128             elsif ($node->isa('YAML::Perl::Node::Scalar')) {
129 46         104 $constructor = \ &construct_scalar;
130             }
131             elsif ($node->isa('YAML::Perl::Node::Sequence')) {
132 10         31 $constructor = \ &construct_sequence;
133             }
134             elsif ($node->isa('YAML::Perl::Node::Mapping')) {
135 14         38 $constructor = \ &construct_mapping;
136             }
137 70         131 last;
138             }
139             }
140 70         96 my $data;
141 70 50       129 if (not defined $tag_suffix) {
142 70         201 $data = &$constructor($self, $node);
143             }
144             else {
145 0         0 $data = &$constructor($self, $tag_suffix, $node);
146             }
147             # if (isinstance(data, types.GeneratorType):
148             # generator = data
149             # data = generator.next()
150             # if self.deep_construct:
151             # for dummy in generator:
152             # pass
153             # else:
154             # self.state_generators.append(generator)
155 70         1893 $self->constructed_objects->{$node} = $data;
156 70         2095 delete $self->recursive_objects->{$node};
157 70 50       186 if ($deep) {
158 0         0 $self->deep_construct($old_deep);
159             }
160 70         206 return $data;
161             }
162              
163             sub construct_scalar {
164 46     46 0 61 my $self = shift;
165 46         62 my $node = shift;
166 46 50       165 if (not $node->isa('YAML::Perl::Node::Scalar')) {
167 0         0 throw YAML::Perl::Error::Constructor(
168             undef,
169             undef,
170             "expected a scalar node, but found %s", $node->id,
171             $node->start_mark,
172             );
173             }
174 46         1206 my $scalar = $node->value;
175 46 100       1137 if (my $tag = $node->tag) {
176 2 50       12 if ($tag =~ s/^tag:yaml.org,2002:perl\/scalar://) {
177 2         9 return bless \ $scalar, $tag;
178             }
179             }
180 44         116 return $scalar;
181             }
182              
183             sub construct_sequence {
184 10     10 0 19 my $self = shift;
185 10         19 my $node = shift;
186 10 50       33 my $deep = @_ ? shift : False;
187              
188 10 50       42 if (not $node->isa('YAML::Perl::Node::Sequence')) {
189 0         0 throw YAML::Perl::Error::Constructor(
190             undef,
191             undef,
192             "expected a sequence node, but found %s", $node->id,
193             $node->start_mark,
194             );
195             }
196 10         301 my $sequence = [
197 10         17 map $self->construct_object($_, $deep), @{$node->value}
198             ];
199 10 100       240 if (my $tag = $node->tag) {
200 2 50       12 if ($tag =~ s/^tag:yaml.org,2002:perl\/array://) {
201 2         6 bless $sequence, $tag;
202             }
203             }
204 10         27 return $sequence;
205             }
206              
207             sub construct_mapping {
208 14     14 0 26 my $self = shift;
209 14         30 my $node = shift;
210 14 50       43 my $deep = @_ ? shift : False;
211              
212 14 50       63 if (not $node->isa('YAML::Perl::Node::Mapping')) {
213 0         0 throw YAML::Perl::Error::Constructor(
214             undef,
215             undef,
216             "expected a mapping node, but found %s", $node->id,
217             $node->start_mark,
218             );
219             }
220 14         27 my $mapping = {};
221 14         25 for (my $i = 0; $i < @{$node->value}; $i += 2) {
  30         769  
222 16         396 my $key_node = $node->value->[$i];
223 16         593 my $value_node = $node->value->[$i + 1];
224 16         74 my $key = $self->construct_object($key_node, $deep);
225             # try:
226             # hash(key)
227             # except TypeError, exc:
228             # raise ConstructorError("while constructing a mapping", node.start_mark,
229             # "found unacceptable key (%s)" % exc, key_node.start_mark)
230 16         45 my $value = $self->construct_object($value_node, $deep);
231 16         66 $mapping->{$key} = $value;
232             }
233 14 100       343 if (my $tag = $node->tag) {
234 2 50       19 if ($tag =~ s/^tag:yaml.org,2002:perl\/hash://) {
235 2         8 bless $mapping, $tag;
236             }
237             }
238 14         42 return $mapping;
239             }
240              
241             1;