File Coverage

blib/lib/OOP/Perlish/Class/Abstract.pm
Criterion Covered Total %
statement 85 87 97.7
branch 15 16 93.7
condition 3 9 33.3
subroutine 21 23 91.3
pod n/a
total 124 135 91.8


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             # $Id$
3             # $Author$
4             # $HeadURL$
5             # $Date$
6             # $Revision$
7 6     6   32 use warnings;
  6         11  
  6         196  
8 6     6   30 use strict;
  6         27  
  6         329  
9             {
10              
11             package OOP::Perlish::Class::Abstract;
12 6     6   30 use warnings;
  6         10  
  6         147  
13 6     6   28 use strict;
  6         11  
  6         170  
14 6     6   1743 use OOP::Perlish::Class;
  6         12  
  6         151  
15 6     6   37 use base qw(OOP::Perlish::Class);
  6         24  
  6         2117  
16 6     6   36 use Carp qw(confess);
  6         11  
  6         344  
17 6     6   31 use Data::Dumper;
  6         10  
  6         1184  
18              
19             our $VERSION = 1.0;
20              
21             ############################################################################################
22             ## Do a sanity check for required interfaces in pre-validation
23             ############################################################################################
24             sub ____pre_validate_opts
25             {
26 14     14   27 my ($self) = @_;
27 14         29 my $class = ref($self);
28              
29 14         20 my %required_interfaces;
30              
31 14         50 for my $parent_class ( $self->_all_isa() ) {
32 32 100       527 if( bless( {}, $parent_class )->can('____OOP_PERLISH_CLASS_REQUIRED_INTERFACES') ) {
33 18         34 @required_interfaces{ @{ $parent_class->____OOP_PERLISH_CLASS_REQUIRED_INTERFACES() } } = undef;
  18         58  
34             }
35             }
36              
37 14         41 my %defined_interfaces;
38              
39 14         52 for my $parent_class ( $self->_all_isa() ) {
40 32 100       323 next if( exists( $self->____OOP_PERLISH_CLASS_ABSTRACT_CLASSES()->{$parent_class} ) );
41 30         97 for my $name ( keys %required_interfaces ) {
42 6     6   43 no strict 'refs';
  6         10  
  6         422  
43 6 100       7 $defined_interfaces{$name} = undef if( defined( *{ '::' . $class . '::' . $name }{CODE} ) );
  6         48  
44 6     6   38 use strict;
  6         21  
  6         1274  
45             }
46             }
47              
48 14 100       73 if( scalar keys %required_interfaces != scalar keys %defined_interfaces ) {
49 1         218 confess( 'Failed to define required interfaces: '
50 1         4 . join( ', ', grep { !exists( $defined_interfaces{$_} ) } keys %required_interfaces ) . 'in '
51             . $class );
52             }
53              
54 13         73 return $self->SUPER::____pre_validate_opts();
55             }
56              
57             ############################################################################################
58             ## set interfaces, usually called like 'BEGIN { __PACKAGE__->_interfaces(...) }' as the
59             ## first section of a derived class.
60             ############################################################################################
61             sub _interfaces(@)
62             {
63 1     1   5 my ( $self, %interfaces ) = @_;
64 1   33     16 my $class = ref($self) || $self;
65              
66 1         7 $self->____OOP_PERLISH_CLASS_ABSTRACT_CLASSES()->{$class} = 1;
67              
68 1         3 for my $name ( keys %interfaces ) {
69 3         5 my $type = $interfaces{$name};
70              
71             ### Symbol table manipulation; creates a method named for the $name in the package's namespace
72             ### The actual method is created via closure in ____oop_perlish_class_interface_factory();
73 6     6   38 no strict 'refs';
  6         35  
  6         357  
74 3         11 *{ '::' . $class . '::' . $name } = $self->____oop_perlish_class_interface_factory( $name, $type );
  3         28  
75 6     6   29 use strict;
  6         10  
  6         2800  
76             }
77              
78 1         43 return;
79             }
80              
81             ############################################################################################
82             ## return a static reference to an array of required fields for this class; must work for
83             ## all derived classes
84             ############################################################################################
85             sub ____OOP_PERLISH_CLASS_REQUIRED_INTERFACES(@)
86             {
87 19     19   36 my ($self) = @_;
88 19   33     167 my $class = ref($self) || $self;
89 19         25 our $____OOP_PERLISH_CLASS_REQUIRED_INTERFACES;
90              
91 19 100       53 $____OOP_PERLISH_CLASS_REQUIRED_INTERFACES = {} unless( defined($____OOP_PERLISH_CLASS_REQUIRED_INTERFACES) );
92 19 100       62 $____OOP_PERLISH_CLASS_REQUIRED_INTERFACES->{$class} = [] unless( exists( $____OOP_PERLISH_CLASS_REQUIRED_INTERFACES->{$class} ) );
93              
94 19         120 return $____OOP_PERLISH_CLASS_REQUIRED_INTERFACES->{$class};
95             }
96              
97             ############################################################################################
98             ## Place to store a registry of all abstract classes;
99             ############################################################################################
100             sub ____OOP_PERLISH_CLASS_ABSTRACT_CLASSES(@)
101             {
102 33     33   46 my ($self) = @_;
103 33         43 our $____OOP_PERLISH_CLASS_ABSTRACT_CLASSES;
104              
105 33 100       71 $____OOP_PERLISH_CLASS_ABSTRACT_CLASSES = {} unless( defined($____OOP_PERLISH_CLASS_ABSTRACT_CLASSES) );
106              
107 33         104 return $____OOP_PERLISH_CLASS_ABSTRACT_CLASSES;
108             }
109              
110             ############################################################################################
111             ## Return a subroutine for the required interfaces
112             ############################################################################################
113             sub ____oop_perlish_class_interface_impl_required
114             {
115 1     1   2 my ( $self, $name ) = @_;
116 1   33     7 my $class = ref($self) || $self;
117              
118 1         2 push( @{ $class->____OOP_PERLISH_CLASS_REQUIRED_INTERFACES() }, $name );
  1         6  
119              
120 1     1   5 return sub { confess("Interface $name is required, but was not defined"); };
  1         264  
121             }
122              
123             ############################################################################################
124             ## Return a subroutine for the optional (false) interfaces
125             ############################################################################################
126             sub ____oop_perlish_class_interface_impl_optional
127             {
128 1     1   3 my ( $self, $name ) = @_;
129 1     0   3 return sub { return; };
  0         0  
130             }
131              
132             ############################################################################################
133             ## Return a subroutine for optional_true interfaces
134             ############################################################################################
135             sub ____oop_perlish_class_interface_impl_optional_true
136             {
137 1     1   2 my ( $self, $name ) = @_;
138 1     0   4 return sub { return 1; };
  0         0  
139             }
140              
141             ############################################################################################
142             ## Return a subroutine for the given type
143             ############################################################################################
144             sub ____oop_perlish_class_interface_factory
145             {
146 3     3   4 my ( $self, $name, $type ) = @_;
147              
148 3         7 my $method = '____oop_perlish_class_interface_impl_' . lc($type);
149 3 50       36 confess('Invalid type of interface specification') unless( $self->can($method) );
150 3         10 return $self->$method($name);
151             }
152             }
153             1;
154             __END__