File Coverage

blib/lib/MooX/VariantAttribute/Role.pm
Criterion Covered Total %
statement 75 78 96.1
branch 44 48 91.6
condition 9 12 75.0
subroutine 11 11 100.0
pod n/a
total 139 149 93.2


line stmt bran cond sub pod time code
1             package MooX::VariantAttribute::Role;
2              
3 8     8   57128 use Moo::Role;
  8         12  
  8         42  
4 8     8   1984 use Carp qw/croak/;
  8         9  
  8         472  
5 8     8   33 use Scalar::Util qw/blessed refaddr reftype/;
  8         8  
  8         528  
6 8     8   3108 use Combine::Keys qw/combine_keys/;
  8         3279  
  8         1484  
7              
8             has variant_last_value => (
9             is => 'rw',
10             lazy => 1,
11             default => sub { {} },
12             );
13              
14             sub _given_when {
15 61     61   6889 my ($self) = shift;
16 61         86 my ( $set, $given, $when, $attr ) = @_;
17              
18 61 100       110 return if $self->_variant_last_value($attr, 'set', $set);
19              
20 34         92 my $find = $self->_find_from_given(@_);
21            
22 34         842 $self->variant_last_value->{$attr}->{find} = $find;
23            
24 34         170 my @when = @{ $when };
  34         99  
25 34         78 while (scalar @when >= 2) {
26 67         66 my $check = shift @when;
27 67         59 my $found = shift @when;
28 67 100       101 if ( _struct_the_same($check, $find) ) {
29 34 100       71 if ( $found->{alias} ) {
30 2 100       16 if (blessed $set) {
31 1         14 for my $alias ( keys %{ $found->{alias} } ) {
  1         4  
32 1 50       11 next if $set->can($alias);
33 1         2 my $actual = $found->{alias}->{$alias};
34             {
35 8     8   45 no strict 'refs';
  8         21  
  8         4351  
  1         1  
36 1     1   3 *{"${find}::${alias}"} = sub { goto &{"${find}::${actual}"} };
  1         5  
  1         4  
  1         5  
37             }
38             }
39             } else {
40 1         2 map { $set->{$_} = $set->{$found->{alias}->{$_}} } keys %{ $found->{alias} };
  1         5  
  1         5  
41             }
42             }
43              
44 34 100       70 if ( my $run = $found->{run} ) {
45             my @new = ref $run eq 'CODE'
46 32 100       119 ? $found->{run}->( $self, $find, $set, )
47             : $self->$run($find, $set);
48 32 50       169 $set = scalar @new > 1 ? \@new : shift @new;
49             }
50              
51 34         636 $self->variant_last_value->{$attr}->{set} = $set;
52 34         678 return $self->$attr($set);
53             }
54             }
55              
56 0         0 croak sprintf 'Could not find - %s - in when spec for attribute - %s',
57             $set, $attr;
58             }
59              
60             sub _variant_last_value {
61 66     66   6278 my ($self, $attr, $value, $set) = @_;
62              
63 66 100       1232 my $stored = $self->variant_last_value->{$attr}->{$value} or return undef;
64 51         334 return _ref_the_same($stored, $set);
65             }
66              
67             sub _ref_the_same {
68 62     62   6672 my ($stored, $passed) = @_;
69              
70 62 100 100     210 if ( ref $passed and ref $stored ) {
71 13 100       113 return refaddr($stored) == refaddr($passed) ? 1 : undef;
72             }
73            
74 49 100       872 return ($stored =~ m/^$passed$/) ? 1 : undef;
75             }
76              
77             sub _struct_the_same {
78 115     115   7549 my ($stored, $passed) = @_;
79            
80 115   66     442 my $stored_ref = reftype($stored) // reftype(\$stored);
81 115   66     336 my $passed_ref = reftype($passed) // reftype(\$passed);
82 115 100       242 $stored_ref eq $passed_ref or return undef;
83            
84 102 100       216 if ( $stored_ref eq 'SCALAR') {
    100          
    50          
85 71 100       832 return ($stored =~ m/^$passed$/) ? 1 : undef;
86             } elsif ($stored_ref eq 'HASH') {
87 24         65 for (combine_keys($stored, $passed)) {
88 26 100 66     418 $stored->{$_} and $passed->{$_} or return undef;
89 19 100       40 _struct_the_same($stored->{$_}, $passed->{$_}) or return undef;
90             }
91 16         43 return 1;
92             } elsif ($stored_ref eq 'ARRAY') {
93 7         8 my @count = (scalar @{$stored}, scalar @{$passed});
  7         11  
  7         12  
94 7 100       25 $count[0] == $count[1] or return undef;
95 5         17 for ( 0 .. $count[1] - 1 ) {
96 12 100       21 _struct_the_same($stored->[$_], $passed->[$_]) or return undef;
97             }
98 4         14 return 1;
99             }
100              
101 0         0 return 1;
102             }
103              
104             sub _find_from_given {
105 41     41   7946 my ( $self, $set, $given, $when ) = @_;
106              
107 41         71 my $ref_given = ref $given;
108 41 100       92 if ( $ref_given eq 'Type::Tiny' ) {
    50          
109 34         283 $set = $given->($set);
110 34 100       5179 return $given->display_name eq 'Object' ? ref $set : $set;
111             }
112             elsif ( $ref_given eq 'CODE' ) {
113 7         17 return $given->( $self, $set );
114             }
115              
116 0           return $set;
117             }
118              
119             1;
120              
121             __END__