File Coverage

blib/lib/Attribute/Property.pm
Criterion Covered Total %
statement 34 67 50.7
branch 7 32 21.8
condition 0 3 0.0
subroutine 10 19 52.6
pod 0 2 0.0
total 51 123 41.4


line stmt bran cond sub pod time code
1             package Attribute::Property;
2              
3             # $Id: Property.pm,v 1.48 2003/04/21 16:04:14 juerd Exp $
4              
5 1     1   17069 use 5.006;
  1         4  
  1         37  
6 1     1   1058 use Attribute::Handlers;
  1         8621  
  1         9  
7 1     1   40 use Carp;
  1         7  
  1         201  
8              
9             # use Want qw(want rreturn);
10             BEGIN {
11 1 50   1   2 if (eval { require Want }) {
  1         479  
12 0         0 *want = *Want::want;
13 0         0 *rreturn = *Want::rreturn;
14             } else {
15 1     0   64 *want = sub { 0 };
  0         0  
16 1     0   25 *rreturn = sub { 0 };
  0         0  
17             }
18             }
19              
20 1     1   5 no strict;
  1         2  
  1         32  
21 1     1   5 no warnings;
  1         2  
  1         429  
22              
23             our $VERSION = '1.05';
24              
25             $Carp::Internal{Attribute::Handlers}++; # may we be forgiven for our sins
26             $Carp::Internal{+__PACKAGE__}++;
27              
28             my %p;
29              
30             sub UNIVERSAL::Property : ATTR(CODE) {
31 13     13 0 1375 my (undef, $s, $r) = @_;
32 13 100       237 croak "Cannot use Property attribute with anonymous sub" unless ref $s;
33 12         22 my $n = *$s{NAME};
34             *$s = defined &$s
35             ? sub : lvalue {
36 0 0   0   0 croak "Too many arguments for $n method" if @_ > 2;
37 0 0       0 if (want 'RVALUE') {
38 0 0       0 rreturn $_[0]{$n} if @_ != 2;
39 0 0       0 $r->($_[0], local $_ = $_[1])
40             or croak "Invalid value for $n property";
41 0         0 rreturn $_[0]{$n} = $_;
42             }
43 0         0 tie my $foo, __PACKAGE__, ${ \$_[0]{$n} }, $r, $_[0], $n;
  0         0  
44 0 0       0 @_ == 2 ? ( $foo = $_[1] ) : $foo
45             }
46             : sub : lvalue {
47 0 0   0   0 croak "Too many arguments for $n method" if @_ > 2;
48 0 0       0 @_ == 2 ? ( $_[0]{$n} = $_[1] ) : ${ \$_[0]{$n} }
  0         0  
49 12 100       90 };
50 12         63 undef $p{\&$s};
51 1     1   7 }
  1         1  
  1         7  
52              
53 0     0     sub TIESCALAR { bless \@_, shift } # @_ = (class, lvalue, subref, object, name)
54 0     0     sub FETCH { $_[0][0] }
55              
56             sub STORE {
57 0 0   0     $_[0][1]->($_[0][2], local $_ = $_[1])
58             or croak "Invalid value for $_[0][3] property";
59 0           $_[0][0] = $_;
60             }
61              
62             sub UNIVERSAL::New : ATTR(CODE) {
63 3     3 0 23876 my ($P, $s, $r) = @_;
64 3         8 my $n = *$s{NAME};
65 3 100       15 undef $r if not defined &$s;
66             *$s = sub {
67 0     0     my $c = shift;
68 0 0         croak qq(Can't call method "$n" on a reference) if ref $c;
69 0 0         croak "Odd number of arguments for $c->$n" if @_ % 2;
70 0           my $o = bless {}, $c;
71 0           my $l = \&Carp::shortmess;
72 0     0     local *Carp::shortmess = sub { $_[-1] .= " in $c->$n"; &$l; };
  0            
  0            
73 0           while (my ($p, $v) = splice @_, 0, 2) {
74 0           my $m = $o->can($p);
75 0 0 0       $m and exists $p{$m} or croak qq(No such property "$p");
76 0           $m->($o, $v);
77             }
78 0 0         return $r->($o) if $r;
79 0           return $o;
80 3         32 };
81 1     1   675 }
  1         1  
  1         4  
82              
83             1;
84              
85             =head1 NAME
86              
87             Attribute::Property - Easy lvalue accessors with validation. ($foo->bar = 42)
88              
89             =head1 SYNOPSIS
90              
91             =head2 CLASS
92              
93             use Attribute::Property;
94             use Carp;
95              
96             package SomeClass;
97              
98             sub new : New { further initialization here ... }
99            
100             sub nondigits : Property { /^\D+\z/ }
101             sub digits : Property { /^\d+\z/ or croak "custom error message" }
102             sub anyvalue : Property;
103             sub another : Property;
104              
105             sub value : Property {
106             my $self = shift; # Object is accessible as $_[0]
107             s/^\s+//; # New value can be altered through $_ or $_[1]
108              
109             $_ <= $self->maximum or croak "Value exceeds maximum";
110             }
111              
112             package Person;
113              
114             sub new : New;
115             sub name : Property;
116             sub age : Property { /^\d+\z/ and $_ > 0 }
117              
118             =head2 USAGE
119              
120             my $object = SomeClass->new(digits => '123');
121              
122             $object->nondigits = "abc";
123             $object->digits = "123";
124             $object->anyvalue = "abc123\n";
125              
126             $object->anyvalue('archaic style still works');
127              
128             my $john = Person->new(name => 'John Doe', age => 19);
129            
130             $john->age++;
131             printf "%s is now %d years old", $john->name, $john->age;
132              
133             # These would croak
134             $object->nondigits = "987";
135             $object->digits = "xyz";
136              
137             =head1 DESCRIPTION
138              
139             This module introduces two attributes that make object oriented programming
140             much easier. You can just define a constructor and some properties without
141             having to write accessors.
142              
143             =over 4
144              
145             =item C
146              
147             sub color : Property;
148             sub color : Property { /^#[0-9A-F]{6}$/ }
149              
150             The C attribute turns a method into an object property. The original
151             code block is used only to validate new values, the module croaks if it returns
152             false. The method returns an I, meaning that you can create a reference
153             to it, assign to it and apply a regex to it.
154              
155             Undefined subs (subs that have been declared but do not have a code block) with
156             the C attribute will be properties without any value validation.
157              
158             In the validation code block, the object is in C<$_[0]> and the value to be
159             validated is aliased as C<$_[1]> and for regexing convenience as C<$_>.
160              
161             Feel free to croak explicitly if you don't want the default error message.
162              
163             =item C
164              
165             sub new : New;
166             sub new : New { my $self = shift; ...; return $self; }
167              
168             The C attribute turns a method into an object constructor. The original
169             code block can be used for further initialization, but it is completely
170             optional.
171              
172             The constructor takes named arguments in C<< property => value >> pairs and
173             populates the hash with the given pairs. After validating them, of course.
174              
175             The new object is passed to the initialization code block as C<$_[0]>. Be
176             sure to return the object if you use any initialization block. If there is
177             no initialization code block, Attribute::Property takes care of returning
178             the new object.
179              
180             =back
181              
182             =head1 PREREQUISITES
183              
184             Your object must be a blessed hash reference. The property names will be used
185             for the hash keys.
186              
187             For class properties of C, the hash C<%Some::Module> is used.
188             For class properties of packages without C<::>, the behaviour is undefined.
189              
190             In short: C<< $foo->bar = 14 >> and C<< $foo->bar(14) >> assign 14 to
191             C<< $foo->{bar} >> after positive validation. The same thing happens with C<< my
192             $foo = Class->new(bar => 14); >> given that C uses the C
193             property.
194              
195             If you have the Want module installed, Attribute::Property will use it to make
196             rvalue method calls more efficient.
197              
198             =head1 COMPATIBILITY
199              
200             Old fashioned C<< $object->property(VALUE) >> is still available.
201              
202             This module requires a modern Perl (5.6.0+), fossils like Perl 5.00x don't
203             support our chicanery.
204              
205             =head1 BUGS
206              
207             =over 2
208              
209             =item *
210              
211             The C attribute should really be called C, but that would
212             conflict with the existing Attribute::Constructor module.
213              
214             =back
215              
216             =head1 LICENSE
217              
218             There is no license. This software was released into the public domain. Do
219             with it what you want, but on your own risk. Both authors disclaim any
220             responsibility.
221              
222             =head1 AUTHORS
223              
224             Juerd Waalboer
225              
226             Matthijs van Duin
227              
228             =cut
229              
230             # vim: ft=perl sts=0 noet sw=8 ts=8
231