File Coverage

blib/lib/Package/MoreUtil.pm
Criterion Covered Total %
statement 75 77 97.4
branch 25 32 78.1
condition 11 19 57.8
subroutine 11 11 100.0
pod 4 4 100.0
total 126 143 88.1


line stmt bran cond sub pod time code
1             package Package::MoreUtil;
2              
3             our $DATE = '2019-12-25'; # DATE
4             our $VERSION = '0.592'; # VERSION
5              
6 1     1   66276 use 5.010001;
  1         13  
7 1     1   5 use strict;
  1         2  
  1         35  
8 1     1   5 use warnings;
  1         3  
  1         90  
9              
10             require Exporter;
11             our @ISA = qw(Exporter);
12             our @EXPORT_OK = qw(
13             package_exists
14             list_package_contents
15             list_package_subs
16             list_subpackages
17             );
18              
19             sub package_exists {
20 1     1   7 no strict 'refs';
  1         2  
  1         151  
21              
22 13     13 1 106 my $pkg = shift;
23              
24             # opt
25             #return unless $pkg =~ /\A\w+(::\w+)*\z/;
26              
27 13 100       82 if ($pkg =~ s/::(\w+)\z//) {
28 3         5 return !!${$pkg . "::"}{$1 . "::"};
  3         20  
29             } else {
30 10         62 return !!$::{$pkg . "::"};
31             }
32             }
33              
34             # XXX incomplete/improper
35             sub list_package_contents {
36 1     1   7 no strict 'refs';
  1         2  
  1         291  
37              
38 2     2 1 5 my $pkg = shift;
39              
40 2 50 33     9 return () unless !length($pkg) || package_exists($pkg);
41 2         5 my $symtbl = \%{$pkg . "::"};
  2         7  
42              
43 2         3 my %res;
44 2         13 while (my ($k, $v) = each %$symtbl) {
45 251 100       639 next if $k =~ /::$/; # subpackage
46 184         226 my $n;
47 184 50       611 if ("$v" !~ /^\*/) {
48             # constant
49 0         0 $res{$k} = $v;
50 0         0 next;
51             }
52 184 100       446 if (defined *$v{CODE}) {
53 32         66 $res{$k} = *$v{CODE}; # subroutine
54 32         54 $n++;
55             }
56 184 100       379 if (defined *$v{HASH}) {
57 6         9 $res{"\%$k"} = \%{*$v}; # hash
  6         17  
58 6         11 $n++;
59             }
60 184 100       364 if (defined *$v{ARRAY}) {
61 4         6 $res{"\@$k"} = \@{*$v}; # array
  4         11  
62 4         7 $n++;
63             }
64 184 100 66     404 if (defined(*$v{SCALAR}) # XXX always defined?
65 184         533 && defined(${*$v})) { # currently we filter undef values
66 127         184 $res{"\$$k"} = \${*$v}; # scalar
  127         332  
67 127         204 $n++;
68             }
69              
70 184 100       629 if (!$n) {
71 21         90 $res{"\*$k"} = $v; # glob
72             }
73             }
74              
75 2         40 %res;
76             }
77              
78             # XXX incomplete/improper too?
79             sub list_package_subs {
80 1     1   8 no strict 'refs';
  1         2  
  1         139  
81              
82 2     2 1 707 my $pkg = shift;
83              
84 2 50 33     13 return () unless !length($pkg) || package_exists($pkg);
85 2         5 my $symtbl = \%{$pkg . "::"};
  2         7  
86              
87 2         4 my @res;
88 2         11 while (my ($k, $v) = each %$symtbl) {
89 251 100 66     1144 if (
90             ref $v eq 'CODE' || # perl >= 5.22
91             defined *$v{CODE}) {
92 32         130 push @res, $k;
93             }
94             }
95              
96 2         11 @res;
97             }
98              
99             sub list_subpackages {
100 1     1   7 no strict 'refs';
  1         2  
  1         214  
101              
102 5     5 1 539 my ($pkg, $recursive, $cur_res, $ref_mem) = @_;
103              
104 5 50 33     18 return () unless !length($pkg) || package_exists($pkg);
105              
106             # this is used to avoid deep recursion. for example (the only one?) %:: and
107             # %main:: point to the same thing.
108 5   100     20 $ref_mem //= {};
109              
110 5         8 my $symtbl = \%{$pkg . "::"};
  5         15  
111 5 50       20 return () if $ref_mem->{"$symtbl"}++;
112              
113 5   100     16 my $res = $cur_res // [];
114 5         16 for (sort keys %$symtbl) {
115 4 50       23 next unless s/::$//;
116 4 50       14 my $name = (length($pkg) ? "$pkg\::" : "" ) . $_;
117 4         8 push @$res, $name;
118 4 100       27 list_subpackages($name, 1, $res, $ref_mem) if $recursive;
119             }
120              
121 5         26 @$res;
122             }
123              
124             1;
125             # ABSTRACT: Package-related utilities
126              
127             __END__