File Coverage

blib/lib/Class/Accessor/Typed.pm
Criterion Covered Total %
statement 144 151 95.3
branch 41 54 75.9
condition 10 15 66.6
subroutine 33 33 100.0
pod 0 1 0.0
total 228 254 89.7


line stmt bran cond sub pod time code
1             package Class::Accessor::Typed;
2 4     4   205348 use 5.008001;
  4         35  
3 4     4   18 use strict;
  4         5  
  4         75  
4 4     4   14 use warnings;
  4         8  
  4         84  
5              
6 4     4   15 use Carp;
  4         8  
  4         253  
7 4     4   1212 use Mouse::Util::TypeConstraints ();
  4         44922  
  4         1399  
8              
9             our $VERSION = "0.03";
10              
11             *_get_isa_type_constraint = \&Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint;
12             *_get_does_type_constraint = \&Mouse::Util::TypeConstraints::find_or_create_does_type_constraint;
13              
14             our $VERBOSE = 1;
15              
16             my %key_ctor = (
17             rw => \&_mk_accessors,
18             ro => \&_mk_ro_accessors,
19             wo => \&_mk_wo_accessors,
20             rw_lazy => \&_mk_lazy_accessors,
21             ro_lazy => \&_mk_ro_lazy_accessors,
22             );
23              
24             sub import {
25 6     6   81 my ($class, %args) = @_;
26 6         17 my $pkg = caller(0);
27              
28 6         87 my %rules;
29              
30 6         34 for my $key (sort keys %key_ctor) {
31 30 100       65 if (defined $args{$key}) {
32 8 50       24 croak("value of the '$key' parameter should be an hashref") unless ref($args{$key}) eq 'HASH';
33              
34 8         11 for my $n (sort keys %{ $args{$key} }) {
  8         23  
35             my $rule = ref($args{$key}->{$n}) eq 'HASH'
36 17 100       44 ? $args{$key}->{$n} : { isa => $args{$key}->{$n} };
37              
38 17         21 $rule->{type} = do {
39 17 50       28 if (defined $rule->{isa}) {
    0          
40 17         32 _get_isa_type_constraint($rule->{isa});
41             } elsif (defined $rule->{does}) {
42 0         0 _get_does_type_constraint($rule->{does});
43             }
44             };
45 17 100 100     250 $rule->{lazy} = ($key eq 'rw_lazy' or $key eq 'ro_lazy') ? 1 : 0;
46              
47 17         25 $args{$key}->{$n} = $rule;
48 17         29 $rules{$n} = $rule;
49             }
50 8         11 $key_ctor{$key}->($pkg, %{ $args{$key} });
  8         20  
51             }
52             }
53 6 100 66     77 return 1 if exists $args{new} && !$args{new};
54              
55 5         20 _mk_new($pkg, %rules);
56 5         5179 return 1;
57             }
58              
59             sub _mk_new {
60 5     5   7 my $pkg = shift;
61 4     4   35 no strict 'refs';
  4         5  
  4         311  
62              
63 5         11 *{ $pkg . '::new' } = __m_new($pkg, @_);
  5         28  
64             }
65              
66             sub _mk_accessors {
67 4     4   4 my $pkg = shift;
68 4     4   23 no strict 'refs';
  4         7  
  4         341  
69              
70 4         10 while (@_) {
71 6         8 my $n = shift;
72 6         7 my $rule = shift;
73 6         20 *{ $pkg . '::' . $n } = __m($n, $rule->{type});
  6         41  
74             }
75             }
76              
77             sub _mk_ro_accessors {
78 1     1   2 my $pkg = shift;
79 4     4   22 no strict 'refs';
  4         7  
  4         320  
80              
81 1         3 while (@_) {
82 2         2 my $n = shift;
83 2         4 my $rule = shift;
84 2         9 *{ $pkg . '::' . $n } = __m_ro($pkg, $n);
  2         11  
85             }
86             }
87              
88             sub _mk_wo_accessors {
89 1     1   3 my $pkg = shift;
90 4     4   22 no strict 'refs';
  4         6  
  4         335  
91              
92 1         3 while (@_) {
93 1         1 my $n = shift;
94 1         2 my $rule = shift;
95 1         2 *{ $pkg . '::' . $n } = __m_wo($pkg, $n, $rule->{type});
  1         5  
96             }
97             }
98              
99             sub _mk_lazy_accessors {
100 1     1   2 my $pkg = shift;
101 4     4   23 no strict 'refs';
  4         8  
  4         404  
102              
103 1         2 while (@_) {
104 4         6 my $n = shift;
105 4         4 my $rule = shift;
106 4   66     22 my $builder = $rule->{builder} || "_build_$n";
107 4         13 *{ $pkg . '::' . $n } = __m_lazy($n, $rule->{type}, $builder);
  4         17  
108             }
109             }
110              
111             sub _mk_ro_lazy_accessors {
112 1     1   2 my $pkg = shift;
113 4     4   23 no strict 'refs';
  4         7  
  4         412  
114              
115 1         2 while (@_) {
116 4         7 my $n = shift;
117 4         4 my $rule = shift;
118 4   66     18 my $builder = $rule->{builder} || "_build_$n";
119 4         6 *{ $pkg . '::' . $n } = __m_ro_lazy($pkg, $n, $rule->{type}, $builder);
  4         20  
120             }
121             }
122              
123             sub __m_new {
124 5     5   8 my $pkg = shift;
125 5         11 my %rules = @_;
126 4     4   30 no strict 'refs';
  4         7  
  4         3191  
127             return sub {
128 15     15   35163 my $klass = shift;
129 15 50 33     107 my %args = (@_ == 1 && ref($_[0]) eq 'HASH' ? %{ $_[0] } : @_);
  0         0  
130 15         24 my %params;
131              
132 15         92 for my $n (sort keys %rules) {
133 72 100       134 if (!exists $args{$n}) {
134 27 100       63 next if $rules{$n}->{lazy};
135              
136 3 100       9 if ($rules{$n}->{default}) {
    100          
137 1         3 $args{$n} = $rules{$n}->{default};
138             } elsif ($rules{$n}->{optional}) {
139 1         4 next;
140             } else {
141 1         4 error("missing mandatory parameter named '\$$n'");
142             }
143             }
144 46         105 $params{$n} = _check($n, $rules{$n}->{type}, $args{$n});
145             }
146              
147 12 100       115 if (keys %args > keys %rules) {
148 1         4 my $message = 'unknown arguments: ' . join ', ', sort grep { not exists $rules{$_} } keys %args;
  6         11  
149 1         40 warnings::warn(void => $message);
150             }
151 12         353 bless \%params, $klass;
152 5         35 };
153             }
154              
155             sub __m {
156 6     6   10 my ($n, $type) = @_;
157              
158             sub {
159 15 100   15   206 return $_[0]->{$n} if @_ == 1;
160 4 50       15 return $_[0]->{$n} = _check($n, $type, $_[1]) if @_ == 2;
161 6         28 };
162             }
163              
164             sub __m_ro {
165 2     2   3 my ($pkg, $n) = @_;
166              
167             sub {
168 3 100   3   56 return $_[0]->{$n} if @_ == 1;
169 1         25 my $caller = caller(0);
170 1         46 error("'$caller' cannot access the value of '$n' on objects of class '$pkg'");
171 2         13 };
172             }
173              
174             sub __m_wo {
175 1     1   2 my ($pkg, $n, $type) = @_;
176              
177             sub {
178 2 100   2   67 return $_[0]->{$n} = _check($n, $type, $_[1]) if @_ == 2;
179 1         4 my $caller = caller(0);
180 1         39 error("'$caller' cannot alter the value of '$n' on objects of class '$pkg'");
181 1         3 };
182             }
183              
184             sub __m_lazy {
185 4     4   7 my ($n, $type, $builder) = @_;
186              
187             sub {
188 11 100   11   2265 if (@_ == 1) {
    50          
189 9 100       38 return $_[0]->{$n} if exists $_[0]->{$n};
190 4         15 return $_[0]->{$n} = _check($n, $type, $_[0]->$builder);
191             } elsif (@_ == 2) {
192 2         7 return $_[0]->{$n} = _check($n, $type, $_[1]);
193             }
194 4         9 };
195             }
196              
197             sub __m_ro_lazy {
198 4     4   19 my ($pkg, $n, $type, $builder) = @_;
199              
200             sub {
201 8 50   8   83 if (@_ == 1) {
202 8 100       73 return $_[0]->{$n} if exists $_[0]->{$n};
203 4         17 return $_[0]->{$n} = _check($n, $type, $_[0]->$builder);
204             }
205 0         0 my $caller = caller(0);
206 0         0 error("'$caller' cannot alter the value of '$n' on objects of class '$pkg'");
207 4         12 };
208             }
209              
210             sub _check {
211 61     61   97 my $n = shift;
212 61         69 my $type = shift;
213 61         78 my $value = shift;
214              
215 61 50       105 return $value unless defined $type;
216 61 100       301 return $value if $type->check($value);
217              
218 7 50       87 if ($type->has_coercion) {
219 0         0 $value = $type->coerce($value);
220 0 0       0 return $value if $type->check($value);
221             }
222              
223 7         47 error("'$n': " . $type->get_message($value));
224             }
225              
226             sub error {
227 10     10 0 230 my $message = shift;
228              
229 10 50       28 if ($VERBOSE) {
230 10         126 confess($message);
231             } else {
232 0           croak($message);
233             }
234             }
235              
236             1;
237             __END__