2 package Class::MOP::Attribute;
8 use Scalar::Util 'blessed', 'reftype';
10 our $VERSION = '0.01';
13 require Class::MOP::Class;
14 Class::MOP::Class->initialize($_[0])
17 # NOTE: (meta-circularity)
18 # This method will be replaces in the
19 # boostrap section of Class::MOP, by
20 # a new version which uses the
21 # &Class::MOP::Class::construct_instance
22 # method to build an attribute meta-object
23 # which itself is described with attribute
25 # - Ain't meta-circularity grand? :)
31 (defined $name && $name)
32 || confess "You must provide a name for the attribute";
33 (!exists $options{reader} && !exists $options{writer})
34 || confess "You cannot declare an accessor and reader and/or writer functions"
35 if exists $options{accessor};
39 accessor => $options{accessor},
40 reader => $options{reader},
41 writer => $options{writer},
42 predicate => $options{predicate},
43 init_arg => $options{init_arg},
44 default => $options{default}
48 sub name { $_[0]->{name} }
50 sub has_accessor { defined($_[0]->{accessor}) ? 1 : 0 }
51 sub has_reader { defined($_[0]->{reader}) ? 1 : 0 }
52 sub has_writer { defined($_[0]->{writer}) ? 1 : 0 }
53 sub has_predicate { defined($_[0]->{predicate}) ? 1 : 0 }
54 sub has_init_arg { defined($_[0]->{init_arg}) ? 1 : 0 }
55 sub has_default { defined($_[0]->{default}) ? 1 : 0 }
57 sub accessor { $_[0]->{accessor} }
58 sub reader { $_[0]->{reader} }
59 sub writer { $_[0]->{writer} }
60 sub predicate { $_[0]->{predicate} }
61 sub init_arg { $_[0]->{init_arg} }
65 if (reftype($self->{default}) && reftype($self->{default}) eq 'CODE') {
66 # if the default is a CODE ref, then
67 # we pass in the instance and default
68 # can return a value based on that
69 # instance. Somewhat crude, but works.
70 return $self->{default}->(shift);
76 # this is just a utility routine to
77 # handle the details of accessors
78 my $_inspect_accessor = sub {
79 my ($attr_name, $type, $accessor) = @_;
81 my %ACCESSOR_TEMPLATES = (
83 $_[0]->{$attr_name} = $_[1] if scalar(@_) == 2;
90 $_[0]->{$attr_name} = $_[1];
94 return defined $_[0]->{$attr_name} ? 1 : 0;
98 if (reftype($accessor) && reftype($accessor) eq 'HASH') {
99 my ($name, $method) = each %{$accessor};
100 return ($name, Class::MOP::Attribute::Accessor->wrap($method));
103 return ($accessor => Class::MOP::Attribute::Accessor->wrap($ACCESSOR_TEMPLATES{$type}));
107 sub install_accessors {
108 my ($self, $class) = @_;
109 (blessed($class) && $class->isa('Class::MOP::Class'))
110 || confess "You must pass a Class::MOP::Class instance (or a subclass)";
113 $_inspect_accessor->($self->name, 'accessor' => $self->accessor())
114 ) if $self->has_accessor();
117 $_inspect_accessor->($self->name, 'reader' => $self->reader())
118 ) if $self->has_reader();
121 $_inspect_accessor->($self->name, 'writer' => $self->writer())
122 ) if $self->has_writer();
125 $_inspect_accessor->($self->name, 'predicate' => $self->predicate())
126 ) if $self->has_predicate();
131 sub remove_accessors {
132 my ($self, $class) = @_;
133 (blessed($class) && $class->isa('Class::MOP::Class'))
134 || confess "You must pass a Class::MOP::Class instance (or a subclass)";
136 if ($self->has_accessor()) {
137 my $accessor = $self->accessor();
138 if (reftype($accessor) && reftype($accessor) eq 'HASH') {
139 ($accessor) = keys %{$accessor};
141 my $method = $class->get_method($accessor);
142 $class->remove_method($accessor)
143 if (blessed($method) && $method->isa('Class::MOP::Attribute::Accessor'));
146 if ($self->has_reader()) {
147 my $reader = $self->reader();
148 if (reftype($reader) && reftype($reader) eq 'HASH') {
149 ($reader) = keys %{$reader};
151 my $method = $class->get_method($reader);
152 $class->remove_method($reader)
153 if (blessed($method) && $method->isa('Class::MOP::Attribute::Accessor'));
155 if ($self->has_writer()) {
156 my $writer = $self->writer();
157 if (reftype($writer) && reftype($writer) eq 'HASH') {
158 ($writer) = keys %{$writer};
160 my $method = $class->get_method($writer);
161 $class->remove_method($writer)
162 if (blessed($method) && $method->isa('Class::MOP::Attribute::Accessor'));
166 if ($self->has_predicate()) {
167 my $predicate = $self->predicate();
168 if (reftype($predicate) && reftype($predicate) eq 'HASH') {
169 ($predicate) = keys %{$predicate};
171 my $method = $class->get_method($predicate);
172 $class->remove_method($predicate)
173 if (blessed($method) && $method->isa('Class::MOP::Attribute::Accessor'));
177 package Class::MOP::Attribute::Accessor;
182 use Class::MOP::Method;
184 our $VERSION = '0.01';
186 our @ISA = ('Class::MOP::Method');
196 Class::MOP::Attribute - Attribute Meta Object
200 Class::MOP::Attribute->new('$foo' => (
201 accessor => 'foo', # dual purpose get/set accessor
202 init_arg => '-foo', # class->new will look for a -foo key
203 default => 'BAR IS BAZ!' # if no -foo key is provided, use this
206 Class::MOP::Attribute->new('$.bar' => (
207 reader => 'bar', # getter
208 writer => 'set_bar', # setter
209 init_arg => '-bar', # class->new will look for a -bar key
210 # no default value means it is undef
215 The Attribute Protocol is almost entirely an invention of this module. This is
216 because Perl 5 does not have consistent notion of what is an attribute
217 of a class. There are so many ways in which this is done, and very few
218 (if any) are discoverable by this module.
220 So, all that said, this module attempts to inject some order into this
221 chaos, by introducing a more consistent approach.
229 =item B<new ($name, %accessor_description, $class_initialization_arg, $default_value)>
253 =head2 Informational predicates
257 =item B<has_accessor>
259 Returns true if this attribute uses a get/set accessor, and false
264 Returns true if this attribute has a reader, and false otherwise
268 Returns true if this attribute has a writer, and false otherwise
270 =item B<has_predicate>
272 Returns true if this attribute has a predicate, and false otherwise
274 =item B<has_init_arg>
276 Returns true if this attribute has a class intialization argument, and
281 Returns true if this attribute has a default value, and false
286 =head2 Attribute Accessor generation
290 =item B<install_accessors ($class)>
292 This allows the attribute to generate and install code for it's own
293 accessor methods. This is called by C<Class::MOP::Class::add_attribute>.
295 =item B<remove_accessors ($class)>
297 This allows the attribute to remove the method for it's own
298 accessor. This is called by C<Class::MOP::Class::remove_attribute>.
312 Stevan Little E<gt>stevan@iinteractive.comE<lt>
314 =head1 COPYRIGHT AND LICENSE
316 Copyright 2006 by Infinity Interactive, Inc.
318 L<http://www.iinteractive.com>
320 This library is free software; you can redistribute it and/or modify
321 it under the same terms as Perl itself.