File Coverage

blib/lib/Rope/Variant.pm
Criterion Covered Total %
statement 61 80 76.2
branch 20 46 43.4
condition 2 7 28.5
subroutine 10 10 100.0
pod n/a
total 93 143 65.0


line stmt bran cond sub pod time code
1             package Rope::Variant;
2              
3 2     2   1155 use strict;
  2         4  
  2         79  
4 2     2   10 use warnings;
  2         4  
  2         107  
5 2     2   1225 use Combine::Keys qw/combine_keys/;
  2         47071  
  2         19  
6 2     2   214 use Rope::Pro;
  2         5  
  2         915  
7             my (%PRO);
8              
9             BEGIN {
10             %PRO = Rope::Pro->new(
11             find_from_given => sub {
12 7         20 my ( $self, $set, $given) = @_;
13 7         16 my $ref_given = ref $given;
14 7 50       35 if ( $ref_given eq 'Type::Tiny' ) {
    0          
15 7         142 $set = $given->($set);
16 7 100       267 return $given->display_name eq 'Object' ? ref $set : $set;
17             }
18             elsif ( $ref_given eq 'CODE' ) {
19 0         0 return $given->( $self, $set );
20             }
21 0         0 return $set;
22             },
23             struct_the_same => sub {
24 16         34 my ($stored, $passed) = @_;
25 16   50     104 my $stored_ref = ref($stored) || 'STRING';
26 16   50     51 my $passed_ref = ref($passed) || 'STRING';
27 16 50       54 $stored_ref eq $passed_ref or return undef;
28 16 50       34 if ($stored_ref eq 'STRING') {
    0          
    0          
    0          
29 16 100       256 return ($stored =~ m/^$passed$/) ? 1 : undef;
30             } elsif ($stored_ref eq 'SCALAR') {
31 0 0       0 return ($$stored =~ m/^$$passed$/) ? 1 : undef;
32             } elsif ($stored_ref eq 'HASH') {
33 0         0 for (combine_keys($stored, $passed)) {
34 0 0 0     0 $stored->{$_} and $passed->{$_} or return undef;
35 0 0       0 $PRO{struct_the_same}($stored->{$_}, $passed->{$_}) or return undef;
36             }
37 0         0 return 1;
38             } elsif ($stored_ref eq 'ARRAY') {
39 0         0 my @count = (scalar @{$stored}, scalar @{$passed});
  0         0  
  0         0  
40 0 0       0 $count[0] == $count[1] or return undef;
41 0         0 for ( 0 .. $count[1] - 1 ) {
42 0 0       0 $PRO{struct_the_same}($stored->[$_], $passed->[$_]) or return undef;
43             }
44 0         0 return 1;
45             }
46 0         0 return 1;
47             }
48 2     2   28 );
49             }
50              
51             sub import {
52 2     2   22 my ($caller) = (scalar caller);
53             $PRO{keyword}($caller, 'variant', sub {
54 3     3   772342 my ($name, %definition) = @_;
55              
56 3         31 my ($meta, $variant, $exists) = (Rope->get_meta($caller), [], 0);
57 3 100       29 if ($meta->{properties}->{$name}) {
58 1 50       5 if ($meta->{properties}->{$name}->{variant}) {
59 1         2 push @{$meta->{properties}->{$name}->{variant}->{when}}, @{$definition{when}};
  1         4  
  1         3  
60 1         8 Rope->set_property($caller, $name, $meta->{properties}->{$name});
61 1         3 $exists = 1;
62             } else {
63 0         0 die "Cannot convert an existing property into a variant property";
64             }
65             }
66              
67             $caller->property($name,
68             initable => 1,
69             writeable => 1,
70             variant => \%definition,
71             trigger => sub {
72 7     7   25 my ($self, $set) = @_;
73 7         28 my $meta = Rope->get_meta($caller)->{properties}->{$name};
74 7         47 my $find = $PRO{find_from_given}(@_, $meta->{variant}->{given});
75 7         57 my @when = @{$meta->{variant}->{when}};
  7         30  
76 7         29 while (scalar @when >= 2) {
77 16         39 my ($check, $found) = (
78             shift @when,
79             shift @when
80             );
81 16 100       40 if ( $PRO{struct_the_same}($check, $find) ) {
82 7 100       26 if ($found->{alias}) {
    50          
83 3 50       9 if (ref $set ne 'HASH') {
84 3         6 for my $alias ( keys %{ $found->{alias} } ) {
  3         10  
85 4 50       34 next if $set->can($alias);
86 4         8 my $actual = $found->{alias}->{$alias};
87             {
88 2     2   16 no strict 'refs';
  2         5  
  2         722  
  4         6  
89 4     4   20 *{"${find}::${alias}"} = sub { goto &{"${find}::${actual}"} };
  4         26  
  4         6  
  4         33  
90             }
91             }
92 3         32 return $set;
93             } else {
94             return {
95 0         0 map { $set->{$_} = $set->{$found->{alias}->{$_}} } keys %{ $found->{alias} }
  0         0  
  0         0  
96             }
97             }
98             }
99             elsif ($found->{run}) {
100 4         18 my $run = $found->{run};
101 4 50       23 return ref $run
102             ? $run->($self, $set)
103             : $self->$run($set);
104             }
105             }
106             }
107             }
108 3 100       46 ) if !$exists;
109 2         17 });
110             }
111              
112             1;
113              
114             __END__