adding in the linearized_isa method
[gitmo/Class-MOP.git] / lib / Class / MOP / Attribute.pm
CommitLineData
8b978dd5 1
2package Class::MOP::Attribute;
3
4use strict;
5use warnings;
6
ba38bf08 7use Class::MOP::Method::Accessor;
8
2eb717d5 9use Carp 'confess';
9ec169fe 10use Scalar::Util 'blessed', 'reftype', 'weaken';
2eb717d5 11
232c4e13 12our $VERSION = '0.17';
f0480c45 13our $AUTHORITY = 'cpan:STEVAN';
8b978dd5 14
b1897d4d 15use base 'Class::MOP::Object';
16
1d68af04 17sub meta {
727919c5 18 require Class::MOP::Class;
aa448b16 19 Class::MOP::Class->initialize(blessed($_[0]) || $_[0]);
727919c5 20}
2eb717d5 21
727919c5 22# NOTE: (meta-circularity)
1d68af04 23# This method will be replaced in the
24# boostrap section of Class::MOP, by
25# a new version which uses the
727919c5 26# &Class::MOP::Class::construct_instance
27# method to build an attribute meta-object
28# which itself is described with attribute
1d68af04 29# meta-objects.
727919c5 30# - Ain't meta-circularity grand? :)
8b978dd5 31sub new {
32 my $class = shift;
33 my $name = shift;
1d68af04 34 my %options = @_;
35
cbd9f942 36 (defined $name && $name)
8b978dd5 37 || confess "You must provide a name for the attribute";
1d68af04 38
39 $options{init_arg} = $name
5659d76e 40 if not exists $options{init_arg};
1d68af04 41 if(exists $options{builder}){
42 confess("builder must be a defined scalar value which is a method name")
43 if ref $options{builder} || !(defined $options{builder});
44 confess("Setting both default and builder is not allowed.")
45 if exists $options{default};
8fe581e5 46 } else {
47 (is_default_a_coderef(\%options))
48 || confess("References are not allowed as default values, you must ".
49 "wrap then in a CODE reference (ex: sub { [] } and not [])")
50 if exists $options{default} && ref $options{default};
1d68af04 51 }
8b978dd5 52 bless {
c23184fc 53 '$!name' => $name,
54 '$!accessor' => $options{accessor},
55 '$!reader' => $options{reader},
56 '$!writer' => $options{writer},
57 '$!predicate' => $options{predicate},
58 '$!clearer' => $options{clearer},
1d68af04 59 '$!builder' => $options{builder},
c23184fc 60 '$!init_arg' => $options{init_arg},
61 '$!default' => $options{default},
1d68af04 62 # keep a weakened link to the
9ec169fe 63 # class we are associated with
c23184fc 64 '$!associated_class' => undef,
1d68af04 65 # and a list of the methods
3545c727 66 # associated with this attr
c23184fc 67 '@!associated_methods' => [],
8b978dd5 68 } => $class;
69}
70
7b31baf4 71# NOTE:
1d68af04 72# this is a primative (and kludgy) clone operation
16e960bd 73# for now, it will be replaced in the Class::MOP
1d68af04 74# bootstrap with a proper one, however we know
5659d76e 75# that this one will work fine for now.
76sub clone {
77 my $self = shift;
78 my %options = @_;
79 (blessed($self))
80 || confess "Can only clone an instance";
81 return bless { %{$self}, %options } => blessed($self);
82}
83
bd4e03f9 84sub initialize_instance_slot {
f892c0f0 85 my ($self, $meta_instance, $instance, $params) = @_;
c23184fc 86 my $init_arg = $self->{'$!init_arg'};
bd4e03f9 87 # try to fetch the init arg from the %params ...
8d2d4c67 88
1d68af04 89 # if nothing was in the %params, we can use the
bd4e03f9 90 # attribute's default value (if it has one)
8d2d4c67 91 if(exists $params->{$init_arg}){
92 $meta_instance->set_slot_value($instance, $self->name, $params->{$init_arg});
b7bdffc3 93 }
94 elsif (defined $self->{'$!default'}) {
8d2d4c67 95 $meta_instance->set_slot_value($instance, $self->name, $self->default($instance));
b7bdffc3 96 }
97 elsif (defined( my $builder = $self->{'$!builder'})) {
98 if ($builder = $instance->can($builder)) {
8d2d4c67 99 $meta_instance->set_slot_value($instance, $self->name, $instance->$builder);
b7bdffc3 100 }
101 else {
232c4e13 102 confess(blessed($instance)." does not support builder method '". $self->{'$!builder'} ."' for attribute '" . $self->name . "'");
8fe581e5 103 }
1d68af04 104 }
bd4e03f9 105}
106
5659d76e 107# NOTE:
1d68af04 108# the next bunch of methods will get bootstrapped
7b31baf4 109# away in the Class::MOP bootstrapping section
110
c23184fc 111sub name { $_[0]->{'$!name'} }
c50c603e 112
c23184fc 113sub associated_class { $_[0]->{'$!associated_class'} }
114sub associated_methods { $_[0]->{'@!associated_methods'} }
7b31baf4 115
c23184fc 116sub has_accessor { defined($_[0]->{'$!accessor'}) ? 1 : 0 }
117sub has_reader { defined($_[0]->{'$!reader'}) ? 1 : 0 }
118sub has_writer { defined($_[0]->{'$!writer'}) ? 1 : 0 }
119sub has_predicate { defined($_[0]->{'$!predicate'}) ? 1 : 0 }
120sub has_clearer { defined($_[0]->{'$!clearer'}) ? 1 : 0 }
1d68af04 121sub has_builder { defined($_[0]->{'$!builder'}) ? 1 : 0 }
c23184fc 122sub has_init_arg { defined($_[0]->{'$!init_arg'}) ? 1 : 0 }
123sub has_default { defined($_[0]->{'$!default'}) ? 1 : 0 }
c50c603e 124
1d68af04 125sub accessor { $_[0]->{'$!accessor'} }
c23184fc 126sub reader { $_[0]->{'$!reader'} }
127sub writer { $_[0]->{'$!writer'} }
128sub predicate { $_[0]->{'$!predicate'} }
129sub clearer { $_[0]->{'$!clearer'} }
1d68af04 130sub builder { $_[0]->{'$!builder'} }
c23184fc 131sub init_arg { $_[0]->{'$!init_arg'} }
c50c603e 132
7b31baf4 133# end bootstrapped away method section.
134# (all methods below here are kept intact)
135
b25109b1 136sub get_read_method { $_[0]->reader || $_[0]->accessor }
137sub get_write_method { $_[0]->writer || $_[0]->accessor }
138
1d68af04 139sub is_default_a_coderef {
140 ('CODE' eq (reftype($_[0]->{'$!default'} || $_[0]->{default}) || ''))
c0cbf4d9 141}
142
1d68af04 143sub default {
c0cbf4d9 144 my ($self, $instance) = @_;
9363ea89 145 if (defined $instance && $self->is_default_a_coderef) {
1d68af04 146 # if the default is a CODE ref, then
727919c5 147 # we pass in the instance and default
1d68af04 148 # can return a value based on that
727919c5 149 # instance. Somewhat crude, but works.
c23184fc 150 return $self->{'$!default'}->($instance);
1d68af04 151 }
c23184fc 152 $self->{'$!default'};
c50c603e 153}
8b978dd5 154
c57c8b10 155# slots
156
157sub slots { (shift)->name }
158
1d68af04 159# class association
727919c5 160
9ec169fe 161sub attach_to_class {
162 my ($self, $class) = @_;
163 (blessed($class) && $class->isa('Class::MOP::Class'))
164 || confess "You must pass a Class::MOP::Class instance (or a subclass)";
1d68af04 165 weaken($self->{'$!associated_class'} = $class);
9ec169fe 166}
167
168sub detach_from_class {
169 my $self = shift;
1d68af04 170 $self->{'$!associated_class'} = undef;
9ec169fe 171}
172
1d68af04 173# method association
3545c727 174
175sub associate_method {
176 my ($self, $method) = @_;
c23184fc 177 push @{$self->{'@!associated_methods'}} => $method;
3545c727 178}
179
16e960bd 180## Slot management
181
182sub set_value {
1396f86b 183 my ($self, $instance, $value) = @_;
16e960bd 184
3545c727 185 Class::MOP::Class->initialize(blessed($instance))
16e960bd 186 ->get_meta_instance
3545c727 187 ->set_slot_value($instance, $self->name, $value);
16e960bd 188}
189
190sub get_value {
1396f86b 191 my ($self, $instance) = @_;
16e960bd 192
3545c727 193 Class::MOP::Class->initialize(blessed($instance))
16e960bd 194 ->get_meta_instance
1396f86b 195 ->get_slot_value($instance, $self->name);
16e960bd 196}
197
3545c727 198sub has_value {
199 my ($self, $instance) = @_;
1d68af04 200
8d2d4c67 201 Class::MOP::Class->initialize(blessed($instance))
202 ->get_meta_instance
203 ->is_slot_initialized($instance, $self->name);
3545c727 204}
205
206sub clear_value {
207 my ($self, $instance) = @_;
1d68af04 208
3545c727 209 Class::MOP::Class->initialize(blessed($instance))
210 ->get_meta_instance
1d68af04 211 ->deinitialize_slot($instance, $self->name);
3545c727 212}
213
ba38bf08 214## load em up ...
c0cbf4d9 215
ba38bf08 216sub accessor_metaclass { 'Class::MOP::Method::Accessor' }
c0cbf4d9 217
9ec169fe 218sub process_accessors {
c0cbf4d9 219 my ($self, $type, $accessor, $generate_as_inline_methods) = @_;
013b1897 220 if (reftype($accessor)) {
221 (reftype($accessor) eq 'HASH')
7d28758b 222 || confess "bad accessor/reader/writer/predicate/clearer format, must be a HASH ref";
4d47b77f 223 my ($name, $method) = %{$accessor};
3545c727 224 $method = $self->accessor_metaclass->wrap($method);
225 $self->associate_method($method);
1d68af04 226 return ($name, $method);
2eb717d5 227 }
9ec169fe 228 else {
1d68af04 229 my $inline_me = ($generate_as_inline_methods && $self->associated_class->instance_metaclass->is_inlinable);
ba38bf08 230 my $method;
231 eval {
232 $method = $self->accessor_metaclass->new(
233 attribute => $self,
d90b42a6 234 is_inline => $inline_me,
ba38bf08 235 accessor_type => $type,
1d68af04 236 );
ba38bf08 237 };
1d68af04 238 confess "Could not create the '$type' method for " . $self->name . " because : $@" if $@;
3545c727 239 $self->associate_method($method);
ba38bf08 240 return ($accessor, $method);
1d68af04 241 }
9ec169fe 242}
243
244sub install_accessors {
c0cbf4d9 245 my $self = shift;
246 my $inline = shift;
247 my $class = $self->associated_class;
1d68af04 248
9ec169fe 249 $class->add_method(
c0cbf4d9 250 $self->process_accessors('accessor' => $self->accessor(), $inline)
9ec169fe 251 ) if $self->has_accessor();
252
1d68af04 253 $class->add_method(
c0cbf4d9 254 $self->process_accessors('reader' => $self->reader(), $inline)
9ec169fe 255 ) if $self->has_reader();
256
257 $class->add_method(
c0cbf4d9 258 $self->process_accessors('writer' => $self->writer(), $inline)
9ec169fe 259 ) if $self->has_writer();
260
261 $class->add_method(
c0cbf4d9 262 $self->process_accessors('predicate' => $self->predicate(), $inline)
9ec169fe 263 ) if $self->has_predicate();
1d68af04 264
7d28758b 265 $class->add_method(
266 $self->process_accessors('clearer' => $self->clearer(), $inline)
267 ) if $self->has_clearer();
1d68af04 268
9ec169fe 269 return;
2eb717d5 270}
271
b51af7f9 272{
273 my $_remove_accessor = sub {
274 my ($accessor, $class) = @_;
c50c603e 275 if (reftype($accessor) && reftype($accessor) eq 'HASH') {
276 ($accessor) = keys %{$accessor};
1d68af04 277 }
278 my $method = $class->get_method($accessor);
279 $class->remove_method($accessor)
ba38bf08 280 if (blessed($method) && $method->isa('Class::MOP::Method::Accessor'));
b51af7f9 281 };
1d68af04 282
b51af7f9 283 sub remove_accessors {
9ec169fe 284 my $self = shift;
2367814a 285 # TODO:
1d68af04 286 # we really need to make sure to remove from the
287 # associates methods here as well. But this is
288 # such a slimly used method, I am not worried
2367814a 289 # about it right now.
9ec169fe 290 $_remove_accessor->($self->accessor(), $self->associated_class()) if $self->has_accessor();
291 $_remove_accessor->($self->reader(), $self->associated_class()) if $self->has_reader();
292 $_remove_accessor->($self->writer(), $self->associated_class()) if $self->has_writer();
293 $_remove_accessor->($self->predicate(), $self->associated_class()) if $self->has_predicate();
7d28758b 294 $_remove_accessor->($self->clearer(), $self->associated_class()) if $self->has_clearer();
1d68af04 295 return;
b51af7f9 296 }
297
8b978dd5 298}
299
3001;
301
302__END__
303
304=pod
305
1d68af04 306=head1 NAME
8b978dd5 307
308Class::MOP::Attribute - Attribute Meta Object
309
310=head1 SYNOPSIS
1d68af04 311
8b978dd5 312 Class::MOP::Attribute->new('$foo' => (
fe122940 313 accessor => 'foo', # dual purpose get/set accessor
1d68af04 314 predicate => 'has_foo' # predicate check for defined-ness
fe122940 315 init_arg => '-foo', # class->new will look for a -foo key
316 default => 'BAR IS BAZ!' # if no -foo key is provided, use this
8b978dd5 317 ));
1d68af04 318
8b978dd5 319 Class::MOP::Attribute->new('$.bar' => (
fe122940 320 reader => 'bar', # getter
1d68af04 321 writer => 'set_bar', # setter
322 predicate => 'has_bar' # predicate check for defined-ness
fe122940 323 init_arg => ':bar', # class->new will look for a :bar key
8b978dd5 324 # no default value means it is undef
325 ));
326
327=head1 DESCRIPTION
328
fe122940 329The Attribute Protocol is almost entirely an invention of this module,
1d68af04 330and is completely optional to this MOP. This is because Perl 5 does not
331have consistent notion of what is an attribute of a class. There are
332so many ways in which this is done, and very few (if any) are
fe122940 333easily discoverable by this module.
552e3d24 334
1d68af04 335So, all that said, this module attempts to inject some order into this
336chaos, by introducing a consistent API which can be used to create
fe122940 337object attributes.
552e3d24 338
339=head1 METHODS
340
341=head2 Creation
342
343=over 4
344
fe122940 345=item B<new ($name, ?%options)>
346
1d68af04 347An attribute must (at the very least), have a C<$name>. All other
a2e85e6c 348C<%options> are contained added as key-value pairs. Acceptable keys
fe122940 349are as follows:
350
351=over 4
352
353=item I<init_arg>
354
1d68af04 355This should be a string value representing the expected key in
356an initialization hash. For instance, if we have an I<init_arg>
fe122940 357value of C<-foo>, then the following code will Just Work.
358
359 MyClass->meta->construct_instance(-foo => "Hello There");
360
1d68af04 361In an init_arg is not assigned, it will automatically use the
7b31baf4 362value of C<$name>.
363
fe122940 364=item I<default>
365
1d68af04 366The value of this key is the default value which
367C<Class::MOP::Class::construct_instance> will initialize the
368attribute to.
369
370=item I<builder>
371
372The value of this key is the name of the method that will be
373called to obtain the value used to initialize the attribute.
374This should be a method in the class associated with the attribute,
375not a method in the attribute class itself.
fe122940 376
377B<NOTE:>
1d68af04 378If the value is a simple scalar (string or number), then it can
379be just passed as is. However, if you wish to initialize it with
380a HASH or ARRAY ref, then you need to wrap that inside a CODE
fe122940 381reference, like so:
382
383 Class::MOP::Attribute->new('@foo' => (
384 default => sub { [] },
385 ));
1d68af04 386
387 # or ...
388
fe122940 389 Class::MOP::Attribute->new('%foo' => (
390 default => sub { {} },
1d68af04 391 ));
fe122940 392
1d68af04 393If you wish to initialize an attribute with a CODE reference
fe122940 394itself, then you need to wrap that in a subroutine as well, like
395so:
1d68af04 396
fe122940 397 Class::MOP::Attribute->new('&foo' => (
398 default => sub { sub { print "Hello World" } },
399 ));
400
1d68af04 401And lastly, if the value of your attribute is dependent upon
402some other aspect of the instance structure, then you can take
403advantage of the fact that when the I<default> value is a CODE
404reference, it is passed the raw (unblessed) instance structure
fe122940 405as it's only argument. So you can do things like this:
406
407 Class::MOP::Attribute->new('$object_identity' => (
408 default => sub { Scalar::Util::refaddr($_[0]) },
409 ));
410
1d68af04 411This last feature is fairly limited as there is no gurantee of
412the order of attribute initializations, so you cannot perform
413any kind of dependent initializations. However, if this is
414something you need, you could subclass B<Class::MOP::Class> and
415this class to acheive it. However, this is currently left as
fe122940 416an exercise to the reader :).
417
418=back
419
7d28758b 420The I<accessor>, I<reader>, I<writer>, I<predicate> and I<clearer> keys can
421contain either; the name of the method and an appropriate default one will be
422generated for you, B<or> a HASH ref containing exactly one key (which will be
423used as the name of the method) and one value, which should contain a CODE
424reference which will be installed as the method itself.
59e7697f 425
426=over 4
427
428=item I<accessor>
429
1d68af04 430The I<accessor> is a standard perl-style read/write accessor. It will
431return the value of the attribute, and if a value is passed as an argument,
fe122940 432it will assign that value to the attribute.
433
434B<NOTE:>
1d68af04 435This method will properly handle the following code, by assigning an
fe122940 436C<undef> value to the attribute.
437
438 $object->set_something(undef);
439
59e7697f 440=item I<reader>
441
1d68af04 442This is a basic read-only accessor, it will just return the value of
fe122940 443the attribute.
444
59e7697f 445=item I<writer>
446
1d68af04 447This is a basic write accessor, it accepts a single argument, and
448assigns that value to the attribute. This method does not intentially
449return a value, however perl will return the result of the last
450expression in the subroutine, which returns in this returning the
451same value that it was passed.
59e7697f 452
fe122940 453B<NOTE:>
1d68af04 454This method will properly handle the following code, by assigning an
fe122940 455C<undef> value to the attribute.
59e7697f 456
fe122940 457 $object->set_something();
458
459=item I<predicate>
460
1d68af04 461This is a basic test to see if the value of the attribute is not
462C<undef>. It will return true (C<1>) if the attribute's value is
fe122940 463defined, and false (C<0>) otherwise.
59e7697f 464
7d28758b 465=item I<clearer>
466
467This is the a method that will uninitialize the attr, reverting lazy values
468back to their "unfulfilled" state.
469
59e7697f 470=back
552e3d24 471
bd4e03f9 472=item B<clone (%options)>
473
474=item B<initialize_instance_slot ($instance, $params)>
475
1d68af04 476=back
552e3d24 477
16e960bd 478=head2 Value management
479
1d68af04 480These methods are basically "backdoors" to the instance, which can be used
481to bypass the regular accessors, but still stay within the context of the MOP.
2367814a 482
1d68af04 483These methods are not for general use, and should only be used if you really
2367814a 484know what you are doing.
485
16e960bd 486=over 4
487
3545c727 488=item B<set_value ($instance, $value)>
16e960bd 489
490Set the value without going through the accessor. Note that this may be done to
491even attributes with just read only accessors.
492
3545c727 493=item B<get_value ($instance)>
16e960bd 494
495Return the value without going through the accessor. Note that this may be done
496even to attributes with just write only accessors.
497
3545c727 498=item B<has_value ($instance)>
499
1d68af04 500Returns a boolean indicating if the item in the C<$instance> has a value in it.
2367814a 501This is basically what the default C<predicate> method calls.
502
3545c727 503=item B<clear_value ($instance)>
504
2367814a 505This will clear the value in the C<$instance>. This is basically what the default
1d68af04 506C<clearer> would call. Note that this may be done even if the attirbute does not
2367814a 507have any associated read, write or clear methods.
508
16e960bd 509=back
510
552e3d24 511=head2 Informational
512
1d68af04 513These are all basic read-only value accessors for the values
fe122940 514passed into C<new>. I think they are pretty much self-explanitory.
515
552e3d24 516=over 4
517
518=item B<name>
519
520=item B<accessor>
521
522=item B<reader>
523
524=item B<writer>
525
c50c603e 526=item B<predicate>
527
7d28758b 528=item B<clearer>
529
552e3d24 530=item B<init_arg>
531
495af518 532=item B<is_default_a_coderef>
533
fe122940 534=item B<default (?$instance)>
535
1d68af04 536As noted in the documentation for C<new> above, if the I<default>
fe122940 537value is a CODE reference, this accessor will pass a single additional
538argument C<$instance> into it and return the value.
552e3d24 539
c57c8b10 540=item B<slots>
541
1d68af04 542Returns a list of slots required by the attribute. This is usually
c57c8b10 543just one, which is the name of the attribute.
544
b25109b1 545=item B<get_read_method>
546
547=item B<get_write_method>
548
549Return the name of a method suitable for reading / writing the value of the
550attribute in the associated class. Suitable for use whether C<reader> and
551C<writer> or C<accessor> was used.
552
552e3d24 553=back
554
555=head2 Informational predicates
556
a2e85e6c 557These are all basic predicate methods for the values passed into C<new>.
fe122940 558
552e3d24 559=over 4
560
561=item B<has_accessor>
562
552e3d24 563=item B<has_reader>
564
552e3d24 565=item B<has_writer>
566
c50c603e 567=item B<has_predicate>
568
7d28758b 569=item B<has_clearer>
570
552e3d24 571=item B<has_init_arg>
572
552e3d24 573=item B<has_default>
574
bf731086 575=item B<has_builder>
576
552e3d24 577=back
578
9ec169fe 579=head2 Class association
580
1d68af04 581These methods allow you to manage the attributes association with
582the class that contains it. These methods should not be used
2367814a 583lightly, nor are they very magical, they are mostly used internally
584and by metaclass instances.
585
9ec169fe 586=over 4
587
588=item B<associated_class>
589
2367814a 590This returns the metaclass this attribute is associated with.
591
9ec169fe 592=item B<attach_to_class ($class)>
593
1d68af04 594This will store a weaken reference to C<$class> internally. You should
2367814a 595note that just changing the class assocation will not remove the attribute
596from it's old class, and initialize it (and it's accessors) in the new
597C<$class>. It is up to you to do this manually.
598
9ec169fe 599=item B<detach_from_class>
600
1d68af04 601This will remove the weakened reference to the class. It does B<not>
602remove the attribute itself from the class (or remove it's accessors),
603you must do that yourself if you want too. Actually if that is what
604you want to do, you should probably be looking at
2367814a 605L<Class::MOP::Class::remove_attribute> instead.
606
9ec169fe 607=back
608
552e3d24 609=head2 Attribute Accessor generation
610
611=over 4
612
ba38bf08 613=item B<accessor_metaclass>
614
2367814a 615Accessors are generated by an accessor metaclass, which is usually
1d68af04 616a subclass of C<Class::MOP::Method::Accessor>. This method returns
2367814a 617the name of the accessor metaclass that this attribute uses.
618
619=item B<associate_method ($method)>
620
1d68af04 621This will associate a C<$method> with the given attribute which is
622used internally by the accessor generator.
3545c727 623
624=item B<associated_methods>
625
1d68af04 626This will return the list of methods which have been associated with
627the C<associate_method> methods.
2367814a 628
9ec169fe 629=item B<install_accessors>
2eb717d5 630
1d68af04 631This allows the attribute to generate and install code for it's own
632I<accessor/reader/writer/predicate> methods. This is called by
fe122940 633C<Class::MOP::Class::add_attribute>.
2eb717d5 634
1d68af04 635This method will call C<process_accessors> for each of the possible
9ec169fe 636method types (accessor, reader, writer & predicate).
637
638=item B<process_accessors ($type, $value)>
639
1d68af04 640This takes a C<$type> (accessor, reader, writer or predicate), and
9ec169fe 641a C<$value> (the value passed into the constructor for each of the
1d68af04 642different types). It will then either generate the method itself
643(using the C<generate_*_method> methods listed below) or it will
644use the custom method passed through the constructor.
9ec169fe 645
9ec169fe 646=item B<remove_accessors>
2eb717d5 647
1d68af04 648This allows the attribute to remove the method for it's own
649I<accessor/reader/writer/predicate/clearer>. This is called by
fe122940 650C<Class::MOP::Class::remove_attribute>.
2eb717d5 651
1d68af04 652NOTE: This does not currently remove methods from the list returned
2367814a 653by C<associated_methods>, that is on the TODO list.
654
2eb717d5 655=back
656
657=head2 Introspection
658
659=over 4
552e3d24 660
2eb717d5 661=item B<meta>
552e3d24 662
1d68af04 663This will return a B<Class::MOP::Class> instance which is related
fe122940 664to this class.
665
1d68af04 666It should also be noted that B<Class::MOP> will actually bootstrap
667this module by installing a number of attribute meta-objects into
668it's metaclass. This will allow this class to reap all the benifits
669of the MOP when subclassing it.
fe122940 670
552e3d24 671=back
672
1a09d9cc 673=head1 AUTHORS
8b978dd5 674
a2e85e6c 675Stevan Little E<lt>stevan@iinteractive.comE<gt>
8b978dd5 676
677=head1 COPYRIGHT AND LICENSE
678
2367814a 679Copyright 2006, 2007 by Infinity Interactive, Inc.
8b978dd5 680
681L<http://www.iinteractive.com>
682
683This library is free software; you can redistribute it and/or modify
1d68af04 684it under the same terms as Perl itself.
8b978dd5 685
16e960bd 686=cut
687
7d28758b 688