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.003'; # VERSION
8              
9 1     1   66242 use strict 'subs', 'vars';
  1         10  
  1         35  
10 1     1   6 use warnings;
  1         2  
  1         27  
11 1     1   1610 use Log::ger;
  1         51  
  1         6  
12              
13             require Exporter;
14             our @ISA = qw(Exporter);
15             our @EXPORT = qw(copy_from);
16              
17             sub _list_pkg_contents {
18 24     24   40 my $pkg = shift;
19              
20 24         31 my %contents;
21 24         28 my $symtbl = \%{"$pkg\::"};
  24         75  
22 24         99 for my $key (keys %$symtbl) {
23 418         742 my $val = $symtbl->{$key};
24             #print "key=$key, val=$val, ref val=", ref($val), "\n";
25 418 100       874 next if $key =~ /::\z/; # skip subpackages
26             $contents{$key} = 1 if ref $val eq 'CODE' || # perl >= 5.22
27 286 100 66     921 defined *$val{CODE};
28 286 50       871 $contents{"\$$key"} = 1 if defined *$val{SCALAR};
29 286 100       645 $contents{"\@$key"} = 1 if defined *$val{ARRAY};
30 286 100       698 $contents{"\%$key"} = 1 if defined *$val{HASH};
31             }
32 24         191 %contents;
33             }
34              
35             sub copy_from {
36 12 100   12 1 412 my $opts = ref $_[0] eq 'HASH' ? shift : {};
37 12         22 my $src_pkg = shift;
38              
39 12 100       38 $opts->{load} = 1 unless defined $opts->{load};
40 12 100       26 if ($opts->{dclone}) {
41 1         731 require Storable;
42             }
43              
44 12         3643 (my $src_pkg_pm = "$src_pkg.pm") =~ s!::!/!g;
45 12 100       30 if ($opts->{load}) {
46 11 100       722 require $src_pkg_pm unless $INC{$src_pkg_pm};
47             }
48 12         26 my %src_contents = _list_pkg_contents($src_pkg);
49              
50 12         33 my $target_pkg = $opts->{to};
51 12 100       35 $target_pkg = caller unless defined $target_pkg;
52 12         31 my %target_contents = _list_pkg_contents($target_pkg);
53              
54             NAME:
55 12         138 for my $name (sort keys %src_contents) {
56 315         441 my $skip;
57 315 100 100     916 if ($name =~ /\A\$/ && $opts->{skip_scalar}) {
58 16         52 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_scalar=1)";
59 16         39 $skip++; goto SKIPPING;
  16         38  
60             }
61 299 100 100     620 if ($name =~ /\A\@/ && $opts->{skip_array}) {
62 4         15 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_array=1)";
63 4         12 $skip++; goto SKIPPING;
  4         10  
64             }
65 295 100 100     562 if ($name =~ /\A\%/ && $opts->{skip_hash}) {
66 3         12 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_hash=1)";
67 3         8 $skip++; goto SKIPPING;
  3         10  
68             }
69 292 100 100     622 if ($name !~ /\A[\$\@\%]/ && $opts->{skip_sub}) {
70 3         14 log_trace "Not copying $name from $src_pkg to $target_pkg (skip_sub=1)";
71 3         8 $skip++; goto SKIPPING;
  3         9  
72             }
73 289 100 100     559 if ($opts->{exclude} && grep { $name eq $_ } @{ $opts->{exclude} }) {
  104         201  
  26         44  
74 4         15 log_trace "Not copying $name from $src_pkg to $target_pkg (listed in exclude)";
75 4         11 $skip++; goto SKIPPING;
  4         14  
76             }
77              
78 285 100       472 my $overwrite = exists $target_contents{$name} ? 1:0;
79              
80 285 100       487 if ($opts->{_before_copy}) {
81 26 100       50 $skip = 1 if $opts->{_before_copy}->($name, $src_pkg, $target_pkg, $opts, $overwrite);
82             }
83 285 100       612 if ($skip) {
84 7         23 log_trace "Not copying $name from $src_pkg to $target_pkg (_before_copy)";
85 7         26 next NAME;
86             }
87              
88             SKIPPING:
89             {
90 308 100       375 last unless $skip;
  308         849  
91 30 50       56 if ($opts->{_on_skip}) {
92 0         0 $opts->{_on_skip}->($name, $src_pkg, $target_pkg, $opts);
93             }
94 30         53 next NAME;
95             }
96              
97 278 100       413 if ($overwrite) {
98 82         228 log_trace "Overwriting $name from $src_pkg to $target_pkg";
99             } else {
100 196         532 log_trace "Copying $name from $src_pkg to $target_pkg ...";
101             }
102              
103 278 100       1157 if ($name =~ /\A\$(.+)/) {
    100          
    100          
104 1     1   913 no warnings 'once', 'redefine';
  1         2  
  1         98  
105 173         219 ${"$target_pkg\::$1"} = ${"$src_pkg\::$1"};
  173         573  
  173         469  
106             } elsif ($name =~ /\A\@(.+)/) {
107 1     1   7 no warnings 'once', 'redefine';
  1         2  
  1         117  
108 42 100       79 @{"$target_pkg\::$1"} = $opts->{dclone} ? @{ Storable::dclone(\@{"$src_pkg\::$1"}) } : @{"$src_pkg\::$1"};
  42         282  
  4         5  
  4         53  
  38         120  
109             } elsif ($name =~ /\A\%(.+)/) {
110 1     1   7 no warnings 'once', 'redefine';
  1         3  
  1         128  
111 31 100       52 %{"$target_pkg\::$1"} = $opts->{dclone} ? %{ Storable::dclone(\%{"$src_pkg\::$1"}) } : %{"$src_pkg\::$1"};
  31         114  
  3         6  
  3         110  
  28         111  
112             } else {
113 1     1   7 no warnings 'once', 'redefine';
  1         3  
  1         211  
114 32         43 *{"$target_pkg\::$name"} = \&{"$src_pkg\::$name"};
  32         95  
  32         84  
115             }
116 278 100       875 if ($opts->{_after_copy}) {
117 26         47 $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__