File Coverage

blib/lib/Class/Accessor/Typed.pm
Criterion Covered Total %
statement 146 154 94.8
branch 42 56 75.0
condition 10 15 66.6
subroutine 33 33 100.0
pod 0 1 0.0
total 231 259 89.1


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