File Coverage

blib/lib/YAML/PP/Schema/YAML1_1.pm
Criterion Covered Total %
statement 75 75 100.0
branch 10 10 100.0
condition n/a
subroutine 11 11 100.0
pod 1 1 100.0
total 97 97 100.0


line stmt bran cond sub pod time code
1 3     3   142111 use strict;
  3         5  
  3         99  
2 3     3   10 use warnings;
  3         5  
  3         241  
3             package YAML::PP::Schema::YAML1_1;
4              
5             our $VERSION = 'v0.39.0'; # VERSION
6              
7 3         209 use YAML::PP::Schema::JSON qw/
8             represent_int represent_float represent_literal represent_bool
9             represent_undef
10 3     3   338 /;
  3         6  
11              
12 3     3   13 use YAML::PP::Common qw/ YAML_PLAIN_SCALAR_STYLE /;
  3         4  
  3         3156  
13              
14             #https://yaml.org/type/bool.html
15             # y|Y|yes|Yes|YES|n|N|no|No|NO
16             # |true|True|TRUE|false|False|FALSE
17             # |on|On|ON|off|Off|OFF
18              
19             # https://yaml.org/type/float.html
20             # [-+]?([0-9][0-9_]*)?\.[0-9.]*([eE][-+][0-9]+)? (base 10)
21             # |[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+\.[0-9_]* (base 60)
22             # |[-+]?\.(inf|Inf|INF) # (infinity)
23             # |\.(nan|NaN|NAN) # (not a number)
24              
25             # https://yaml.org/type/int.html
26             # [-+]?0b[0-1_]+ # (base 2)
27             # |[-+]?0[0-7_]+ # (base 8)
28             # |[-+]?(0|[1-9][0-9_]*) # (base 10)
29             # |[-+]?0x[0-9a-fA-F_]+ # (base 16)
30             # |[-+]?[1-9][0-9_]*(:[0-5]?[0-9])+ # (base 60)
31              
32             # https://yaml.org/type/null.html
33             # ~ # (canonical)
34             # |null|Null|NULL # (English)
35             # | # (Empty)
36              
37             my $RE_INT_1_1 = qr{^([+-]?(?:0|[1-9][0-9_]*))$};
38             #my $RE_FLOAT_1_1 = qr{^([+-]?([0-9][0-9_]*)?\.[0-9.]*([eE][+-][0-9]+)?)$};
39             # https://yaml.org/type/float.html has a bug. The regex says \.[0-9.], but
40             # probably means \.[0-9_]
41             my $RE_FLOAT_1_1 = qr{^([+-]?(?:[0-9][0-9_]*)?\.[0-9_]*(?:[eE][+-][0-9]+)?)$};
42             my $RE_SEXAGESIMAL = qr{^([+-]?[0-9][0-9_]*(:[0-5]?[0-9])+\.[0-9_]*)$};
43             my $RE_SEXAGESIMAL_INT = qr{^([-+]?[1-9][0-9_]*(:[0-5]?[0-9])+)$};
44             my $RE_INT_OCTAL_1_1 = qr{^([+-]?)0([0-7_]+)$};
45             my $RE_INT_HEX_1_1 = qr{^([+-]?)(0x[0-9a-fA-F_]+)$};
46             my $RE_INT_BIN_1_1 = qr{^([-+]?)(0b[0-1_]+)$};
47              
48             sub _from_oct {
49 22     22   49 my ($constructor, $event, $matches) = @_;
50 22         48 my ($sign, $oct) = @$matches;
51 22         40 $oct =~ tr/_//d;
52 22         58 my $result = oct $oct;
53 22 100       65 $result = -$result if $sign eq '-';
54 22         80 return $result;
55             }
56             sub _from_hex {
57 12     12   39 my ($constructor, $event, $matches) = @_;
58 12         30 my ($sign, $hex) = @$matches;
59 12         29 my $result = hex $hex;
60 12 100       33 $result = -$result if $sign eq '-';
61 12         40 return $result;
62             }
63             sub _sexa_to_float {
64 8     8   22 my ($constructor, $event, $matches) = @_;
65 8         28 my ($float) = @$matches;
66 8         15 my $result = 0;
67 8         15 my $i = 0;
68 8         18 my $sign = 1;
69 8 100       44 $float =~ s/^-// and $sign = -1;
70 8         42 for my $part (reverse split m/:/, $float) {
71 24         63 $result += $part * ( 60 ** $i );
72 24         29 $i++;
73             }
74 8         61 $result = unpack F => pack F => $result;
75 8         41 return $result * $sign;
76             }
77             sub _to_float {
78 24     24   67 my ($constructor, $event, $matches) = @_;
79 24         49 my ($float) = @$matches;
80 24         48 $float =~ tr/_//d;
81 24         174 $float = unpack F => pack F => $float;
82 24         97 return $float;
83             }
84             sub _to_int {
85 14     14   48 my ($constructor, $event, $matches) = @_;
86 14         28 my ($int) = @$matches;
87 14         26 $int =~ tr/_//d;
88 14         62 0 + $int;
89             }
90              
91             sub register {
92 5     5 1 18 my ($self, %args) = @_;
93 5         10 my $schema = $args{schema};
94              
95             $schema->add_resolver(
96             tag => 'tag:yaml.org,2002:null',
97             match => [ equals => $_ => undef ],
98 5         21 ) for (qw/ null NULL Null ~ /, '');
99             $schema->add_resolver(
100             tag => 'tag:yaml.org,2002:bool',
101             match => [ equals => $_ => $schema->true ],
102 5         30 ) for (qw/ true TRUE True y Y yes Yes YES on On ON /);
103             $schema->add_resolver(
104             tag => 'tag:yaml.org,2002:bool',
105             match => [ equals => $_ => $schema->false ],
106 5         18 ) for (qw/ false FALSE False n N no No NO off Off OFF /);
107 5         19 $schema->add_resolver(
108             tag => 'tag:yaml.org,2002:int',
109             match => [ regex => $RE_INT_OCTAL_1_1 => \&_from_oct ],
110             );
111 5         16 $schema->add_resolver(
112             tag => 'tag:yaml.org,2002:int',
113             match => [ regex => $RE_INT_1_1 => \&_to_int ],
114             );
115 5         15 $schema->add_resolver(
116             tag => 'tag:yaml.org,2002:int',
117             match => [ regex => $RE_INT_HEX_1_1 => \&_from_hex ],
118             );
119 5         15 $schema->add_resolver(
120             tag => 'tag:yaml.org,2002:float',
121             match => [ regex => $RE_FLOAT_1_1 => \&_to_float ],
122             );
123 5         15 $schema->add_resolver(
124             tag => 'tag:yaml.org,2002:int',
125             match => [ regex => $RE_INT_BIN_1_1 => \&_from_oct ],
126             );
127 5         14 $schema->add_resolver(
128             tag => 'tag:yaml.org,2002:int',
129             match => [ regex => $RE_SEXAGESIMAL_INT => \&_sexa_to_float ],
130             );
131 5         13 $schema->add_resolver(
132             tag => 'tag:yaml.org,2002:float',
133             match => [ regex => $RE_SEXAGESIMAL => \&_sexa_to_float ],
134             );
135             $schema->add_resolver(
136             tag => 'tag:yaml.org,2002:float',
137             match => [ equals => $_ => 0 + "inf" ],
138 5         14 ) for (qw/ .inf .Inf .INF +.inf +.Inf +.INF /);
139             $schema->add_resolver(
140             tag => 'tag:yaml.org,2002:float',
141             match => [ equals => $_ => 0 - "inf" ],
142 5         15 ) for (qw/ -.inf -.Inf -.INF /);
143             $schema->add_resolver(
144             tag => 'tag:yaml.org,2002:float',
145             match => [ equals => $_ => 0 + "nan" ],
146 5         14 ) for (qw/ .nan .NaN .NAN /);
147             $schema->add_resolver(
148             tag => 'tag:yaml.org,2002:str',
149 5     81   30 match => [ all => sub { $_[1]->{value} } ],
  81         274  
150             implicit => 0,
151             );
152              
153 5         6 my $int_flags = B::SVp_IOK;
154 5         10 my $float_flags = B::SVp_NOK;
155 5         15 $schema->add_representer(
156             flags => $int_flags,
157             code => \&represent_int,
158             );
159 5         13 $schema->add_representer(
160             flags => $float_flags,
161             code => \&represent_float,
162             );
163 5         12 $schema->add_representer(
164             undefined => \&represent_undef,
165             );
166             $schema->add_representer(
167             equals => $_,
168             code => \&represent_literal,
169 5         17 ) for ("", qw/
170             true TRUE True y Y yes Yes YES on On ON
171             false FALSE False n N n no No NO off Off OFF
172             null NULL Null ~
173             .inf .Inf .INF -.inf -.Inf -.INF +.inf +.Inf +.INF .nan .NaN .NAN
174             /);
175 5         464 $schema->add_representer(
176             regex => qr{$RE_INT_1_1|$RE_FLOAT_1_1|$RE_INT_OCTAL_1_1|$RE_INT_HEX_1_1|$RE_INT_BIN_1_1|$RE_SEXAGESIMAL_INT|$RE_SEXAGESIMAL},
177             code => \&represent_literal,
178             );
179              
180 5 100       15 if ($schema->bool_class) {
181 2         3 for my $class (@{ $schema->bool_class }) {
  2         5  
182 2 100       5 if ($class eq 'perl') {
183 1         2 $schema->add_representer(
184             bool => 1,
185             code => \&represent_bool,
186             );
187 1         2 next;
188             }
189             $schema->add_representer(
190 1         2 class_equals => $class,
191             code => \&represent_bool,
192             );
193             }
194             }
195              
196 5         33 return;
197             }
198              
199              
200             1;
201              
202             __END__
203              
204             =pod
205              
206             =encoding utf-8
207              
208             =head1 NAME
209              
210             YAML::PP::Schema::YAML1_1 - YAML 1.1 Schema for YAML::PP
211              
212             =head1 SYNOPSIS
213              
214             use YAML::PP;
215              
216             my $yp = YAML::PP->new( schema => ['YAML1_1'] );
217             my $yaml = <<'EOM';
218             ---
219             booltrue: [ true, True, TRUE, y, Y, yes, Yes, YES, on, On, ON ]
220             EOM
221             my $data = $yp->load_string($yaml);
222              
223             =head1 DESCRIPTION
224              
225             This schema allows you to load the common YAML Types from YAML 1.1.
226              
227             =head1 METHODS
228              
229             =over
230              
231             =item register
232              
233             Called by YAML::PP::Schema
234              
235             =back
236              
237             =head1 SEE ALSO
238              
239             =over
240              
241             =item L<https://yaml.org/type/null.html>
242              
243             =item L<https://yaml.org/type/float.html>
244              
245             =item L<https://yaml.org/type/int.html>
246              
247             =item L<https://yaml.org/type/bool.html>
248              
249             =back