File Coverage

blib/lib/Validation/Class/Directives.pm
Criterion Covered Total %
statement 81 85 95.2
branch 14 24 58.3
condition 3 5 60.0
subroutine 13 13 100.0
pod 2 3 66.6
total 113 130 86.9


line stmt bran cond sub pod time code
1             # ABSTRACT: Validation::Class Core Directives Registry
2              
3             package Validation::Class::Directives;
4              
5 109     109   703 use strict;
  109         232  
  109         2986  
6 109     109   612 use warnings;
  109         226  
  109         3218  
7              
8 109     109   585 use base 'Validation::Class::Mapping';
  109         217  
  109         50652  
9              
10 109     109   839 use Validation::Class::Util '!has';
  109         255  
  109         711  
11              
12 109     109   64672 use List::MoreUtils 'first_index';
  109         1521421  
  109         733  
13 109     109   128130 use Module::Find 'usesub';
  109         21288  
  109         6586  
14 109     109   733 use Carp 'confess';
  109         266  
  109         4510  
15              
16 109     109   660 use List::MoreUtils;
  109         239  
  109         540  
17              
18             our $_registry = {};
19              
20             foreach my $module (usesub 'Validation::Class::Directive') {
21             $_registry->{$module} = $module->new
22             if $module->isa('Validation::Class::Directive')
23             ;
24             }
25              
26             our $VERSION = '7.900059'; # VERSION
27              
28              
29             sub new {
30              
31 3177     3177 1 6942 my $class = shift;
32              
33 3177         9471 my $arguments = $class->build_args(@_);
34              
35 3177 100       6057 $arguments = $_registry unless keys %{$arguments};
  3177         10710  
36              
37 3177         7537 my $self = bless {}, $class;
38              
39 3177         9408 $self->add($arguments);
40              
41 3177         10531 return $self;
42              
43             }
44              
45             sub add {
46              
47 3177     3177 1 5080 my $self = shift;
48              
49 3177         7749 my $arguments = $self->build_args(@_);
50              
51 3177         6493 while (my ($key, $value) = each %{$arguments}) {
  69094         183928  
52              
53             # never overwrite
54 65917 50       130721 unless (defined $self->{$key}) {
55             # is it a direct directive?
56 65917 100       172565 if ("Validation::Class::Directive" eq ref $value) {
    50          
    0          
57 1         5 $self->{$key} = $value;
58             }
59             # is it a directive sub-class
60             elsif (isa_classref($value)) {
61 65916 50       196264 if ($value->isa("Validation::Class::Directive")) {
62 65916         149227 $self->{$value->name} = $value;
63             }
64             }
65             # is it a hashref
66             elsif (isa_hashref($value)) {
67 0         0 $self->{$key} = Validation::Class::Directive->new($value);
68             }
69             }
70              
71             }
72              
73 3177         12117 return $self;
74              
75             }
76              
77             sub resolve_dependencies {
78              
79 2639     2639 0 5516 my ($self, $type) = @_;
80              
81 2639   50     5855 $type ||= 'validation';
82              
83 2639         4735 my $dependencies = {};
84              
85 2639         7329 foreach my $key ($self->keys) {
86              
87 41169         86483 my $class = $self->get($key);
88 41169         88370 my $name = $class->name;
89 41169         100068 my $dependents = $class->dependencies->{$type};
90              
91             # avoid invalid dependencies by excluding the unknown
92 41169         58901 $dependencies->{$name} = [grep { $self->has($_) } @{$dependents}];
  110444         215694  
  41169         90800  
93              
94             }
95              
96 2639         8845 my @ordered;
97             my %found;
98 2639         0 my %track;
99              
100 2639         11898 my @pending = keys %$dependencies;
101 2639         5891 my $limit = scalar(keys %$dependencies);
102 2639         7566 $limit += scalar(@{$_}) for values %$dependencies;
  41169         61841  
103              
104 2639         6395 while (@pending) {
105              
106 53034         78843 my $k = shift @pending;
107              
108 53034 50       71775 if (grep { $_ eq $k } @{$dependencies->{$k}}) {
  161978 100       269126  
  53034         93853  
109              
110 0         0 confess sprintf 'Direct circular dependency on event %s: %s -> %s',
111             $type, $k, $k;
112              
113             }
114              
115 161978         287036 elsif (grep { ! exists $found{$_} } @{$dependencies->{$k}}) {
  53034         90322  
116              
117             confess sprintf 'Invalid dependency on event %s: %s -> %s',
118 0         0 $type, $k, join(',', @{$dependencies->{$k}})
119 11865 50       16974 if grep { ! exists $dependencies->{$_} } @{$dependencies->{$k}};
  104623         187468  
  11865         19906  
120              
121             confess
122             sprintf 'Indirect circular dependency on event %s: %s -> %s ',
123 0         0 $type, $k, join(',', @{$dependencies->{$k}})
124 11865 50 66     31991 if $track{$k} && $track{$k} > $limit; # allowed circular iterations
125              
126 11865 50       35836 $track{$k}++ if push @pending, $k;
127              
128             }
129              
130             else {
131              
132 41169         62918 $found{$k} = 1;
133 41169         87860 push @ordered, $k;
134              
135             }
136              
137             }
138              
139 2639         10598 my @list = reverse @ordered;
140              
141 2639         11637 foreach my $x (keys %$dependencies) {
142              
143 41169         54630 foreach my $y (@{$dependencies->{$x}}) {
  41169         73108  
144              
145 57355     121179   166529 my $a = first_index { $_ eq $x } @list;
  121179         177471  
146 57355     1086640   175376 my $b = first_index { $_ eq $y } @list;
  1086640         1393297  
147              
148 57355 50       146127 confess sprintf
149             'Broken dependency chain; Faulty ordering on '.
150             'event %s: %s before %s', $type, $x, $y
151             if $a > $b
152             ;
153              
154             }
155              
156             }
157              
158 2639         28832 return (@ordered);
159              
160             }
161              
162             1;
163              
164             __END__