File Coverage

blib/lib/Boundary.pm
Criterion Covered Total %
statement 56 56 100.0
branch 16 16 100.0
condition 2 2 100.0
subroutine 12 12 100.0
pod 0 5 0.0
total 86 91 94.5


line stmt bran cond sub pod time code
1             package Boundary;
2 7     7   360789 use strict;
  7         66  
  7         220  
3 7     7   36 use warnings;
  7         15  
  7         184  
4              
5 7     7   3387 use namespace::allclean ();
  7         122706  
  7         218  
6 7     7   3437 use Class::Load qw(try_load_class);
  7         93311  
  7         734  
7              
8             our $VERSION = "0.01";
9              
10             our %INFO;
11              
12             sub import {
13 6     6   2458 my $class = shift;
14 6         16 my $target = scalar caller;
15              
16 6         24 my $requires = $class->gen_requires($target);
17             {
18 7     7   59 no strict 'refs';
  7         19  
  7         4332  
  6         12  
19 6         14 *{"${target}::requires"} = $requires;
  6         45  
20             }
21              
22             namespace::allclean->import(
23 6         81 -cleanee => $target,
24             );
25            
26 6         391 return;
27             }
28              
29              
30             our $CROAK_MESSAGE_SUFFIX;
31             sub croak {
32 6     6 0 4549 require Carp;
33 6 100       25 push @_ => $CROAK_MESSAGE_SUFFIX if $CROAK_MESSAGE_SUFFIX;
34 6         874 goto &Carp::croak;
35             }
36              
37             sub gen_requires {
38 7     7 0 108 my ($class, $target) = @_;
39             sub {
40 7     7   2740 my @methods = @_;
41 7   100     16 push @{$INFO{$target}{requires}||=[]} => @methods;
  7         61  
42 7         17 return;
43             }
44 7         45 }
45              
46             sub assert_requires {
47 7     7 0 9222 my ($class, $impl, $interface) = @_;
48 7 100       28 croak "Not found interface info. $interface" if !$INFO{$interface};
49              
50 6         12 my @requires = @{$INFO{$interface}{requires}};
  6         19  
51 6 100       20 return if !@requires;
52              
53 5 100       12 if (my @requires_fail = grep { !$impl->can($_) } @requires) {
  5         69  
54 1         9 croak "Can't apply ${interface} to ${impl} - missing ". join(', ', @requires_fail);
55             }
56 4         15 return;
57             }
58              
59             sub apply_interfaces_to_package {
60 6     6 0 6793 my ($class, $impl, @interfaces) = @_;
61 6 100       25 croak "No interfaces supplied!" unless @interfaces;
62              
63 5         14 for my $interface (@interfaces) {
64 6         30 my ($ok, $e) = try_load_class($interface);
65 6 100       855 croak("cannot load interface package: $e") if !$ok;
66              
67 5         21 $class->assert_requires($impl, $interface);
68             }
69 4         22 $INFO{$impl}{interface_map}{$_} = 1 for @interfaces;
70 4         11 return;
71             }
72              
73             sub check_implementations {
74 8     8 0 109 my ($class, $impl, @interfaces) = @_;
75 8 100       33 return if !$INFO{$impl};
76 4         8 my %interface_map = %{$INFO{$impl}{interface_map}};
  4         17  
77 4         9 for (@interfaces) {
78 4 100       17 return if !$interface_map{$_}
79             }
80 2         8 return !!1;
81             }
82              
83             1;
84             __END__