File Coverage

blib/lib/Data/Sah/Compiler/perl/TH/hash.pm
Criterion Covered Total %
statement 187 194 96.3
branch 57 74 77.0
condition 16 16 100.0
subroutine 25 25 100.0
pod 0 18 0.0
total 285 327 87.1


line stmt bran cond sub pod time code
1              
2             use 5.010;
3 2     2   42 use strict;
  2         7  
4 2     2   10 use warnings;
  2         5  
  2         48  
5 2     2   10 #use Log::Any '$log';
  2         4  
  2         48  
6              
7             use Data::Dmp;
8 2     2   16  
  2         4  
  2         101  
9             use Mo qw(build default);
10 2     2   11 use Role::Tiny::With;
  2         4  
  2         9  
11 2     2   481  
  2         4  
  2         5101  
12             extends 'Data::Sah::Compiler::perl::TH';
13             with 'Data::Sah::Type::hash';
14              
15             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
16             our $DATE = '2022-08-20'; # DATE
17             our $DIST = 'Data-Sah'; # DIST
18             our $VERSION = '0.912'; # VERSION
19              
20             my ($self, $cd) = @_;
21             my $c = $self->compiler;
22 742     742 0 1403  
23 742         2294 my $dt = $cd->{data_term};
24             $cd->{_ccl_check_type} = "ref($dt) eq 'HASH'";
25 742         3472 }
26 742         2350  
27             my ($self, $which, $cd) = @_;
28             my $c = $self->compiler;
29             my $ct = $cd->{cl_term};
30 288     288 0 644 my $dt = $cd->{data_term};
31 288         892  
32 288         1244 $c->add_runtime_module($cd, $cd->{args}{dump_module});
33 288         532  
34             if ($which eq 'is') {
35 288         953 $c->add_ccl($cd, $c->expr_dump($cd, $dt).' eq '.$c->expr_dump($cd, $ct));
36             } elsif ($which eq 'in') {
37 288 100       1043 $c->add_ccl($cd, "do { my \$_sahv_dt_str = ".$c->expr_dump($cd, $dt)."; my \$_sahv_res = 0; " .
    50          
38 150         435 "for my \$_sahv_el (\@{ $ct }) { my \$_sahv_el_str = ".$c->expr_dump($cd, "\$_sahv_el")."; ".
39             "if (\$_sahv_dt_str eq \$_sahv_el_str) { \$_sahv_res = 1; last } } \$_sahv_res }");
40 138         434 }
41             }
42              
43             my ($self_th, $which, $cd) = @_;
44             my $c = $self_th->compiler;
45             my $cv = $cd->{cl_value};
46             my $ct = $cd->{cl_term};
47 115     115 0 273 my $dt = $cd->{data_term};
48 115         347  
49 115         490 if ($which eq 'len') {
50 115         205 $c->add_ccl($cd, "keys(\%{$dt}) == $ct");
51 115         222 } elsif ($which eq 'min_len') {
52             $c->add_ccl($cd, "keys(\%{$dt}) >= $ct");
53 115 100       515 } elsif ($which eq 'max_len') {
    100          
    100          
    100          
    100          
    100          
    50          
    0          
    0          
    0          
    0          
54 6         24 $c->add_ccl($cd, "keys(\%{$dt}) <= $ct");
55             } elsif ($which eq 'len_between') {
56 34         120 if ($cd->{cl_is_expr}) {
57             $c->add_ccl(
58 21         82 $cd, "keys(\%{$dt}) >= $ct\->[0] && ".
59             "keys(\%{$dt}) >= $ct\->[1]");
60 6 50       12 } else {
61 0         0 # simplify code
62             $c->add_ccl(
63             $cd, "keys(\%{$dt}) >= $cv->[0] && ".
64             "keys(\%{$dt}) <= $cv->[1]");
65             }
66 6         31 } elsif ($which eq 'has') {
67             $c->add_runtime_module($cd, $cd->{args}{dump_module});
68             $c->add_ccl($cd, "do { my \$_sahv_ct_str = ".$c->expr_dump($cd, $ct)."; my \$_sahv_res = 0; " .
69             "for my \$_sahv_el (values \%{ $dt }) { my \$_sahv_el_str = ".$c->expr_dump($cd, "\$_sahv_el")."; ".
70             "if (\$_sahv_ct_str eq \$_sahv_el_str) { \$_sahv_res = 1; last } } \$_sahv_res }");
71 18         60 } elsif ($which eq 'each_index') {
72 18         60 $self_th->set_tmp_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
73             $self_th->gen_each($cd, "sort keys(\%{$cd->{data_term}})", '', '$_');
74             $self_th->restore_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
75             } elsif ($which eq 'each_elem') {
76 12 50       33 $self_th->set_tmp_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
77 12         56 $self_th->gen_each($cd, "sort keys(\%{$cd->{data_term}})", '_', "$cd->{data_term}\->{\$_}");
78 12 50       62 $self_th->restore_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
79             } elsif ($which eq 'check_each_index') {
80 18 50       44 $self_th->compiler->_die_unimplemented_clause($cd);
81 18         94 } elsif ($which eq 'check_each_elem') {
82 18 50       91 $self_th->compiler->_die_unimplemented_clause($cd);
83             } elsif ($which eq 'uniq') {
84 0         0 $self_th->compiler->_die_unimplemented_clause($cd);
85             } elsif ($which eq 'exists') {
86 0         0 $self_th->compiler->_die_unimplemented_clause($cd);
87             }
88 0         0 }
89              
90 0         0 my ($self_th, $which, $cd) = @_;
91             my $c = $self_th->compiler;
92             my $cv = $cd->{cl_value};
93             my $dt = $cd->{data_term};
94              
95 55     55   107 local $cd->{_subdata_level} = $cd->{_subdata_level} + 1;
96 55         143  
97 55         252 # we handle subdata manually here, because in generated code for
98 55         99 # {keys,re_keys}.restrict, we haven't delved into the keys
99              
100 55         133 my $jccl;
101             {
102             local $cd->{ccls} = [];
103              
104             my $lit_valid_keys;
105 55         83 if ($which eq 'keys') {
106             $lit_valid_keys = $c->literal([sort keys %$cv]);
107 55         77 } else {
  55         100  
108             $lit_valid_keys = "[".
109 55         73 join(",", map { "qr/".$c->_str2reliteral($cd, $_)."/" }
110 55 100       124 sort keys %$cv)."]";
111 46         186 }
112              
113             $self_th->set_tmp_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
114 9         26  
  9         21  
115             if ($cd->{clset}{"$which.restrict"} // 1) {
116             local $cd->{_debug_ccl_note} = "$which.restrict";
117             #$c->add_runtime_module($cd, "List::Util");
118 55 100       3327 $c->add_ccl(
119             $cd,
120 55 100 100     255 #"!defined(List::Util::first(sub { my \$ditem=\$_; !defined(List::Util::first(sub {\$ditem ".($which eq 'keys' ? 'eq' : '=~')." \$_ }, \@{ $lit_valid_keys })) }, keys %{ $dt }))",
121 52         129 "!(grep { my \$_sahv_dt_item=\$_; !(grep { \$_sahv_dt_item ".($which eq 'keys' ? 'eq' : '=~')." \$_ } \@{ $lit_valid_keys }) } keys %{ $dt })",
122             {
123 52 100       260 err_msg => 'TMP',
    100          
124             err_expr => join(
125             "",
126             'sprintf(',
127             $c->literal($c->_xlt(
128             $cd, "hash contains ".
129             "unknown field(s) (%s)")),
130             ',',
131             "join(', ', sort grep { my \$_sahv_dt_item=\$_; !(grep { \$_sahv_dt_item ".($which eq 'keys' ? 'eq':'=~')." \$_ } \@{ $lit_valid_keys })} keys %{ $dt })",
132             ')',
133             ),
134             },
135             );
136             $self_th->restore_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
137             }
138             delete $cd->{uclset}{"$which.restrict"};
139              
140             my $cdef;
141 52 100       198 if ($which eq 'keys') {
142             $cdef = $cd->{clset}{"keys.create_default"} // 1;
143 55         122 delete $cd->{uclset}{"keys.create_default"};
144             }
145 55         71  
146 55 100       108 $self_th->set_tmp_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
147 46   100     149  
148 46         77 my $nkeys = scalar(keys %$cv);
149             my $i = 0;
150             for my $k (sort keys %$cv) {
151 55 100       148 my $kre = $c->_str2reliteral($cd, $k);
152             local $cd->{spath} = [@{ $cd->{spath} }, $k];
153 55         97 ++$i;
154 55         86 my $nsch = $c->main->normalize_schema($cv->{$k});
155 55         151 my $kdn = $k; $kdn =~ s/\W+/_/g;
156 100         289 my $klit = $which eq 're_keys' ? '$_' : $c->literal($k);
157 100         3558 my $kdt = "$dt\->{$klit}";
  100         310  
158 100         149 my %iargs = %{$cd->{args}};
159 100         280 $iargs{outer_cd} = $cd;
160 100         2425 $iargs{data_name} = $kdn;
  100         227  
161 100 100       342 $iargs{data_term} = $kdt;
162 100         2604 $iargs{schema} = $nsch;
163 100         143 $iargs{schema_is_normalized} = 1;
  100         1118  
164 100         272 $iargs{cache} = $cd->{args}{cache};
165 100         181 $iargs{indent_level}++;
166 100         170 $iargs{data_term_includes_topic_var} = 1 if $which eq 're_keys';
167 100         164 my $icd = $c->compile(%iargs);
168 100         162  
169 100         253 # should we set default for hash value?
170 100         167 my $sdef = $cdef && defined($nsch->[1]{default});
171 100 100       228  
172 100         510 # stack is used to store (non-bool) subresults
173             $c->add_var($cd, '_sahv_stack', []) if $cd->{use_dpath};
174              
175 100   100     539 $c->add_runtime_module($cd, "List::Util") if $which eq 're_keys'; # for re_keys
176              
177             my @code = (
178 100 100       374 ($c->indent_str($cd), "(push(@\$_sahv_dpath, undef), push(\@\$_sahv_stack, undef), \$_sahv_stack->[-1] = \n")
179             x !!($cd->{use_dpath} && $i == 1),
180 100 100       247  
181             # for re_keys, we iterate over all data's keys which match regex
182             ('(!defined(List::Util::first(sub {!(')
183             x !!($which eq 're_keys'),
184              
185             $which eq 're_keys' ? "\$_ !~ /$kre/ || (" :
186             ($sdef ? "" : "!exists($kdt) || ("),
187              
188             ($c->indent_str($cd), "(\$_sahv_dpath->[-1] = ".
189             ($which eq 're_keys' ? '$_' : $klit)."),\n")
190             x !!$cd->{use_dpath},
191             $icd->{result}, "\n",
192              
193             $which eq 're_keys' || !$sdef ? ")" : "",
194              
195             # close iteration over all data's keys which match regex
196             (")}, sort keys %{ $dt })))")
197             x !!($which eq 're_keys'),
198              
199             ($c->indent_str($cd), "), pop(\@\$_sahv_dpath), pop(\@\$_sahv_stack)\n")
200             x !!($cd->{use_dpath} && $i == $nkeys),
201             );
202             my $ires = join("", @code);
203             local $cd->{_debug_ccl_note} = "$which: ".$c->literal($k);
204             $c->add_ccl($cd, $ires);
205 100 100 100     264 }
    100 100        
    100 100        
    100          
206              
207 100         1011 $self_th->restore_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
208 100         297  
209 100         3134 $jccl = $c->join_ccls(
210             $cd, $cd->{ccls}, {err_msg => ''});
211             }
212 55 100       172 $c->add_ccl($cd, $jccl, {});
213             }
214              
215 55         201 my ($self, $cd) = @_;
216             $self->_clause_keys_or_re_keys('keys', $cd);
217 55         225 }
218              
219             my ($self, $cd) = @_;
220             $self->_clause_keys_or_re_keys('re_keys', $cd);
221 46     46 0 103 }
222 46         127  
223             my ($self, $cd) = @_;
224             my $c = $self->compiler;
225             my $ct = $cd->{cl_term};
226 9     9 0 16 my $dt = $cd->{data_term};
227 9         29  
228             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
229              
230             $c->add_runtime_module($cd, "List::Util");
231 45     45 0 87 $c->add_ccl(
232 45         125 $cd,
233 45         193 "do { my \$_sahv_h = $dt; !defined(List::Util::first(sub {!exists(\$_sahv_h\->{\$_})}, \@{ $ct })) }",
234 45         79 {
235             err_msg => 'TMP',
236             err_expr =>
237             "sprintf(".
238 45         130 $c->literal($c->_xlt($cd, "hash has missing required field(s) (%s)")).
239 45         217 ",join(', ', do { my \$_sahv_h = $dt; grep { !exists(\$_sahv_h\->{\$_}) } \@{ $ct } }))"
240             }
241             );
242             }
243              
244             my ($self, $cd) = @_;
245             my $c = $self->compiler;
246             my $ct = $cd->{cl_term};
247             my $dt = $cd->{data_term};
248              
249             #$c->add_runtime_module($cd, "List::Util");
250             $c->add_ccl(
251             $cd,
252             #"!defined(List::Util::first(sub { my \$_sahv_dt_item=\$_; !defined(List::Util::first!(sub { \$_sahv_dt_item eq \$_ }, \@{ $ct })) }, keys \%{ $dt }))",
253 9     9 0 19 "!(grep { my \$_sahv_dt_item=\$_; !(grep { \$_sahv_dt_item eq \$_ } \@{ $ct }) } keys \%{ $dt })",
254 9         25 {
255 9         40 err_msg => 'TMP',
256 9         11 err_expr =>
257             "sprintf(".
258             $c->literal($c->_xlt($cd, "hash contains non-allowed field(s) (%s)")).
259 9         32 ",join(', ', sort grep { my \$_sahv_dt_item=\$_; !(grep { \$_sahv_dt_item eq \$_ } \@{ $ct }) } keys \%{ $dt }))"
260             }
261             );
262             }
263              
264             my ($self, $cd) = @_;
265             my $c = $self->compiler;
266             #my $ct = $cd->{cl_term};
267             my $cv = $cd->{cl_value};
268             my $dt = $cd->{data_term};
269              
270             if ($cd->{cl_is_expr}) {
271             # i'm lazy atm and does not need expr yet
272             $c->_die_unimplemented_clause($cd, "with expr");
273             }
274 9     9 0 19  
275 9         24 my $re = $c->_str2reliteral($cd, $cv);
276             #$c->add_runtime_module($cd, "List::Util");
277 9         39 $c->add_ccl(
278 9         18 $cd,
279             #"!defined(List::Util::first(sub {\$_ !~ /$re/}, keys \%{ $dt }))",
280 9 50       22 "!(grep {\$_ !~ /$re/} keys \%{ $dt })",
281             {
282 0         0 err_msg => 'TMP',
283             err_expr =>
284             "sprintf(".
285 9         21 $c->literal($c->_xlt($cd, "hash contains non-allowed field(s) (%s)")).
286             ",join(', ', sort grep { \$_ !~ /$re/ } keys \%{ $dt }))"
287 9         361 }
288             );
289             }
290              
291             my ($self, $cd) = @_;
292             my $c = $self->compiler;
293             my $ct = $cd->{cl_term};
294             my $dt = $cd->{data_term};
295              
296             #$c->add_runtime_module($cd, "List::Util");
297             $c->add_ccl(
298             $cd,
299             #"!defined(List::Util::first(sub {\$_ ~~ $ct}, keys \%{ $dt }))",
300             "!(grep { my \$_sahv_dt_item=\$_; !!(grep { \$_sahv_dt_item eq \$_ } \@{ $ct }) } keys \%{ $dt })",
301             {
302 9     9 0 17 err_msg => 'TMP',
303 9         23 err_expr =>
304 9         43 "sprintf(".
305 9         15 $c->literal($c->_xlt($cd, "hash contains forbidden field(s) (%s)")).
306             ",join(', ', sort grep { my \$_sahv_dt_item=\$_; !(grep { \$_sahv_dt_item eq \$_ } \@{ $ct }) } keys \%{ $dt }))"
307             }
308 9         36 );
309             }
310              
311             my ($self, $cd) = @_;
312             my $c = $self->compiler;
313             #my $ct = $cd->{cl_term};
314             my $cv = $cd->{cl_value};
315             my $dt = $cd->{data_term};
316              
317             if ($cd->{cl_is_expr}) {
318             # i'm lazy atm and does not need expr yet
319             $c->_die_unimplemented_clause($cd, "with expr");
320             }
321              
322             my $re = $c->_str2reliteral($cd, $cv);
323 9     9 0 21 #$c->add_runtime_module($cd, "List::Util");
324 9         26 $c->add_ccl(
325             $cd,
326 9         38 #"!defined(List::Util::first(sub {\$_ =~ /$re/}, keys \%{ $dt }))",
327 9         16 "!(grep {\$_ =~ /$re/} keys \%{ $dt })",
328             {
329 9 50       21 err_msg => 'TMP',
330             err_expr =>
331 0         0 "sprintf(".
332             $c->literal($c->_xlt($cd, "hash contains forbidden field(s) (%s)")).
333             ",join(', ', sort grep { \$_ =~ /$re/ } keys \%{ $dt }))"
334 9         26 }
335             );
336 9         393 }
337              
338             my ($self, $cd) = @_;
339             my $c = $self->compiler;
340             my $ct = $cd->{cl_term};
341             my $dt = $cd->{data_term};
342              
343             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
344              
345             $c->add_runtime_module($cd, "List::Util");
346             $c->add_ccl(
347             $cd,
348             "do { my \$_sahv_h = $dt; List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ $ct }) <= 1 }",
349             {},
350             );
351 36     36 0 71 }
352 36         102  
353 36         152 my ($self, $cd) = @_;
354 36         69 my $c = $self->compiler;
355             my $ct = $cd->{cl_term};
356             my $dt = $cd->{data_term};
357              
358 36         94 # we assign to $h first to avoid variable clashing if $dt is '$_'.
359 36         169  
360             $c->add_runtime_module($cd, "List::Util");
361             $c->add_ccl(
362             $cd,
363             "do { my \$_sahv_h = $dt; my \$_sahv_keys = $ct; my \$_sahv_tot = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@\$_sahv_keys); \$_sahv_tot==0 || \$_sahv_tot==\@\$_sahv_keys }",
364             {},
365             );
366             }
367 36     36 0 76  
368 36         102 my ($self, $cd) = @_;
369 36         154 my $c = $self->compiler;
370 36         67 my $ct = $cd->{cl_term};
371             my $dt = $cd->{data_term};
372              
373             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
374 36         91  
375 36         173 $c->add_runtime_module($cd, "List::Util");
376             $c->add_ccl(
377             $cd,
378             "do { my \$_sahv_h = $dt; List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ $ct }) == 1 }",
379             {},
380             );
381             }
382              
383 24     24 0 50 my ($self, $cd) = @_;
384 24         102 my $c = $self->compiler;
385 24         113 my $cv = $cd->{cl_value};
386 24         49 my $dt = $cd->{data_term};
387              
388             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
389              
390 24         74 $c->add_runtime_module($cd, "List::Util");
391 24         124 $c->add_ccl(
392             $cd,
393             "do { my \$_sahv_h = $dt; my \$_sahv_n = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ ".$c->literal($cv->[2])." }); \$_sahv_n >= $cv->[0] && \$_sahv_n <= $cv->[1] }",
394             {},
395             );
396             }
397              
398             my ($self, $cd) = @_;
399 60     60 0 109 my $c = $self->compiler;
400 60         157 my $ct = $cd->{cl_term};
401 60         246 my $dt = $cd->{data_term};
402 60         107  
403             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
404              
405             $c->add_runtime_module($cd, "List::Util");
406 60         158 $c->add_ccl(
407 60         254 $cd,
408             "do { my \$_sahv_h = $dt; my \$_sahv_ct = $ct; ".
409             "my \$_sahv_has_prereq = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ \$_sahv_ct->[1] }) ? 1:0; ".
410             "my \$_sahv_has_dep = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} (ref(\$_sahv_ct->[0]) eq 'ARRAY' ? \@{ \$_sahv_ct->[0] } : (\$_sahv_ct->[0]))) ? 1:0; ".
411             "!\$_sahv_has_dep || \$_sahv_has_prereq }",
412             {},
413             );
414             }
415 18     18 0 31  
416 18         49 my ($self, $cd) = @_;
417 18         74 my $c = $self->compiler;
418 18         32 my $ct = $cd->{cl_term};
419             my $dt = $cd->{data_term};
420              
421             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
422 18         45  
423 18         431 $c->add_runtime_module($cd, "List::Util");
424             $c->add_ccl(
425             $cd,
426             "do { my \$_sahv_h = $dt; my \$_sahv_ct = $ct; ".
427             "my \$_sahv_has_prereq = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ \$_sahv_ct->[1] }) == \@{ \$_sahv_ct->[1] } ? 1:0; ".
428             "my \$_sahv_has_dep = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} (ref(\$_sahv_ct->[0]) eq 'ARRAY' ? \@{ \$_sahv_ct->[0] } : (\$_sahv_ct->[0]))) ? 1:0; ".
429             "!\$_sahv_has_dep || \$_sahv_has_prereq }",
430             {},
431             );
432             }
433              
434 18     18 0 36 my ($self, $cd) = @_;
435 18         49 my $c = $self->compiler;
436 18         76 my $ct = $cd->{cl_term};
437 18         30 my $dt = $cd->{data_term};
438              
439             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
440              
441 18         46 $c->add_runtime_module($cd, "List::Util");
442 18         109 $c->add_ccl(
443             $cd,
444             "do { my \$_sahv_h = $dt; my \$_sahv_ct = $ct; ".
445             "my \$_sahv_has_prereq = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ \$_sahv_ct->[1] }) ? 1:0; ".
446             "my \$_sahv_has_dep = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} (ref(\$_sahv_ct->[0]) eq 'ARRAY' ? \@{ \$_sahv_ct->[0] } : (\$_sahv_ct->[0]))) ? 1:0; ".
447             "\$_sahv_has_dep || !\$_sahv_has_prereq }",
448             {},
449             );
450             }
451              
452             my ($self, $cd) = @_;
453 24     24 0 45 my $c = $self->compiler;
454 24         59 my $ct = $cd->{cl_term};
455 24         99 my $dt = $cd->{data_term};
456 24         43  
457             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
458              
459             $c->add_runtime_module($cd, "List::Util");
460 24         59 $c->add_ccl(
461 24         131 $cd,
462             "do { my \$_sahv_h = $dt; my \$_sahv_ct = $ct; ".
463             "my \$_sahv_has_prereq = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} \@{ \$_sahv_ct->[1] }) == \@{ \$_sahv_ct->[1] } ? 1:0; ".
464             "my \$_sahv_has_dep = List::Util::sum(map {exists(\$_sahv_h\->{\$_}) ? 1:0} (ref(\$_sahv_ct->[0]) eq 'ARRAY' ? \@{ \$_sahv_ct->[0] } : (\$_sahv_ct->[0]))) ? 1:0; ".
465             "\$_sahv_has_dep || !\$_sahv_has_prereq }",
466             {},
467             );
468             }
469              
470             1;
471             # ABSTRACT: perl's type handler for type "hash"
472 24     24 0 46  
473 24         63  
474 24         99 =pod
475 24         55  
476             =encoding UTF-8
477              
478             =head1 NAME
479 24         65  
480 24         146 Data::Sah::Compiler::perl::TH::hash - perl's type handler for type "hash"
481              
482             =head1 VERSION
483              
484             This document describes version 0.912 of Data::Sah::Compiler::perl::TH::hash (from Perl distribution Data-Sah), released on 2022-08-20.
485              
486             =for Pod::Coverage ^(clause_.+|superclause_.+)$
487              
488             =head1 HOMEPAGE
489              
490             Please visit the project's homepage at L<https://metacpan.org/release/Data-Sah>.
491              
492             =head1 SOURCE
493              
494             Source repository is at L<https://github.com/perlancar/perl-Data-Sah>.
495              
496             =head1 AUTHOR
497              
498             perlancar <perlancar@cpan.org>
499              
500             =head1 CONTRIBUTING
501              
502              
503             To contribute, you can send patches by email/via RT, or send pull requests on
504             GitHub.
505              
506             Most of the time, you don't need to build the distribution yourself. You can
507             simply modify the code, then test via:
508              
509             % prove -l
510              
511             If you want to build the distribution (e.g. to try to install it locally on your
512             system), you can install L<Dist::Zilla>,
513             L<Dist::Zilla::PluginBundle::Author::PERLANCAR>,
514             L<Pod::Weaver::PluginBundle::Author::PERLANCAR>, and sometimes one or two other
515             Dist::Zilla- and/or Pod::Weaver plugins. Any additional steps required beyond
516             that are considered a bug and can be reported to me.
517              
518             =head1 COPYRIGHT AND LICENSE
519              
520             This software is copyright (c) 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012 by perlancar <perlancar@cpan.org>.
521              
522             This is free software; you can redistribute it and/or modify it under
523             the same terms as the Perl 5 programming language system itself.
524              
525             =head1 BUGS
526              
527             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah>
528              
529             When submitting a bug or request, please include a test-file or a
530             patch to an existing test-file that illustrates the bug or desired
531             feature.
532              
533             =cut