X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FClass%2FMOP%2FInstance.pm;h=a9d5a5d36ddf95e28d21616fa1786d68b661db43;hb=8ee74136c5d5c5a6416844e7238898f47b00f553;hp=dcc13c76d3bea66251c7f7041619277ba7b2d0c4;hpb=84ef30d18bb35c6ac09d1e3f7d49a27d275c88e1;p=gitmo%2FClass-MOP.git diff --git a/lib/Class/MOP/Instance.pm b/lib/Class/MOP/Instance.pm index dcc13c7..a9d5a5d 100644 --- a/lib/Class/MOP/Instance.pm +++ b/lib/Class/MOP/Instance.pm @@ -4,173 +4,170 @@ package Class::MOP::Instance; use strict; use warnings; -use Carp 'confess'; -use Scalar::Util 'blessed', 'reftype', 'weaken'; +use Scalar::Util 'weaken', 'blessed'; -our $VERSION = '0.01'; +our $VERSION = '0.04'; +our $AUTHORITY = 'cpan:STEVAN'; -sub meta { +sub meta { require Class::MOP::Class; Class::MOP::Class->initialize(blessed($_[0]) || $_[0]); } -sub new { - my ( $class, $meta ) = @_; - bless { - meta => $meta, - instance_layout => {} - } => $class; +sub new { + my ($class, $meta, @attrs) = @_; + my @slots = map { $_->slots } @attrs; + my $instance = bless { + # NOTE: + # I am not sure that it makes + # sense to pass in the meta + # The ideal would be to just + # pass in the class name, but + # that is placing too much of + # an assumption on bless(), + # which is *probably* a safe + # assumption,.. but you can + # never tell <:) + '$!meta' => $meta, + '@!slots' => { map { $_ => undef } @slots }, + } => $class; + + weaken($instance->{'$!meta'}); + + return $instance; } +sub associated_metaclass { (shift)->{'$!meta'} } + sub create_instance { - my ( $self, $class ) = @_; - - # rely on autovivification - $self->bless_instance_structure( {}, $class ); + my $self = shift; + $self->bless_instance_structure({}); } sub bless_instance_structure { - my ( $self, $instance_structure, $class ) = @_; - $class ||= $self->{meta}->name; - bless $instance_structure, $class; + my ($self, $instance_structure) = @_; + bless $instance_structure, $self->associated_metaclass->name; } -sub get_all_parents { - my $self = shift; - my @parents = $self->{meta}->class_precedence_list; - shift @parents; # shift off ourselves - return map { $_->get_meta_instance } map { $_->meta || () } @parents; +sub clone_instance { + my ($self, $instance) = @_; + $self->bless_instance_structure({ %$instance }); } # operations on meta instance -sub add_slot { - my ($self, $slot_name ) = @_; - confess "The slot '$slot_name' already exists" - if 0 && $self->has_slot_recursively( $slot_name ); # FIXME - $self->{instance_layout}->{$slot_name} = undef; -} - sub get_all_slots { my $self = shift; - keys %{ $self->{instance_layout} }; + return keys %{$self->{'@!slots'}}; } -sub get_all_slots_recursively { - my $self = shift; - return ( - $self->get_all_slots, - map { $_->get_all_slots } $self->get_all_parents, - ), -} - -sub has_slot { +sub is_valid_slot { my ($self, $slot_name) = @_; - exists $self->{instance_layout}->{$slot_name} ? 1 : 0; -} - -sub has_slot_recursively { - my ( $self, $slot_name ) = @_; - return 1 if $self->has_slot($slot_name); - $_->has_slot_recursively($slot_name) && return 1 for $self->get_all_parents; - return 0; -} - -sub remove_slot { - my ( $self, $slot_name ) = @_; - # NOTE: - # this does not search recursively cause - # that is not the domain of this meta-instance - # it is specific to this class ... - confess "The slot '$slot_name' does not exist (maybe it's inherited?)" - if 0 && $self->has_slot( $slot_name ); # FIXME - delete $self->{instance_layout}->{$slot_name}; + exists $self->{'@!slots'}->{$slot_name}; } - # operations on created instances sub get_slot_value { my ($self, $instance, $slot_name) = @_; - return $instance->{$slot_name}; + $instance->{$slot_name}; } -# can be called only after initialize_slot_value sub set_slot_value { my ($self, $instance, $slot_name, $value) = @_; $instance->{$slot_name} = $value; } -sub set_weak_slot_value { - my ( $self, $instance, $slot_name, $value) = @_; - $self->set_slot_value( $instance, $slot_name, $value ); - $self->weeaken_slot_value( $instance, $slot_name ); +sub initialize_slot { + my ($self, $instance, $slot_name) = @_; + #$self->set_slot_value($instance, $slot_name, undef); } -sub weaken_slot_value { - my ( $self, $instance, $slot_name ) = @_; - weaken( $instance->{$slot_name} ); +sub deinitialize_slot { + my ( $self, $instance, $slot_name ) = @_; + delete $instance->{$slot_name}; } -# convenience method -# non autovivifying stores will have this as { initialize_slot unless slot_initlized; set_slot_value } -sub set_slot_value_with_init { - my ( $self, $instance, $slot_name, $value ) = @_; - $self->set_slot_value( $instance, $slot_name, $value ); +sub initialize_all_slots { + my ($self, $instance) = @_; + foreach my $slot_name ($self->get_all_slots) { + $self->initialize_slot($instance, $slot_name); + } } -sub initialize_slot { - my ( $self, $instance, $slot_name ) = @_; +sub deinitialize_all_slots { + my ($self, $instance) = @_; + foreach my $slot_name ($self->get_all_slots) { + $self->deinitialize_slot($instance, $slot_name); + } +} + +sub is_slot_initialized { + my ($self, $instance, $slot_name, $value) = @_; + exists $instance->{$slot_name}; } -sub slot_initialized { +sub weaken_slot_value { + my ($self, $instance, $slot_name) = @_; + weaken $instance->{$slot_name}; +} + +sub strengthen_slot_value { my ($self, $instance, $slot_name) = @_; - exists $instance->{$slot_name} ? 1 : 0; + $self->set_slot_value($instance, $slot_name, $self->get_slot_value($instance, $slot_name)); } +sub rebless_instance_structure { + my ($self, $instance, $metaclass) = @_; + bless $instance, $metaclass->name; +} # inlinable operation snippets -sub inline_get_slot_value { +sub is_inlinable { 1 } + +sub inline_create_instance { + my ($self, $class_variable) = @_; + 'bless {} => ' . $class_variable; +} + +sub inline_slot_access { my ($self, $instance, $slot_name) = @_; sprintf "%s->{%s}", $instance, $slot_name; } -sub inline_set_slot_value { - my ($self, $instance, $slot_name, $value) = @_; - $self->_inline_slot_lvalue( $instance, $slot_name ) . " = $value", +sub inline_get_slot_value { + my ($self, $instance, $slot_name) = @_; + $self->inline_slot_access($instance, $slot_name); } -sub inline_set_weak_slot_value { - my ( $self, $instance, $slot_name, $value ) = @_; - return "" - . $self->inline_set_slot_value( $instance, $slot_name, $value ) - . "; " - . $self->inline_weaken_slot_value( $instance, $slot_name ); +sub inline_set_slot_value { + my ($self, $instance, $slot_name, $value) = @_; + $self->inline_slot_access($instance, $slot_name) . " = $value", } -sub inline_weaken_slot_value { - my ( $self, $instance, $slot_name ) = @_; - return 'Scalar::Util::weaken( ' . $self->_inline_slot_lvalue( $instance, $slot_name ) . ')'; +sub inline_initialize_slot { + my ($self, $instance, $slot_name) = @_; + $self->inline_set_slot_value($instance, $slot_name, 'undef'), } -sub inline_set_slot_value_with_init { - my ( $self, $instance, $slot_name, $value) = @_; - $self->inline_set_slot_value( $instance, $slot_name, $value ) . ";"; +sub inline_deinitialize_slot { + my ($self, $instance, $slot_name) = @_; + "delete " . $self->inline_slot_access($instance, $slot_name); } - -sub inline_initialize_slot { - return ""; +sub inline_is_slot_initialized { + my ($self, $instance, $slot_name) = @_; + "exists " . $self->inline_slot_access($instance, $slot_name); } -sub inline_slot_initialized { +sub inline_weaken_slot_value { my ($self, $instance, $slot_name) = @_; - "exists " . $self->inline_get_slot_value; + sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name); } -sub _inline_slot_lvalue { +sub inline_strengthen_slot_value { my ($self, $instance, $slot_name) = @_; - $self->inline_get_slot_value( $instance, $slot_name ); + $self->inline_set_slot_value($instance, $slot_name, $self->inline_slot_access($instance, $slot_name)); } 1; @@ -179,82 +176,166 @@ __END__ =pod -=head1 NAME +=head1 NAME Class::MOP::Instance - Instance Meta Object =head1 SYNOPSIS + # This API is largely internal + # you shouldn't need it unless you are writing meta attributes or meta + # instances + =head1 DESCRIPTION +The meta instance is used by attributes for low level storage. + +Using this API generally violates attribute encapsulation and is not +reccomended, instead look at L, +L for the reccomended way to fiddle with +attribute values in a generic way, independant of how/whether accessors have +been defined. Accessors can be found using L. + +This may seem like over-abstraction, but by abstracting +this process into a sub-protocol we make it possible to +easily switch the details of how an object's instance is +stored with minimal impact. In most cases just subclassing +this class will be all you need to do (see the examples; +F and +F for details). + =head1 METHODS =over 4 -=item B +=item B + +Creates a new instance meta-object and gathers all the slots from +the list of C<@attrs> given. + +=item B + +This will return a B instance which is related +to this class. + +=back -=item B +=head2 Creation of Instances -=item B +=over 4 =item B -=item B +This creates the appropriate structure needed for the instance and +then calls C to bless it into the class. -=item B +=item B -=item B +This does just exactly what it says it does. -=item B +=item B -=item B +=back -=item B +=head2 Instrospection -=item B +NOTE: There might be more methods added to this part of the API, +we will add then when we need them basically. -=item B +=over 4 -=item B +=item B -=item B +=item B -=item B +This will return the current list of slots based on what was +given to this object in C. -=item B +=item B -=item B +=back -=item B +=head2 Operations on Instance Structures -=item B +An important distinction of this sub-protocol is that the +instance meta-object is a different entity from the actual +instance it creates. For this reason, any actions on slots +require that the C<$instance_structure> is passed into them. + +=over 4 + +=item B + +=item B -=item B +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B =back -=head2 Introspection +=head2 Inlineable Instance Operations + +This part of the API is currently un-used. It is there for use +in future experiments in class finailization mostly. Best to +ignore this for now. =over 4 -=item B +=item B -This will return a B instance which is related -to this class. +Each meta-instance should override this method to tell Class::MOP if it's +possible to inline the slot access. + +This is currently only used by Class::MOP::Class::Immutable when performing +optimizations. + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B =back -=head1 AUTHOR +=head1 AUTHORS + +Yuval Kogman Enothingmuch@woobling.comE Stevan Little Estevan@iinteractive.comE =head1 COPYRIGHT AND LICENSE -Copyright 2006 by Infinity Interactive, Inc. +Copyright 2006-2008 by Infinity Interactive, Inc. L This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. +it under the same terms as Perl itself. =cut +