File Coverage

blib/lib/Test/NoOverride.pm
Criterion Covered Total %
statement 76 78 97.4
branch 13 16 81.2
condition 2 3 66.6
subroutine 12 12 100.0
pod n/a
total 103 109 94.5


line stmt bran cond sub pod time code
1             package Test::NoOverride;
2 2     2   32349 use strict;
  2         4  
  2         78  
3 2     2   11 use warnings;
  2         2  
  2         56  
4 2     2   1020 use Module::Functions;
  2         5819  
  2         127  
5 2     2   12 use Test::More;
  2         3  
  2         14  
6              
7             our $VERSION = '0.04';
8              
9             sub import {
10 2     2   17 my $class = shift;
11              
12 2         4 my $caller = caller;
13 2     2   535 no strict 'refs'; ## no critic
  2         7  
  2         882  
14 2         5 for my $func (qw/ no_override /) {
15 2         2 *{"${caller}::$func"} = \&{ __PACKAGE__. "::_$func" };
  2         1385  
  2         15  
16             }
17             }
18              
19             sub _no_override {
20 4     4   1375 my ($klass, %opt) = @_;
21              
22 4         6 my %exclude;
23 4 100       14 if (exists $opt{exclude}) {
24 1         1 $exclude{$_} = 1 for @{$opt{exclude}};
  1         5  
25             }
26 4         4 my %exclude_overridden;
27 4 100       12 if (exists $opt{exclude_overridden}) {
28 1         2 $exclude_overridden{$_} = 1 for @{$opt{exclude_overridden}};
  1         7  
29             }
30 4 50       14 unless ($opt{new}) {
31 4         7 $exclude{new} = 1; # default ignore 'new' method
32             }
33              
34 4         7 _load_class($klass);
35 4         11 my @functions = _get_functions($klass);
36              
37 4         3 my @methods;
38 4         11 _isa_list(\@methods, $klass);
39              
40 4         5 my $fail = 0;
41 4         5 for my $func (@functions) {
42 5         3 for my $m (@methods) {
43 35         18 my ($class, $method) = %{$m};
  35         41  
44 35 100       60 if ($func eq $method) {
45 5 50 66     15 if (!$exclude{$func} && !$exclude_overridden{"$class\::$method"} ) {
46 0         0 fail("[$klass\::$func] overrides [$class\::$method]");
47 0         0 $fail++;
48             }
49             }
50             }
51             }
52              
53 4 50       17 ok(1, "No Override: $klass") unless $fail;
54             }
55              
56             sub _load_class {
57 4     4   6 my $class = shift;
58              
59 4         7 my $class_path = $class;
60 4         15 $class_path =~ s!::!/!g;
61 4         1690 require "$class_path\.pm"; ## no critic
62 4         2021 $class->import;
63             }
64              
65             sub _isa_list {
66 12     12   16 my ($methods, @klass_list) = @_;
67              
68 12         10 my @parents;
69 12         14 for my $klass (@klass_list) {
70             {
71 2     2   13 no strict 'refs'; ## no critic
  2         3  
  2         345  
  16         12  
72 16         13 push @parents, @{"$klass\::ISA"};
  16         53  
73             }
74 16         18 for my $parent_klass (@parents) {
75 12         16 my @functions = _get_functions($parent_klass);
76 12         14 for my $func (@functions) {
77 28         20 push @{$methods}, { $parent_klass => $func };
  28         60  
78             }
79             }
80             }
81              
82 12 100       27 if ( scalar @parents ) {
83 8         445 _isa_list($methods, @parents);
84             }
85              
86             }
87              
88             sub _get_functions {
89 16     16   18 my $package = shift;
90              
91 16         29 my @functions = get_public_functions($package);
92              
93             {
94 2     2   13 no strict 'refs'; ## no critic
  2         2  
  2         222  
  16         851  
95 16         13 my %class = %{"${package}::"};
  16         85  
96 16         41 while (my ($k, $v) = each %class) {
97 83 100       339 push @functions, $k if $k =~ /^_.+/;
98             }
99             }
100              
101 16         32 return @functions;
102             }
103              
104             1;
105              
106             __END__