File Coverage

blib/lib/Class/Meta/Attribute.pm
Criterion Covered Total %
statement 87 87 100.0
branch 62 64 96.8
condition 39 45 86.6
subroutine 18 18 100.0
pod 17 17 100.0
total 223 231 96.5


line stmt bran cond sub pod time code
1             package Class::Meta::Attribute;
2              
3             =head1 NAME
4              
5             Class::Meta::Attribute - Class::Meta class attribute introspection
6              
7             =head1 SYNOPSIS
8              
9             # Assuming MyApp::Thingy was generated by Class::Meta.
10             my $class = MyApp::Thingy->my_class;
11             my $thingy = MyApp::Thingy->new;
12              
13             print "\nAttributes:\n";
14             for my $attr ($class->attributes) {
15             print " o ", $attr->name, " => ", $attr->get($thingy), $/;
16             if ($attr->authz >= Class::Meta::SET && $attr->type eq 'string') {
17             $attr->get($thingy, 'hey there!');
18             print " Changed to: ", $attr->get($thingy) $/;
19             }
20             }
21              
22             =head1 DESCRIPTION
23              
24             An object of this class describes an attribute of a class created by
25             Class::Meta. It includes meta data such as the name of the attribute, its data
26             type, its accessibility, and whether or not a value is required. It also
27             provides methods to easily get and set the value of the attribute for a given
28             instance of the class.
29              
30             Class::Meta::Attribute objects are created by Class::Meta; they are never
31             instantiated directly in client code. To access the attribute objects for a
32             Class::Meta-generated class, simply call its C method to retrieve
33             its Class::Meta::Class object, and then call the C method on the
34             Class::Meta::Class object.
35              
36             =cut
37              
38             ##############################################################################
39             # Dependencies #
40             ##############################################################################
41 21     21   125 use strict;
  21         38  
  21         42148  
42              
43             ##############################################################################
44             # Package Globals #
45             ##############################################################################
46             our $VERSION = '0.66';
47              
48             ##############################################################################
49             # Private Package Globals #
50             ##############################################################################
51             my %type_pkg_for = (
52             map( { $_ => 'Boolean' } qw(bool boolean) ),
53             map( { $_ => 'Numeric' } qw(whole integer int decimal dec real float) ),
54             map(
55             { $_ => 'Perl' }
56             qw(scalar scalarref array arrayref hash hashref code coderef closure)
57             ),
58             string => 'String',
59             );
60              
61             ##############################################################################
62             # Constructors #
63             ##############################################################################
64              
65             =head1 INTERFACE
66              
67             =head2 Constructors
68              
69             =head3 new
70              
71             A protected method for constructing a Class::Meta::Attribute object. Do not
72             call this method directly; Call the
73             L|Class::Meta/"add_attribute"> method on a Class::Meta
74             object, instead.
75              
76             =cut
77              
78             sub new {
79 137     137 1 282 my $pkg = shift;
80 137         203 my $class = shift;
81              
82             # Check to make sure that only Class::Meta or a subclass is constructing a
83             # Class::Meta::Attribute object.
84 137         308 my $caller = caller;
85 137 100 100     899 Class::Meta->handle_error("Package '$caller' cannot create $pkg "
86             . "objects")
87             unless UNIVERSAL::isa($caller, 'Class::Meta')
88             || UNIVERSAL::isa($caller, __PACKAGE__);
89              
90             # Make sure we can get all the arguments.
91 135 100       497 $class->handle_error("Odd number of parameters in call to new() when "
92             . "named parameters were expected")
93             if @_ % 2;
94 134         696 my %p = @_;
95              
96             # Validate the name.
97 134 100       383 $class->handle_error("Parameter 'name' is required in call to new()")
98             unless $p{name};
99             # Is this too paranoid?
100 132 100       520 $class->handle_error("Attribute '$p{name}' is not a valid attribute "
101             . "name -- only alphanumeric and '_' characters "
102             . "allowed")
103             if $p{name} =~ /\W/;
104              
105             # Grab the package name.
106 131         356 $p{package} = $class->{package};
107              
108             # Set the required and once attributes.
109 131         309 for (qw(required once)) {
110 262 100       976 $p{$_} = $p{$_} ? 1 : 0;
111             }
112              
113             # Make sure the name hasn't already been used for another attribute
114 131 100 100     6004 $class->handle_error("Attribute '$p{name}' already exists in class '"
115             . $class->{attrs}{$p{name}}{package} . "'")
116             if ! delete $p{override} && exists $class->{attrs}{$p{name}};
117              
118             # Check the view.
119 128 100       353 if (exists $p{view}) {
120 61         265 $p{view} = Class::Meta::_str_to_const($p{view});
121 61 100 100     620 $class->handle_error(
      100        
      100        
122             "Not a valid view parameter: '$p{view}'"
123             ) unless $p{view} == Class::Meta::PUBLIC
124             or $p{view} == Class::Meta::PROTECTED
125             or $p{view} == Class::Meta::TRUSTED
126             or $p{view} == Class::Meta::PRIVATE;
127             } else {
128             # Make it public by default.
129 67         195 $p{view} = Class::Meta::PUBLIC;
130             }
131              
132             # Check the authorization level.
133 125 100       365 if (exists $p{authz}) {
134 12         39 $p{authz} = Class::Meta::_str_to_const($p{authz});
135 12 100 66     173 $class->handle_error(
      66        
      100        
136             "Not a valid authz parameter: '$p{authz}'"
137             ) unless $p{authz} == Class::Meta::NONE
138             or $p{authz} == Class::Meta::READ
139             or $p{authz} == Class::Meta::WRITE
140             or $p{authz} == Class::Meta::RDWR;
141             } else {
142             # Make it read/write by default.
143 113         271 $p{authz} = Class::Meta::RDWR;
144             }
145              
146             # Check the creation constant.
147 124 100       314 if (exists $p{create}) {
148 45         130 $p{create} = Class::Meta::_str_to_const($p{create});
149 45 100 100     531 $class->handle_error(
      66        
      100        
150             "Not a valid create parameter: '$p{create}'"
151             ) unless $p{create} == Class::Meta::NONE
152             or $p{create} == Class::Meta::GET
153             or $p{create} == Class::Meta::SET
154             or $p{create} == Class::Meta::GETSET;
155             } else {
156             # Rely on the authz setting by default.
157 79         268 $p{create} = $p{authz};
158             }
159              
160             # Check the context.
161 123 100       320 if (exists $p{context}) {
162 4         17 $p{context} = Class::Meta::_str_to_const($p{context});
163 4 100 100     42 $class->handle_error(
164             "Not a valid context parameter: '$p{context}'"
165             ) unless $p{context} == Class::Meta::OBJECT
166             or $p{context} == Class::Meta::CLASS;
167             } else {
168             # Put it in object context by default.
169 119         270 $p{context} = Class::Meta::OBJECT;
170             }
171              
172             # Check the type.
173 122 100       481 $p{type} = delete $p{is} if exists $p{is};
174 122   100     336 $p{type} ||= $class->default_type;
175 122 100       386 $class->handle_error( "No type specified for the '$p{name}' attribute" )
176             unless $p{type};
177 121 100       184 unless ( eval { Class::Meta::Type->new($p{type}) } ) {
  121         581  
178 6 100       38 my $pkg = $type_pkg_for{ $p{type} }
179             or $class->handle_error( "Unknown type: '$p{type}'" );
180 5         360 eval "require Class::Meta::Types::$pkg";
181 5 50       32 $class->handle_error( "Unknown type: '$p{type}'" ) if $@;
182 5         52 "Class::Meta::Types::$pkg"->import;
183             }
184              
185             # Check the default.
186 120 100       409 if (exists $p{default}) {
187             # A code ref should be executed when the default is called.
188 68 100       206 $p{_def_code} = delete $p{default}
189             if ref $p{default} eq 'CODE';
190             }
191              
192             # Create and cache the attribute object.
193 120   33     903 $class->{attrs}{$p{name}} = bless \%p, ref $pkg || $pkg;
194              
195             # Index its view.
196 120         194 push @{ $class->{all_attr_ord} }, $p{name};
  120         378  
197 120 100       380 if ($p{view} > Class::Meta::PRIVATE) {
198 116 100       393 push @{$class->{prot_attr_ord}}, $p{name}
  113         310  
199             unless $p{view} == Class::Meta::TRUSTED;
200 116 100       333 if ($p{view} > Class::Meta::PROTECTED) {
201 113         350 push @{$class->{trst_attr_ord}}, $p{name};
  113         309  
202 113 100       355 push @{$class->{attr_ord}}, $p{name}
  110         322  
203             if $p{view} == Class::Meta::PUBLIC;
204             }
205             }
206              
207             # Store a reference to the class object.
208 120         1621 $p{class} = $class;
209              
210             # Let 'em have it.
211 120         507 return $class->{attrs}{$p{name}};
212             }
213              
214             ##############################################################################
215             # Instance Methods #
216             ##############################################################################
217              
218             =head2 Instance Methods
219              
220             =head3 name
221              
222             my $name = $attr->name;
223              
224             Returns the name of the attribute.
225              
226             =head3 type
227              
228             my $type = $attr->type;
229              
230             Returns the name of the attribute's data type. Typical values are "scalar",
231             "string", and "boolean". See L for a
232             complete list.
233              
234             =head3 is
235              
236             if ($attr->is('string')) {
237             # ...
238             }
239              
240             A convenience method for C<< $attr->type eq $type >>.
241              
242             =head3 desc
243              
244             my $desc = $attr->desc;
245              
246             Returns a description of the attribute.
247              
248             =head3 label
249              
250             my $label = $attr->label;
251              
252             Returns a label for the attribute, suitable for use in a user interface. It is
253             distinguished from the attribute name, which functions to name the accessor
254             methods for the attribute.
255              
256             =head3 required
257              
258             my $req = $attr->required;
259              
260             Indicates if the attribute is required to have a value.
261              
262             =head3 once
263              
264             my $once = $attr->once;
265              
266             Indicates whether an attribute value can be set to a defined value only once.
267              
268             =head3 package
269              
270             my $package = $attr->package;
271              
272             Returns the package name of the class that attribute is associated with.
273              
274             =head3 view
275              
276             my $view = $attr->view;
277              
278             Returns the view of the attribute, reflecting its visibility. The possible
279             values are defined by the following constants:
280              
281             =over 4
282              
283             =item Class::Meta::PUBLIC
284              
285             =item Class::Meta::PRIVATE
286              
287             =item Class::Meta::TRUSTED
288              
289             =item Class::Meta::PROTECTED
290              
291             =back
292              
293             =head3 context
294              
295             my $context = $attr->context;
296              
297             Returns the context of the attribute, essentially whether it is a class or
298             object attribute. The possible values are defined by the following constants:
299              
300             =over 4
301              
302             =item Class::Meta::CLASS
303              
304             =item Class::Meta::OBJECT
305              
306             =back
307              
308             =head3 authz
309              
310             my $authz = $attr->authz;
311              
312             Returns the authorization for the attribute, which determines whether it can be
313             read or changed. The possible values are defined by the following constants:
314              
315             =over 4
316              
317             =item Class::Meta::READ
318              
319             =item Class::Meta::WRITE
320              
321             =item Class::Meta::RDWR
322              
323             =item Class::Meta::NONE
324              
325             =back
326              
327             =head3 class
328              
329             my $class = $attr->class;
330              
331             Returns the Class::Meta::Class object that this attribute is associated
332             with. Note that this object will always represent the class in which the
333             attribute is defined, and I any of its subclasses.
334              
335             =cut
336              
337 870     870 1 5348 sub name { $_[0]->{name} }
338 7     7 1 45 sub type { $_[0]->{type} }
339 7     7 1 45 sub desc { $_[0]->{desc} }
340 8     8 1 53 sub label { $_[0]->{label} }
341 363     363 1 2013 sub required { $_[0]->{required} }
342 107     107 1 708 sub once { $_[0]->{once} }
343 226     226 1 782 sub package { $_[0]->{package} }
344 428     428 1 1803 sub view { $_[0]->{view} }
345 502     502 1 2098 sub context { $_[0]->{context} }
346 139     139 1 790 sub authz { $_[0]->{authz} }
347 206     206 1 2232 sub class { $_[0]->{class} }
348 2     2 1 12 sub is { $_[0]->{type} eq $_[1] }
349              
350             ##############################################################################
351              
352             =head3 default
353              
354             my $default = $attr->default;
355              
356             Returns the default value for a new instance of this attribute. Since the
357             default value can be determined dynamically, the value returned by
358             C may change on subsequent calls. It all depends on what was
359             passed for the C parameter in the call to C on the
360             Class::Meta object that generated the class.
361              
362             =cut
363              
364             sub default {
365 258 100   258 1 803 if (my $code = $_[0]->{_def_code}) {
366 6         25 return $code->();
367             }
368 252         1005 return $_[0]->{default};
369             }
370              
371             ##############################################################################
372              
373             =head3 get
374              
375             my $value = $attr->get($thingy);
376              
377             This method calls the "get" accessor method on the object passed as the sole
378             argument and returns the value of the attribute for that object. Note that it
379             uses a C to execute the accessor, so the call to C itself
380             will not appear in a call stack trace.
381              
382             =cut
383              
384             sub get {
385 104     104 1 34805 my $self = shift;
386 104 100       599 my $code = $self->{_get} or $self->class->handle_error(
387             q{Cannot get attribute '}, $self->name, q{'}
388             );
389 103         624 goto &$code;
390             }
391              
392             ##############################################################################
393              
394             =head3 set
395              
396             $attr->set($thingy, $new_value);
397              
398             This method calls the "set" accessor method on the object passed as the first
399             argument and passes any remaining arguments to assign a new value to the
400             attribute for that object. Note that it uses a C to execute the
401             accessor, so the call to C itself will not appear in a call stack
402             trace.
403              
404             =cut
405              
406             sub set {
407 195     195 1 2726 my $self = shift;
408 195 100       842 my $code = $self->{_set} or $self->class->handle_error(
409             q{Cannot set attribute '}, $self->name, q{'}
410             );
411 192         846 goto &$code;
412             }
413              
414             ##############################################################################
415              
416             =head3 build
417              
418             $attr->build($class);
419              
420             This is a protected method, designed to be called only by the Class::Meta
421             class or a subclass of Class::Meta. It takes a single argument, the
422             Class::Meta::Class object for the class in which the attribute was defined,
423             and generates attribute accessors by calling out to the C and
424             C methods of Class::Meta::Type as appropriate for the
425             Class::Meta::Attribute object.
426              
427             Although you should never call this method directly, subclasses of
428             Class::Meta::Constructor may need to override its behavior.
429              
430             =cut
431              
432             sub build {
433 80     80 1 1725 my ($self, $class) = @_;
434              
435             # Check to make sure that only Class::Meta or a subclass is building
436             # attribute accessors.
437 80         147 my $caller = caller;
438 80 100 66     379 $self->class->handle_error(
439             "Package '$caller' cannot call " . ref($self) . "->build"
440             ) unless UNIVERSAL::isa($caller, 'Class::Meta')
441             || UNIVERSAL::isa($caller, __PACKAGE__);
442              
443             # Get the data type object and build any accessors.
444 79         328 my $type = Class::Meta::Type->new($self->{type});
445 79         238 $self->{type} = $type->key;
446 79         186 my $create = delete $self->{create};
447 79 100       381 $type->build($class->{package}, $self, $create)
448             if $create != Class::Meta::NONE;
449              
450             # Create the attribute object get code reference.
451 79 50       225 if ($self->{authz} >= Class::Meta::READ) {
452 79         246 $self->{_get} = $type->make_attr_get($self);
453             }
454              
455             # Create the attribute object set code reference.
456 79 100       1787 if ($self->{authz} >= Class::Meta::WRITE) {
457 75         243 $self->{_set} = $type->make_attr_set($self);
458             }
459              
460             }
461              
462             1;
463             __END__