File Coverage

blib/lib/Package/CopyFrom.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::CopyFrom;
3              
4             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
5             our $DATE = '2020-02-16'; # DATE
6             our $DIST = 'Package-CopyFrom'; # DIST
7             our $VERSION = '0.002'; # VERSION
8              
9 1     1   65074 use strict 'subs', 'vars';
  1         13  
  1         34  
10 1     1   5 use warnings;
  1         2  
  1         24  
11 1     1   1594 use Log::ger;
  1         52  
  1         5  
12              
13             require Exporter;
14             our @ISA = qw(Exporter);
15             our @EXPORT = qw(copy_from);
16              
17             sub _list_pkg_contents {
18 24     24   34 my $pkg = shift;
19              
20 24         36 my %contents;
21 24         31 my $symtbl = \%{"$pkg\::"};
  24         75  
22 24         101 for my $key (keys %$symtbl) {
23 418         784 my $val = $symtbl->{$key};
24             #print "key=$key, val=$val, ref val=", ref($val), "\n";
25 418 100       876 next if $key =~ /::\z/; # skip subpackages
26             $contents{$key} = 1 if ref $val eq 'CODE' || # perl >= 5.22
27 286 100 66     949 defined *$val{CODE};
28 286 50       830 $contents{"\$$key"} = 1 if defined *$val{SCALAR};
29 286 100       663 $contents{"\@$key"} = 1 if defined *$val{ARRAY};
30 286 100       913 $contents{"\%$key"} = 1 if defined *$val{HASH};
31             }
32 24         189 %contents;
33             }
34              
35             sub copy_from {
36 12 100   12 1 397 my $opts = ref $_[0] eq 'HASH' ? shift : {};
37 12         23 my $src_pkg = shift;
38              
39 12 100       33 $opts->{load} = 1 unless defined $opts->{load};
40 12 100       27 if ($opts->{dclone}) {
41 1         711 require Storable;
42             }
43              
44 12         3603 (my $src_pkg_pm = "$src_pkg.pm") =~ s!::!/!g;
45 12 100       33 if ($opts->{load}) {
46 11 100       702 require $src_pkg_pm unless $INC{$src_pkg_pm};
47             }
48 12         27 my %src_contents = _list_pkg_contents($src_pkg);
49              
50 12         32 my $target_pkg = $opts->{to};
51 12 100       36 $target_pkg = caller unless defined $target_pkg;
52 12         31 my %target_contents = _list_pkg_contents($target_pkg);
53              
54             NAME:
55 12         136 for my $name (sort keys %src_contents) {
56 315         455 my $skip;
57 315 100 100     951 if ($name =~ /\A\$/ && $opts->{skip_scalar}) {
58 16         54 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_scalar=1)";
59 16         39 $skip++; goto SKIPPING;
  16         40  
60             }
61 299 100 100     651 if ($name =~ /\A\@/ && $opts->{skip_array}) {
62 4         17 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_array=1)";
63 4         11 $skip++; goto SKIPPING;
  4         12  
64             }
65 295 100 100     578 if ($name =~ /\A\%/ && $opts->{skip_hash}) {
66 3         11 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_hash=1)";
67 3         8 $skip++; goto SKIPPING;
  3         9  
68             }
69 292 100 100     665 if ($name !~ /\A[\$\@\%]/ && $opts->{skip_sub}) {
70 3         30 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_sub=1)";
71 3         8 $skip++; goto SKIPPING;
  3         13  
72             }
73 289 100 100     548 if ($opts->{exclude} && grep { $name eq $_ } @{ $opts->{exclude} }) {
  104         202  
  26         44  
74 4         13 log_trace "Not copying $name from $src_pkg to $target_pkg (listed in exclude)";
75 4         12 $skip++; goto SKIPPING;
  4         13  
76             }
77              
78 285 100       494 my $overwrite = exists $target_contents{$name} ? 1:0;
79              
80 285 100       453 if ($opts->{_before_copy}) {
81 26 100       54 $skip = 1 if $opts->{_before_copy}->($name, $src_pkg, $target_pkg, $opts, $overwrite);
82             }
83 285 100       577 if ($skip) {
84 7         23 log_trace "Not copying $name from $src_pkg to $target_pkg (_before_copy)";
85 7         25 next NAME;
86             }
87              
88             SKIPPING:
89             {
90 308 100       371 last unless $skip;
  308         496  
91 30 50       52 if ($opts->{_on_skip}) {
92 0         0 $opts->{_on_skip}->($name, $src_pkg, $target_pkg, $opts);
93             }
94 30         54 next NAME;
95             }
96              
97 278 100       400 if ($overwrite) {
98 82         241 log_trace "Overwriting $name from $src_pkg to $target_pkg";
99             } else {
100 196         536 log_trace "Copying $name from $src_pkg to $target_pkg ...";
101             }
102              
103 278 100       1108 if ($name =~ /\A\$(.+)/) {
    100          
    100          
104 1     1   946 no warnings 'once', 'redefine';
  1         4  
  1         95  
105 173         225 ${"$target_pkg\::$1"} = ${"$src_pkg\::$1"};
  173         562  
  173         482  
106             } elsif ($name =~ /\A\@(.+)/) {
107 1     1   7 no warnings 'once', 'redefine';
  1         2  
  1         152  
108 42 100       73 @{"$target_pkg\::$1"} = $opts->{dclone} ? @{ Storable::dclone(\@{"$src_pkg\::$1"}) } : @{"$src_pkg\::$1"};
  42         277  
  4         6  
  4         54  
  38         114  
109             } elsif ($name =~ /\A\%(.+)/) {
110 1     1   8 no warnings 'once', 'redefine';
  1         2  
  1         93  
111 31 100       66 %{"$target_pkg\::$1"} = $opts->{dclone} ? %{ Storable::dclone(\%{"$src_pkg\::$1"}) } : %{"$src_pkg\::$1"};
  31         112  
  3         5  
  3         116  
  28         102  
112             } else {
113 1     1   7 no warnings 'once', 'redefine';
  1         1  
  1         209  
114 32         45 *{"$target_pkg\::$name"} = \&{"$src_pkg\::$name"};
  32         90  
  32         86  
115             }
116 278 100       906 if ($opts->{_after_copy}) {
117 26         49 $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__