File Coverage

blib/lib/Class/Accessor/Validated.pm
Criterion Covered Total %
statement 64 68 94.1
branch 17 18 94.4
condition 5 9 55.5
subroutine 10 11 90.9
pod 2 2 100.0
total 98 108 90.7


line stmt bran cond sub pod time code
1             package Class::Accessor::Validated;
2              
3 1     1   88744 use strict;
  1         2  
  1         29  
4 1     1   4 use warnings;
  1         5  
  1         35  
5              
6 1     1   424 use Class::Accessor::Fast;
  1         2624  
  1         7  
7 1     1   27 use Class::Accessor;
  1         4  
  1         2  
8              
9 1     1   20 use Exporter qw(import);
  1         2  
  1         46  
10              
11             our @EXPORT_OK = qw(setup_accessors);
12             our $VERSION = '0.04';
13              
14             our $FOLLOW_BAD_PRACTICE = 0;
15              
16 1     1   4 use parent qw(Exporter Class::Accessor::Fast);
  1         1  
  1         4  
17              
18             ########################################################################
19             sub new {
20             ########################################################################
21 6     6 1 160246 my ( $class, @args ) = @_;
22              
23 6 50       16 my $arg_ref = ref $args[0] ? $args[0] : {@args};
24              
25 6         7 my @bad_keys;
26              
27 6         7 for my $maybe_valid_key ( keys %{$arg_ref} ) {
  6         17  
28 10   66     93 my $follows_best_practice = $class->can("set_$maybe_valid_key") && $class->can("get_$maybe_valid_key");
29              
30 10   33     20 my $follows_bad_practice = $FOLLOW_BAD_PRACTICE && $class->can($maybe_valid_key);
31              
32 10 100 66     26 next if $follows_best_practice || $follows_bad_practice;
33              
34 1         3 push @bad_keys, $maybe_valid_key;
35             }
36              
37 1     1   140 no strict 'refs';
  1         3  
  1         259  
38              
39 6         8 my %required_keys;
40              
41 6         13 for my $ancestor_class ( reverse _linear_isa($class) ) {
42 32         34 my $symbol = $ancestor_class . '::ATTRIBUTES';
43 32         28 my $attr_ref = *{$symbol}{HASH};
  32         56  
44 32 100       58 next if !$attr_ref;
45              
46 8         10 %required_keys = ( %required_keys, %{$attr_ref} );
  8         25  
47             }
48              
49 6         9 my @missing_required_keys;
50              
51 6         11 for my $maybe_required_key ( keys %required_keys ) {
52 14 100       26 next if !$required_keys{$maybe_required_key};
53 8 100       22 next if exists $arg_ref->{$maybe_required_key};
54 2         3 push @missing_required_keys, $maybe_required_key;
55             }
56              
57 6         8 my @errors;
58              
59 6 100       28 if (@bad_keys) {
60 1         3 push @errors, 'invalid argument(s): ' . join ', ', @bad_keys;
61             }
62              
63 6 100       10 if (@missing_required_keys) {
64 2         7 push @errors, 'required argument(s): ' . join ', ', @missing_required_keys;
65             }
66              
67 6 100       10 if (@errors) {
68 3         42 die join '; ', @errors;
69             }
70              
71 3         14 return $class->SUPER::new($arg_ref);
72             }
73              
74             ########################################################################
75             sub setup_accessors {
76             ########################################################################
77 0     0 1 0 my ( $class, @keys ) = @_;
78 0         0 Class::Accessor->follow_best_practice($class);
79 0         0 Class::Accessor::Fast->mk_accessors( $class, @keys );
80              
81 0         0 return 1;
82             }
83              
84             ########################################################################
85             sub _linear_isa {
86             ########################################################################
87 6     6   10 my ($start_class) = @_;
88              
89 1     1   8 no strict 'refs'; ## no critic
  1         2  
  1         102  
90              
91 6         7 my @isa_list;
92             my %seen;
93 6         13 my @queue = ($start_class);
94              
95 6         28 while ( my $current = shift @queue ) {
96 40 100       87 next if $seen{$current};
97 32         40 $seen{$current} = 1;
98 32         41 push @isa_list, $current;
99 32         26 unshift @queue, @{ $current . '::ISA' };
  32         120  
100             }
101              
102 6         22 return @isa_list;
103             }
104              
105             1;
106              
107             __END__