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   610 use strict;
  109         178  
  109         2479  
6 109     109   469 use warnings;
  109         176  
  109         2367  
7              
8 109     109   462 use base 'Validation::Class::Mapping';
  109         177  
  109         39981  
9              
10 109     109   805 use Validation::Class::Util '!has';
  109         198  
  109         649  
11              
12 109     109   55362 use List::MoreUtils 'first_index';
  109         1245370  
  109         631  
13 109     109   103557 use Module::Find 'usesub';
  109         16752  
  109         5578  
14 109     109   580 use Carp 'confess';
  109         217  
  109         3938  
15              
16 109     109   542 use List::MoreUtils;
  109         197  
  109         496  
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.900058'; # VERSION
27              
28              
29             sub new {
30              
31 3177     3177 1 6274 my $class = shift;
32              
33 3177         9073 my $arguments = $class->build_args(@_);
34              
35 3177 100       5354 $arguments = $_registry unless keys %{$arguments};
  3177         9021  
36              
37 3177         6644 my $self = bless {}, $class;
38              
39 3177         8801 $self->add($arguments);
40              
41 3177         9272 return $self;
42              
43             }
44              
45             sub add {
46              
47 3177     3177 1 5077 my $self = shift;
48              
49 3177         7040 my $arguments = $self->build_args(@_);
50              
51 3177         5774 while (my ($key, $value) = each %{$arguments}) {
  69094         149857  
52              
53             # never overwrite
54 65917 50       105960 unless (defined $self->{$key}) {
55             # is it a direct directive?
56 65917 100       147370 if ("Validation::Class::Directive" eq ref $value) {
    50          
    0          
57 1         4 $self->{$key} = $value;
58             }
59             # is it a directive sub-class
60             elsif (isa_classref($value)) {
61 65916 50       172953 if ($value->isa("Validation::Class::Directive")) {
62 65916         126569 $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         10676 return $self;
74              
75             }
76              
77             sub resolve_dependencies {
78              
79 2639     2639 0 5202 my ($self, $type) = @_;
80              
81 2639   50     5599 $type ||= 'validation';
82              
83 2639         4174 my $dependencies = {};
84              
85 2639         7028 foreach my $key ($self->keys) {
86              
87 41169         70860 my $class = $self->get($key);
88 41169         73636 my $name = $class->name;
89 41169         87228 my $dependents = $class->dependencies->{$type};
90              
91             # avoid invalid dependencies by excluding the unknown
92 41169         48976 $dependencies->{$name} = [grep { $self->has($_) } @{$dependents}];
  110444         177110  
  41169         75916  
93              
94             }
95              
96 2639         8003 my @ordered;
97             my %found;
98 2639         0 my %track;
99              
100 2639         10767 my @pending = keys %$dependencies;
101 2639         5140 my $limit = scalar(keys %$dependencies);
102 2639         6470 $limit += scalar(@{$_}) for values %$dependencies;
  41169         50881  
103              
104 2639         6096 while (@pending) {
105              
106 53259         65178 my $k = shift @pending;
107              
108 53259 50       59446 if (grep { $_ eq $k } @{$dependencies->{$k}}) {
  162082 100       221040  
  53259         78999  
109              
110 0         0 confess sprintf 'Direct circular dependency on event %s: %s -> %s',
111             $type, $k, $k;
112              
113             }
114              
115 162082         234563 elsif (grep { ! exists $found{$_} } @{$dependencies->{$k}}) {
  53259         75083  
116              
117             confess sprintf 'Invalid dependency on event %s: %s -> %s',
118 0         0 $type, $k, join(',', @{$dependencies->{$k}})
119 12090 50       14203 if grep { ! exists $dependencies->{$_} } @{$dependencies->{$k}};
  104727         153882  
  12090         16788  
120              
121             confess
122             sprintf 'Indirect circular dependency on event %s: %s -> %s ',
123 0         0 $type, $k, join(',', @{$dependencies->{$k}})
124 12090 50 66     27826 if $track{$k} && $track{$k} > $limit; # allowed circular iterations
125              
126 12090 50       31562 $track{$k}++ if push @pending, $k;
127              
128             }
129              
130             else {
131              
132 41169         52615 $found{$k} = 1;
133 41169         71758 push @ordered, $k;
134              
135             }
136              
137             }
138              
139 2639         9738 my @list = reverse @ordered;
140              
141 2639         10371 foreach my $x (keys %$dependencies) {
142              
143 41169         44984 foreach my $y (@{$dependencies->{$x}}) {
  41169         60896  
144              
145 57355     120689   138287 my $a = first_index { $_ eq $x } @list;
  120689         146116  
146 57355     1083950   142768 my $b = first_index { $_ eq $y } @list;
  1083950         1136965  
147              
148 57355 50       121121 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         26269 return (@ordered);
159              
160             }
161              
162             1;
163              
164             __END__