File Coverage

blib/lib/SHARYANTO/Array/Util.pm
Criterion Covered Total %
statement 49 49 100.0
branch 17 18 94.4
condition 5 6 83.3
subroutine 8 8 100.0
pod 2 2 100.0
total 81 83 97.5


line stmt bran cond sub pod time code
1             package SHARYANTO::Array::Util;
2              
3 1     1   21811 use 5.010;
  1         5  
  1         40  
4 1     1   5 use strict;
  1         2  
  1         39  
5 1     1   4 use warnings;
  1         1  
  1         40  
6 1     1   1019 use experimental 'smartmatch';
  1         1116  
  1         6  
7 1     1   1054 use Data::Clone;
  1         1976  
  1         458  
8              
9             require Exporter;
10             our @ISA = qw(Exporter);
11             our @EXPORT_OK = qw(
12             match_array_or_regex
13             match_regex_or_array
14             split_array
15             );
16              
17             our $VERSION = '0.75'; # VERSION
18              
19             our %SPEC;
20              
21             my $_str_or_re = ['any*'=>{of=>['re*','str*']}];
22              
23             $SPEC{match_array_or_regex} = {
24             v => 1.1,
25             summary => 'Check whether an item matches (list of) values/regexes',
26             description => <<'_',
27              
28             This routine can be used to match an item against a regex or a list of
29             strings/regexes, e.g. when matching against an ACL.
30              
31             Since the smartmatch (`~~`) operator can already match against a list of strings
32             or regexes, this function is currently basically equivalent to:
33              
34             if (reg($haystack) eq 'ARRAY') {
35             return $needle ~~ @$haystack;
36             } else {
37             return $needle =~ /$haystack/;
38             }
39              
40             _
41             examples => [
42             {args=>{needle=>"abc", haystack=>["abc", "abd"]}, result=>1},
43             {args=>{needle=>"abc", haystack=>qr/ab./}, result=>1},
44             {args=>{needle=>"abc", haystack=>[qr/ab./, "abd"]}, result=>1},
45             ],
46             args_as => 'array',
47             args => {
48             needle => {
49             schema => ["str*"],
50             pos => 0,
51             req => 1,
52             },
53             haystack => {
54             # XXX checking this schema might actually take longer than matching
55             # the needle! so when arg validation is implemented, provide a way
56             # to skip validating this schema
57              
58             schema => ["any*" => {
59             of => [$_str_or_re, ["array*"=>{of=>$_str_or_re}]],
60             }],
61             pos => 1,
62             req => 1,
63             },
64             },
65             result_naked => 1,
66             };
67             sub match_array_or_regex {
68 11     11 1 495 my ($needle, $haystack) = @_;
69 11         23 my $ref = ref($haystack);
70 11 100       40 if ($ref eq 'ARRAY') {
    100          
    100          
71 5         46 return $needle ~~ @$haystack;
72             } elsif (!$ref) {
73 1         26 return $needle =~ /$haystack/;
74             } elsif ($ref eq 'Regexp') {
75 4         35 return $needle =~ $haystack;
76             } else {
77 1         13 die "Invalid haystack, must be regex or array of strings/regexes";
78             }
79             }
80              
81             *match_regex_or_array = \&match_array_or_regex;
82             $SPEC{match_regex_or_array} = clone $SPEC{match_array_or_regex};
83             $SPEC{match_regex_or_array}{summary} = 'Alias for match_array_or_regex';
84              
85             sub split_array {
86 1     1   7 no strict 'refs';
  1         2  
  1         328  
87              
88 6     6 1 819 my ($pat, $ary, $limit) = @_;
89              
90 6 50       19 die "BUG: Second argument must be an array" unless ref($ary) eq 'ARRAY';
91 6 100       43 $pat = qr/\A\Q$pat\E\z/ unless ref($pat) eq 'Regexp';
92              
93 6         9 my @res;
94 6         8 my $num_elems = 0;
95 6         8 my $i = 0;
96             ELEM:
97 6         18 while ($i < @$ary) {
98 15         28 push @res, [];
99             COLLECT:
100 15         18 while (1) {
101 40 100       160 if ($ary->[$i] =~ $pat) {
102 10 100       32 push @res, [map { ${"$_"} } 1..@+-1] if @+ > 1;
  6         7  
  6         31  
103 10         18 last COLLECT;
104             }
105 30         29 push @{ $res[-1] }, $ary->[$i];
  30         81  
106 30 100       62 last ELEM unless ++$i < @$ary;
107             }
108 10         9 $num_elems++;
109             LIMIT:
110 10 100 66     41 if (defined($limit) && $limit > 0 && $num_elems >= $limit) {
      100        
111 1         5 push @{ $res[-1] }, $ary->[$_] for $i..(@$ary-1);
  2         6  
112 1         3 last ELEM;
113             }
114 9         21 $i++;
115             }
116              
117 6         56 return @res;
118             }
119              
120             1;
121             # ABSTRACT: Array-related utilities
122              
123             __END__