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 11     10   524867 use strict;
  11         57  
  11         247  
4 11     10   1542 use warnings;
  10         23  
  10         269  
5 10     10   55 use Scalar::Util qw/reftype refaddr blessed/;
  10         17  
  10         484  
6 10     10   3713 use MooX::ReturnModifiers qw/return_has/;
  10         5257  
  10         544  
7              
8             our $VERSION = '1.07';
9              
10 10     10   61 use constant ro => 'ro';
  10         20  
  10         18093  
11 10     10   64 use constant is_ro => ( is => ro );
  10         17  
  10         464  
12 10     10   47 use constant rw => 'rw';
  10         15  
  10         362  
13 10     10   43 use constant is_rw => ( is => rw );
  10         17  
  10         391  
14 10     10   48 use constant nan => undef;
  10         16  
  10         430  
15 10     10   53 use constant lzy => ( lazy => 1 );
  10         16  
  10         458  
16 10     10   55 use constant bld => ( builder => 1 );
  10         40  
  10         484  
17 10     10   51 use constant lzy_bld => ( lazy_build => 1 );
  10         16  
  10         424  
18 10     10   64 use constant trg => ( trigger => 1 );
  10         46  
  10         455  
19 10     10   49 use constant clr => ( clearer => 1 );
  10         16  
  10         450  
20 10     10   75 use constant req => ( required => 1 );
  10         21  
  10         589  
21 10     10   51 use constant coe => ( coerce => 1 );
  10         16  
  10         609  
22 10     10   51 use constant lzy_hash => ( lazy => 1, default => sub { {} });
  10         17  
  10         655  
  1         12383  
23 10     10   52 use constant lzy_array => ( lazy => 1, default => sub { [] });
  10         22  
  10         682  
  0         0  
24 10     10   61 use constant lzy_str => (lazy => 1, default => sub { "" });
  10         16  
  10         588  
  0         0  
25 10     10   51 use constant dhash => (default => sub { {} });
  10         15  
  10         574  
  0         0  
26 10     10   52 use constant darray => (default => sub { [] });
  10         18  
  10         584  
  0         0  
27 10     10   91 use constant dstr => (default => sub { "" });
  10         36  
  10         657  
  0         0  
28              
29             our %opts;
30             BEGIN {
31 10     10   3269 %opts => (limit => 5, skip => '');
32             }
33              
34             sub import {
35 11     11   29842 my ($package, @export) = @_;
36 11         25 my $target = caller;
37 11         34 my $has = return_has($target);
38              
39             my $attributes = sub {
40 5     5   48204 my @attr = @_;
41 5         19 while (@attr) {
42 31 100       59688 my @names = ref $attr[0] eq 'ARRAY' ? @{ shift @attr } : shift @attr;
  3         9  
43 31         40 my @spec = @{ shift(@attr) };
  31         63  
44            
45 31         50 my $eye = scalar @spec - 1;
46 56         200 (grep { ref $spec[$_] eq 'Type::Tiny'} (0 .. $eye))
47             ? push @spec, delete $spec[$eye]->{default}
48 31 100 66     63 : ( ref $spec[$eye] eq 'HASH' && exists $spec[$eye]->{default} ) && splice @spec, ($eye == 0 ? 0 : 1), 0, delete $spec[$eye]->{default};
49            
50 31         58 for (@names) {
51 36 100 100     2181 unshift @spec, 'set' if $_ =~ m/^\+/ and ( !$spec[0] || $spec[0] ne 'set' );
      100        
52 36 100 100     190 unshift @spec, ro unless ref \$spec[0] eq 'SCALAR' and $spec[0] =~ m/^ro|rw|set$/;
53 36         82 $has->( $_, construct_attribute(@spec) );
54             }
55             }
56 11         321 };
57              
58 11 100       37 if (ref $export[0]) {
59 1         1 my $o = shift @export;
60 1   66     6 exists $o->{$_} and $opts{$_} = $o->{$_} for (qw/limit skip/);
61             }
62              
63             {
64 10     10   84 no strict 'refs';
  10         17  
  10         4548  
  11         21  
65 132         273 ${"${target}::"}{$_} = ${"${package}::"}{$_}
  132         220  
66 11 100       37 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 11         17 *{"${target}::attributes"} = $attributes;
  11         50  
68             }
69              
70 11         2374 return 1;
71             }
72              
73             sub construct_attribute {
74 45     45 0 3666 my @spec = @_;
75 45         63 my %attr = ();
76 45 100       107 $attr{is} = $spec[0] unless $spec[0] eq 'set';
77              
78 45 100       90 if ( ref $spec[1] eq 'Type::Tiny' ) {
79 7         12 $attr{isa} = $spec[1];
80 7         12 $spec[1] = pop @spec;
81             }
82              
83 26     26   34850 $attr{default} = ref $spec[1] eq 'CODE' ? $spec[1] : sub { _clone( $spec[1] ) }
84 45 100       167 if defined $spec[1];
    100          
85              
86 45         63 $attr{$_} = $spec[2]->{$_} foreach keys %{ $spec[2] };
  45         121  
87              
88 45         173 return %attr;
89             }
90              
91             sub _clone {
92 50     50   19157 my ($to_clone, $recur) = @_;
93 50         84 my $blessed = blessed $to_clone;
94 50 50 0     95 $blessed =~ m/^$opts{skip}$/ and return $to_clone if $opts{skip};
95 50         85 my $clone = _deep_clone($to_clone, $recur);
96 50 100       427 return $blessed ? bless $clone, $blessed : $clone;
97             }
98              
99             sub _deep_clone {
100 53     53   1263 my ($to_clone, $recur) = @_;
101 53   66     179 my $rt = reftype($to_clone) || reftype(\$to_clone);
102 53 100       117 $rt eq 'SCALAR' and return $to_clone;
103 19         38 my $addr = refaddr $to_clone;
104 19 50 33     66 $recur->{$addr}++ && $recur->{$addr} > $opts{limit} and return $to_clone;
105 19 100       75 $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__