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