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