File Coverage

blib/lib/MooX/LazierAttributes.pm
Criterion Covered Total %
statement 121 127 95.2
branch 29 32 90.6
condition 16 23 69.5
subroutine 30 30 100.0
pod 0 1 0.0
total 196 213 92.0


line stmt bran cond sub pod time code
1             package MooX::LazierAttributes;
2              
3 10     9   403132 use strict;
  10         68  
  10         270  
4 10     9   1594 use warnings;
  9         18  
  9         268  
5 9     9   54 use Scalar::Util qw/reftype refaddr blessed/;
  9         20  
  9         557  
6 9     9   2475 use MooX::ReturnModifiers qw/return_modifiers/;
  9         5431  
  9         603  
7              
8             our $VERSION = '1.06';
9              
10 9     9   70 use constant ro => 'ro';
  9         19  
  9         754  
11 9     9   58 use constant is_ro => ( is => ro );
  9         18  
  9         492  
12 9     9   53 use constant rw => 'rw';
  9         16  
  9         405  
13 9     9   52 use constant is_rw => ( is => rw );
  9         17  
  9         432  
14 9     9   62 use constant nan => undef;
  9         16  
  9         408  
15 9     9   55 use constant lzy => ( lazy => 1 );
  9         19  
  9         443  
16 9     9   57 use constant bld => ( builder => 1 );
  9         22  
  9         490  
17 9     9   62 use constant lzy_bld => ( lazy_build => 1 );
  9         20  
  9         469  
18 9     9   69 use constant trg => ( trigger => 1 );
  9         64  
  9         456  
19 9     9   51 use constant clr => ( clearer => 1 );
  9         16  
  9         455  
20 9     9   56 use constant req => ( required => 1 );
  9         20  
  9         547  
21 9     9   63 use constant coe => ( coerce => 1 );
  9         22  
  9         630  
22 9     9   61 use constant lzy_hash => ( lazy => 1, default => sub { {} });
  9         17  
  9         625  
  1         12612  
23 9     9   55 use constant lzy_array => ( lazy => 1, default => sub { [] });
  9         18  
  9         621  
  0         0  
24 9     9   57 use constant lzy_str => (lazy => 1, default => sub { "" });
  9         22  
  9         605  
  0         0  
25 9     9   62 use constant dhash => (default => sub { {} });
  9         20  
  9         570  
  0         0  
26 9     9   62 use constant darray => (default => sub { [] });
  9         18  
  9         638  
  0         0  
27 9     9   92 use constant dstr => (default => sub { "" });
  9         40  
  9         667  
  0         0  
28              
29             our %opts;
30             BEGIN {
31 9     9   3375 %opts => (limit => 5, skip => '');
32             }
33              
34             sub import {
35 9     9   24553 my ($package, @export) = @_;
36 9         31 my $target = caller;
37 9         40 my %modifiers = return_modifiers($target);
38              
39             my $attributes = sub {
40 5     5   57215 my @attr = @_;
41 5         27 while (@attr) {
42 31 100       59658 my @names = ref $attr[0] eq 'ARRAY' ? @{ shift @attr } : shift @attr;
  3         11  
43 31         53 my @spec = @{ shift(@attr) };
  31         73  
44            
45 31         64 my $eye = scalar @spec - 1;
46 56         242 (grep { ref $spec[$_] eq 'Type::Tiny'} (0 .. $eye))
47             ? push @spec, delete $spec[$eye]->{default}
48 31 100 66     75 : ( ref $spec[$eye] eq 'HASH' && exists $spec[$eye]->{default} ) && splice @spec, ($eye == 0 ? 0 : 1), 0, delete $spec[$eye]->{default};
49            
50 31         68 for (@names) {
51 36 100 100     2234 unshift @spec, 'set' if $_ =~ m/^\+/ and ( !$spec[0] || $spec[0] ne 'set' );
      100        
52 36 100 100     221 unshift @spec, ro unless ref \$spec[0] eq 'SCALAR' and $spec[0] =~ m/^ro|rw|set$/;
53 36         100 $modifiers{has}->( $_, construct_attribute(@spec) );
54             }
55             }
56 9         474 };
57              
58 9 100       38 if (ref $export[0]) {
59 1         4 my $o = shift @export;
60 1   66     13 exists $o->{$_} and $opts{$_} = $o->{$_} for (qw/limit skip/);
61             }
62              
63             {
64 9     9   68 no strict 'refs';
  9         17  
  9         4577  
  9         20  
65 104         275 ${"${target}::"}{$_} = ${"${package}::"}{$_}
  104         231  
66 9 100       40 foreach (scalar @export ? @export : qw/ro is_ro rw is_rw nan lzy bld lzy_bld trg clr req coe lzy_hash lzy_array/);
67 9         22 *{"${target}::attributes"} = $attributes;
  9         52  
68             }
69              
70 9         2253 return 1;
71             }
72              
73             sub construct_attribute {
74 45     45 0 4299 my @spec = @_;
75 45         77 my %attr = ();
76 45 100       122 $attr{is} = $spec[0] unless $spec[0] eq 'set';
77              
78 45 100       110 if ( ref $spec[1] eq 'Type::Tiny' ) {
79 7         15 $attr{isa} = $spec[1];
80 7         15 $spec[1] = pop @spec;
81             }
82              
83 26     26   36785 $attr{default} = ref $spec[1] eq 'CODE' ? $spec[1] : sub { _clone( $spec[1] ) }
84 45 100       187 if defined $spec[1];
    100          
85              
86 45         78 $attr{$_} = $spec[2]->{$_} foreach keys %{ $spec[2] };
  45         152  
87              
88 45         233 return %attr;
89             }
90              
91             sub _clone {
92 50     50   19521 my ($to_clone, $recur) = @_;
93 50         99 my $blessed = blessed $to_clone;
94 50 50 0     110 $blessed =~ m/^$opts{skip}$/ and return $to_clone if $opts{skip};
95 50         98 my $clone = _deep_clone($to_clone, $recur);
96 50 100       458 return $blessed ? bless $clone, $blessed : $clone;
97             }
98              
99             sub _deep_clone {
100 53     53   2106 my ($to_clone, $recur) = @_;
101 53   66     209 my $rt = reftype($to_clone) || reftype(\$to_clone);
102 53 100       151 $rt eq 'SCALAR' and return $to_clone;
103 19         41 my $addr = refaddr $to_clone;
104 19 50 33     82 $recur->{$addr}++ && $recur->{$addr} > $opts{limit} and return $to_clone;
105 19 100       104 $rt eq 'HASH' and return { map +( $_ => _clone( $to_clone->{$_}, $recur ) ), keys %$to_clone };
106 4 50       25 $rt eq 'ARRAY' and return [ map _clone($_, $recur), @$to_clone ];
107 0           return $to_clone;
108             }
109              
110             1;
111              
112             __END__