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   43 use strict;
  2         5  
4 2     2   10 use warnings;
  2         3  
  2         48  
5 2     2   10 #use Log::Any '$log';
  2         4  
  2         45  
6              
7             use Data::Dmp;
8 2     2   18  
  2         4  
  2         103  
9             use Mo qw(build default);
10 2     2   12 use Role::Tiny::With;
  2         4  
  2         17  
11 2     2   484  
  2         4  
  2         4983  
12             extends 'Data::Sah::Compiler::perl::TH';
13             with 'Data::Sah::Type::hash';
14              
15             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
16             our $DATE = '2022-09-30'; # DATE
17             our $DIST = 'Data-Sah'; # DIST
18             our $VERSION = '0.913'; # VERSION
19              
20             my ($self, $cd) = @_;
21             my $c = $self->compiler;
22 742     742 0 1462  
23 742         2255 my $dt = $cd->{data_term};
24             $cd->{_ccl_check_type} = "ref($dt) eq 'HASH'";
25 742         3779 }
26 742         2662  
27             my ($self, $which, $cd) = @_;
28             my $c = $self->compiler;
29             my $ct = $cd->{cl_term};
30 288     288 0 572 my $dt = $cd->{data_term};
31 288         2155  
32 288         1230 $c->add_runtime_module($cd, $cd->{args}{dump_module});
33 288         533  
34             if ($which eq 'is') {
35 288         997 $c->add_ccl($cd, $c->expr_dump($cd, $dt).' eq '.$c->expr_dump($cd, $ct));
36             } elsif ($which eq 'in') {
37 288 100       972 $c->add_ccl($cd, "do { my \$_sahv_dt_str = ".$c->expr_dump($cd, $dt)."; my \$_sahv_res = 0; " .
    50          
38 150         395 "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         387 }
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 230 my $dt = $cd->{data_term};
48 115         372  
49 115         503 if ($which eq 'len') {
50 115         200 $c->add_ccl($cd, "keys(\%{$dt}) == $ct");
51 115         235 } elsif ($which eq 'min_len') {
52             $c->add_ccl($cd, "keys(\%{$dt}) >= $ct");
53 115 100       559 } elsif ($which eq 'max_len') {
    100          
    100          
    100          
    100          
    100          
    50          
    0          
    0          
    0          
    0          
54 6         22 $c->add_ccl($cd, "keys(\%{$dt}) <= $ct");
55             } elsif ($which eq 'len_between') {
56 34         129 if ($cd->{cl_is_expr}) {
57             $c->add_ccl(
58 21         89 $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         37 } 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         68 } elsif ($which eq 'each_index') {
72 18         65 $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       36 $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       47 $self_th->compiler->_die_unimplemented_clause($cd);
81 18         83 } elsif ($which eq 'check_each_elem') {
82 18 50       103 $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         162  
97 55         240 # we handle subdata manually here, because in generated code for
98 55         95 # {keys,re_keys}.restrict, we haven't delved into the keys
99              
100 55         171 my $jccl;
101             {
102             local $cd->{ccls} = [];
103              
104             my $lit_valid_keys;
105 55         92 if ($which eq 'keys') {
106             $lit_valid_keys = $c->literal([sort keys %$cv]);
107 55         72 } else {
  55         114  
108             $lit_valid_keys = "[".
109 55         79 join(",", map { "qr/".$c->_str2reliteral($cd, $_)."/" }
110 55 100       116 sort keys %$cv)."]";
111 46         210 }
112              
113             $self_th->set_tmp_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
114 9         27  
  9         30  
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       3430 $c->add_ccl(
119             $cd,
120 55 100 100     247 #"!defined(List::Util::first(sub { my \$ditem=\$_; !defined(List::Util::first(sub {\$ditem ".($which eq 'keys' ? 'eq' : '=~')." \$_ }, \@{ $lit_valid_keys })) }, keys %{ $dt }))",
121 52         125 "!(grep { my \$_sahv_dt_item=\$_; !(grep { \$_sahv_dt_item ".($which eq 'keys' ? 'eq' : '=~')." \$_ } \@{ $lit_valid_keys }) } keys %{ $dt })",
122             {
123 52 100       290 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       252 if ($which eq 'keys') {
142             $cdef = $cd->{clset}{"keys.create_default"} // 1;
143 55         126 delete $cd->{uclset}{"keys.create_default"};
144             }
145 55         69  
146 55 100       110 $self_th->set_tmp_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
147 46   100     172  
148 46         75 my $nkeys = scalar(keys %$cv);
149             my $i = 0;
150             for my $k (sort keys %$cv) {
151 55 100       140 my $kre = $c->_str2reliteral($cd, $k);
152             local $cd->{spath} = [@{ $cd->{spath} }, $k];
153 55         106 ++$i;
154 55         70 my $nsch = $c->main->normalize_schema($cv->{$k});
155 55         175 my $kdn = $k; $kdn =~ s/\W+/_/g;
156 100         328 my $klit = $which eq 're_keys' ? '$_' : $c->literal($k);
157 100         3524 my $kdt = "$dt\->{$klit}";
  100         350  
158 100         152 my %iargs = %{$cd->{args}};
159 100         320 $iargs{outer_cd} = $cd;
160 100         2491 $iargs{data_name} = $kdn;
  100         230  
161 100 100       325 $iargs{data_term} = $kdt;
162 100         2644 $iargs{schema} = $nsch;
163 100         119 $iargs{schema_is_normalized} = 1;
  100         1248  
164 100         280 $iargs{cache} = $cd->{args}{cache};
165 100         187 $iargs{indent_level}++;
166 100         155 $iargs{data_term_includes_topic_var} = 1 if $which eq 're_keys';
167 100         149 my $icd = $c->compile(%iargs);
168 100         170  
169 100         237 # should we set default for hash value?
170 100         153 my $sdef = $cdef && defined($nsch->[1]{default});
171 100 100       248  
172 100         512 # stack is used to store (non-bool) subresults
173             $c->add_var($cd, '_sahv_stack', []) if $cd->{use_dpath};
174              
175 100   100     534 $c->add_runtime_module($cd, "List::Util") if $which eq 're_keys'; # for re_keys
176              
177             my @code = (
178 100 100       369 ($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       228  
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     258 }
    100 100        
    100 100        
    100          
206              
207 100         1015 $self_th->restore_data_term($cd) if $cd->{args}{data_term_includes_topic_var};
208 100         298  
209 100         3169 $jccl = $c->join_ccls(
210             $cd, $cd->{ccls}, {err_msg => ''});
211             }
212 55 100       184 $c->add_ccl($cd, $jccl, {});
213             }
214              
215 55         231 my ($self, $cd) = @_;
216             $self->_clause_keys_or_re_keys('keys', $cd);
217 55         222 }
218              
219             my ($self, $cd) = @_;
220             $self->_clause_keys_or_re_keys('re_keys', $cd);
221 46     46 0 97 }
222 46         121  
223             my ($self, $cd) = @_;
224             my $c = $self->compiler;
225             my $ct = $cd->{cl_term};
226 9     9 0 20 my $dt = $cd->{data_term};
227 9         28  
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 93 $c->add_ccl(
232 45         135 $cd,
233 45         196 "do { my \$_sahv_h = $dt; !defined(List::Util::first(sub {!exists(\$_sahv_h\->{\$_})}, \@{ $ct })) }",
234 45         90 {
235             err_msg => 'TMP',
236             err_expr =>
237             "sprintf(".
238 45         128 $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 16 "!(grep { my \$_sahv_dt_item=\$_; !(grep { \$_sahv_dt_item eq \$_ } \@{ $ct }) } keys \%{ $dt })",
254 9         26 {
255 9         39 err_msg => 'TMP',
256 9         16 err_expr =>
257             "sprintf(".
258             $c->literal($c->_xlt($cd, "hash contains non-allowed field(s) (%s)")).
259 9         34 ",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 20  
275 9         28 my $re = $c->_str2reliteral($cd, $cv);
276             #$c->add_runtime_module($cd, "List::Util");
277 9         39 $c->add_ccl(
278 9         21 $cd,
279             #"!defined(List::Util::first(sub {\$_ !~ /$re/}, keys \%{ $dt }))",
280 9 50       20 "!(grep {\$_ !~ /$re/} keys \%{ $dt })",
281             {
282 0         0 err_msg => 'TMP',
283             err_expr =>
284             "sprintf(".
285 9         30 $c->literal($c->_xlt($cd, "hash contains non-allowed field(s) (%s)")).
286             ",join(', ', sort grep { \$_ !~ /$re/ } keys \%{ $dt }))"
287 9         401 }
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         26 err_expr =>
304 9         39 "sprintf(".
305 9         19 $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         32 );
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 19 #$c->add_runtime_module($cd, "List::Util");
324 9         27 $c->add_ccl(
325             $cd,
326 9         38 #"!defined(List::Util::first(sub {\$_ =~ /$re/}, keys \%{ $dt }))",
327 9         20 "!(grep {\$_ =~ /$re/} keys \%{ $dt })",
328             {
329 9 50       20 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         21 }
335             );
336 9         356 }
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 77 }
352 36         109  
353 36         147 my ($self, $cd) = @_;
354 36         71 my $c = $self->compiler;
355             my $ct = $cd->{cl_term};
356             my $dt = $cd->{data_term};
357              
358 36         111 # we assign to $h first to avoid variable clashing if $dt is '$_'.
359 36         177  
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 75  
368 36         103 my ($self, $cd) = @_;
369 36         147 my $c = $self->compiler;
370 36         69 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         99  
375 36         191 $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 52 my ($self, $cd) = @_;
384 24         73 my $c = $self->compiler;
385 24         99 my $cv = $cd->{cl_value};
386 24         47 my $dt = $cd->{data_term};
387              
388             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
389              
390 24         65 $c->add_runtime_module($cd, "List::Util");
391 24         126 $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 110 my $c = $self->compiler;
400 60         189 my $ct = $cd->{cl_term};
401 60         255 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         167 $c->add_ccl(
407 60         271 $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 39  
416 18         54 my ($self, $cd) = @_;
417 18         75 my $c = $self->compiler;
418 18         34 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         51  
423 18         107 $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 30 my ($self, $cd) = @_;
435 18         53 my $c = $self->compiler;
436 18         114 my $ct = $cd->{cl_term};
437 18         31 my $dt = $cd->{data_term};
438              
439             # we assign to $_sahv_h first to avoid variable clashing if $dt is '$_'.
440              
441 18         53 $c->add_runtime_module($cd, "List::Util");
442 18         135 $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 65 my $c = $self->compiler;
454 24         66 my $ct = $cd->{cl_term};
455 24         108 my $dt = $cd->{data_term};
456 24         42  
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         74 $c->add_ccl(
461 24         158 $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 47  
473 24         69  
474 24         111 =pod
475 24         40  
476             =encoding UTF-8
477              
478             =head1 NAME
479 24         66  
480 24         166 Data::Sah::Compiler::perl::TH::hash - perl's type handler for type "hash"
481              
482             =head1 VERSION
483              
484             This document describes version 0.913 of Data::Sah::Compiler::perl::TH::hash (from Perl distribution Data-Sah), released on 2022-09-30.
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