File Coverage

blib/lib/Package/CopyContents.pm
Criterion Covered Total %
statement 101 102 99.0
branch 56 58 96.5
condition 17 18 94.4
subroutine 9 9 100.0
pod 1 1 100.0
total 184 188 97.8


line stmt bran cond sub pod time code
1             ## no critic: Modules::ProhibitAutomaticExportation
2             package Package::CopyContents;
3              
4             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
5             our $DATE = '2020-02-16'; # DATE
6             our $DIST = 'Package-CopyContents'; # DIST
7             our $VERSION = '0.004'; # VERSION
8              
9 1     1   53701 use strict 'subs', 'vars';
  1         8  
  1         28  
10 1     1   4 use warnings;
  1         2  
  1         20  
11 1     1   1280 use Log::ger;
  1         39  
  1         4  
12              
13             require Exporter;
14             our @ISA = qw(Exporter);
15             our @EXPORT = qw(copy_contents_from);
16              
17             sub _list_pkg_contents {
18 24     24   32 my $pkg = shift;
19              
20 24         29 my %contents;
21 24         24 my $symtbl = \%{"$pkg\::"};
  24         58  
22 24         80 for my $key (keys %$symtbl) {
23 418         628 my $val = $symtbl->{$key};
24             #print "key=$key, val=$val, ref val=", ref($val), "\n";
25 418 100       758 next if $key =~ /::\z/; # skip subpackages
26             $contents{$key} = 1 if ref $val eq 'CODE' || # perl >= 5.22
27 286 100 66     731 defined *$val{CODE};
28 286 50       656 $contents{"\$$key"} = 1 if defined *$val{SCALAR};
29 286 100       527 $contents{"\@$key"} = 1 if defined *$val{ARRAY};
30 286 100       599 $contents{"\%$key"} = 1 if defined *$val{HASH};
31             }
32 24         151 %contents;
33             }
34              
35             sub copy_contents_from {
36 12 100   12 1 323 my $opts = ref $_[0] eq 'HASH' ? shift : {};
37 12         18 my $src_pkg = shift;
38              
39 12 100       30 $opts->{load} = 1 unless defined $opts->{load};
40 12 100       23 if ($opts->{dclone}) {
41 1         549 require Storable;
42             }
43              
44 12         2903 (my $src_pkg_pm = "$src_pkg.pm") =~ s!::!/!g;
45 12 100       27 if ($opts->{load}) {
46 11 100       587 require $src_pkg_pm unless $INC{$src_pkg_pm};
47             }
48 12         20 my %src_contents = _list_pkg_contents($src_pkg);
49              
50 12         30 my $target_pkg = $opts->{to};
51 12 100       28 $target_pkg = caller unless defined $target_pkg;
52 12         28 my %target_contents = _list_pkg_contents($target_pkg);
53              
54             NAME:
55 12         112 for my $name (sort keys %src_contents) {
56 315         369 my $skip;
57 315 100 100     756 if ($name =~ /\A\$/ && $opts->{skip_scalar}) {
58 16         42 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_scalar=1)";
59 16         33 $skip++; goto SKIPPING;
  16         31  
60             }
61 299 100 100     551 if ($name =~ /\A\@/ && $opts->{skip_array}) {
62 4         13 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_array=1)";
63 4         8 $skip++; goto SKIPPING;
  4         9  
64             }
65 295 100 100     514 if ($name =~ /\A\%/ && $opts->{skip_hash}) {
66 3         10 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_hash=1)";
67 3         6 $skip++; goto SKIPPING;
  3         8  
68             }
69 292 100 100     856 if ($name !~ /\A[\$\@\%]/ && $opts->{skip_sub}) {
70 3         11 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_sub=1)";
71 3         7 $skip++; goto SKIPPING;
  3         8  
72             }
73 289 100 100     440 if ($opts->{exclude} && grep { $name eq $_ } @{ $opts->{exclude} }) {
  104         167  
  26         36  
74 4         13 log_trace "Not copying $name from $src_pkg to $target_pkg (listed in exclude)";
75 4         9 $skip++; goto SKIPPING;
  4         11  
76             }
77              
78 285 100       403 my $overwrite = exists $target_contents{$name} ? 1:0;
79              
80 285 100       376 if ($opts->{_before_copy}) {
81 26 100       42 $skip = 1 if $opts->{_before_copy}->($name, $src_pkg, $target_pkg, $opts, $overwrite);
82             }
83 285 100       474 if ($skip) {
84 7         18 log_trace "Not copying $name from $src_pkg to $target_pkg (_before_copy)";
85 7         21 next NAME;
86             }
87              
88             SKIPPING:
89             {
90 308 100       314 last unless $skip;
  308         440  
91 30 50       45 if ($opts->{_on_skip}) {
92 0         0 $opts->{_on_skip}->($name, $src_pkg, $target_pkg, $opts);
93             }
94 30         43 next NAME;
95             }
96              
97 278 100       360 if ($overwrite) {
98 82         191 log_trace "Overwriting $name from $src_pkg to $target_pkg";
99             } else {
100 196         438 log_trace "Copying $name from $src_pkg to $target_pkg ...";
101             }
102              
103 278 100       951 if ($name =~ /\A\$(.+)/) {
    100          
    100          
104 1     1   751 no warnings 'once', 'redefine';
  1         2  
  1         74  
105 173         195 ${"$target_pkg\::$1"} = ${"$src_pkg\::$1"};
  173         468  
  173         408  
106             } elsif ($name =~ /\A\@(.+)/) {
107 1     1   5 no warnings 'once', 'redefine';
  1         2  
  1         106  
108 42 100       71 @{"$target_pkg\::$1"} = $opts->{dclone} ? @{ Storable::dclone(\@{"$src_pkg\::$1"}) } : @{"$src_pkg\::$1"};
  42         237  
  4         6  
  4         43  
  38         90  
109             } elsif ($name =~ /\A\%(.+)/) {
110 1     1   6 no warnings 'once', 'redefine';
  1         1  
  1         76  
111 31 100       48 %{"$target_pkg\::$1"} = $opts->{dclone} ? %{ Storable::dclone(\%{"$src_pkg\::$1"}) } : %{"$src_pkg\::$1"};
  31         98  
  3         4  
  3         92  
  28         94  
112             } else {
113 1     1   5 no warnings 'once', 'redefine';
  1         2  
  1         167  
114 32         34 *{"$target_pkg\::$name"} = \&{"$src_pkg\::$name"};
  32         77  
  32         72  
115             }
116 278 100       703 if ($opts->{_after_copy}) {
117 26         45 $opts->{_after_copy}->($name, $src_pkg, $target_pkg, $opts, $overwrite);
118             }
119             }
120             }
121              
122             1;
123             # ABSTRACT: Copy (some) contents from another package
124              
125             __END__