File Coverage

blib/lib/MooX/VariantAttribute/Role.pm
Criterion Covered Total %
statement 76 78 97.4
branch 45 48 93.7
condition 10 12 83.3
subroutine 11 11 100.0
pod n/a
total 142 149 95.3


line stmt bran cond sub pod time code
1             package MooX::VariantAttribute::Role;
2              
3 9     9   72832 use Moo::Role;
  9         18  
  9         46  
4 9     9   2816 use Carp qw/croak/;
  9         22  
  9         426  
5 9     9   49 use Scalar::Util qw/blessed refaddr reftype/;
  9         15  
  9         478  
6 9     9   3474 use Combine::Keys qw/combine_keys/;
  9         12038  
  9         58  
7              
8             has variant_last_value => (
9             is => 'rw',
10             lazy => 1,
11             default => sub { {} },
12             );
13              
14             sub _given_when {
15 82     82   8307 my ($self) = shift;
16 82         155 my ( $set, $given, $when, $attr, $run ) = @_;
17              
18 82 100       148 return if $self->_variant_last_value($attr, 'set', $set);
19              
20 45         131 my $find = $self->_find_from_given(@_);
21              
22 45         948 $self->variant_last_value->{$attr}->{find} = $find;
23 45         243 my @when = @{ $when };
  45         109  
24 45         100 while (scalar @when >= 2) {
25 89         126 my $check = shift @when;
26 89         111 my $found = shift @when;
27 89 100       145 if ( _struct_the_same($check, $find) ) {
28 44 100       97 if ( $found->{alias} ) {
29 6 100       19 if (blessed $set) {
30 5         6 for my $alias ( keys %{ $found->{alias} } ) {
  5         19  
31 6 100       36 next if $set->can($alias);
32 5         10 my $actual = $found->{alias}->{$alias};
33             {
34 9     9   1608 no strict 'refs';
  9         17  
  9         5265  
  5         8  
35 5     5   15 *{"${find}::${alias}"} = sub { goto &{"${find}::${actual}"} };
  5         24  
  5         2496  
  5         28  
36             }
37             }
38             } else {
39 1         1 map { $set->{$_} = $set->{$found->{alias}->{$_}} } keys %{ $found->{alias} };
  1         3  
  1         3  
40             }
41             }
42              
43 44 100       169 if ( $run = $found->{run} ) {
44             my @new = ref $run eq 'CODE'
45 38 100       145 ? $found->{run}->( $self, $find, $set, )
46             : $self->$run($find, $set);
47 38 50       215 $set = scalar @new > 1 ? \@new : shift @new;
48             }
49              
50 44         698 $self->variant_last_value->{$attr}->{set} = $set;
51 44         738 return $self->$attr($set);
52             }
53             }
54              
55 1         173 croak sprintf 'Could not find - %s - in when spec for attribute - %s',
56             $set, $attr;
57             }
58              
59             sub _variant_last_value {
60 87     87   6955 my ($self, $attr, $value, $set) = @_;
61              
62 87 100       1258 my $stored = $self->variant_last_value->{$attr}->{$value} or return undef;
63 65         446 return _ref_the_same($stored, $set);
64             }
65              
66             sub _ref_the_same {
67 76     76   8190 my ($stored, $passed) = @_;
68              
69 76 100 100     216 if ( ref $passed and ref $stored ) {
70 17 100       183 return refaddr($stored) == refaddr($passed) ? 1 : undef;
71             }
72            
73 59 100       853 return ($stored =~ m/^$passed$/) ? 1 : undef;
74             }
75              
76             sub _struct_the_same {
77 137     137   13115 my ($stored, $passed) = @_;
78            
79 137   66     534 my $stored_ref = reftype($stored) // reftype(\$stored);
80 137   66     441 my $passed_ref = reftype($passed) // reftype(\$passed);
81 137 100       305 $stored_ref eq $passed_ref or return undef;
82            
83 124 100       266 if ( $stored_ref eq 'SCALAR') {
    100          
    50          
84 93 100       1021 return ($stored =~ m/^$passed$/) ? 1 : undef;
85             } elsif ($stored_ref eq 'HASH') {
86 24         76 for (combine_keys($stored, $passed)) {
87 26 100 100     402 $stored->{$_} and $passed->{$_} or return undef;
88 19 100       53 _struct_the_same($stored->{$_}, $passed->{$_}) or return undef;
89             }
90 16         62 return 1;
91             } elsif ($stored_ref eq 'ARRAY') {
92 7         13 my @count = (scalar @{$stored}, scalar @{$passed});
  7         20  
  7         25  
93 7 100       29 $count[0] == $count[1] or return undef;
94 5         19 for ( 0 .. $count[1] - 1 ) {
95 12 100       34 _struct_the_same($stored->[$_], $passed->[$_]) or return undef;
96             }
97 4         15 return 1;
98             }
99              
100 0         0 return 1;
101             }
102              
103             sub _find_from_given {
104 52     52   7765 my ( $self, $set, $given, $when ) = @_;
105              
106 52         96 my $ref_given = ref $given;
107 52 100       113 if ( $ref_given eq 'Type::Tiny' ) {
    50          
108 42         302 $set = $given->($set);
109 42 100       7337 return $given->display_name eq 'Object' ? ref $set : $set;
110             }
111             elsif ( $ref_given eq 'CODE' ) {
112 10         27 return $given->( $self, $set );
113             }
114              
115 0           return $set;
116             }
117              
118             1;
119              
120             __END__