sub initialize {
(shift)->SUPER::initialize(@_,
# use the custom attribute metaclass here
- ':attribute_metaclass' => 'ClassEncapsulatedAttributes::Attribute'
+ ':attribute_metaclass' => 'ClassEncapsulatedAttributes::Attribute',
);
}
sub construct_instance {
my ($class, %params) = @_;
- my $meta_instance = Class::MOP::Instance->new($class);
+
+ my $instance = $class->get_meta_instance->create_instance();
+
+ # initialize *ALL* attributes, including masked ones (as opposed to applicable)
foreach my $current_class ($class->class_precedence_list()) {
- $meta_instance->add_slot($current_class => {})
- unless $meta_instance->has_slot($current_class);
my $meta = $current_class->meta;
foreach my $attr_name ($meta->get_attribute_list()) {
my $attr = $meta->get_attribute($attr_name);
- $attr->initialize_instance_slot($meta, $meta_instance, \%params);
+ $attr->initialize_instance_slot($instance, \%params);
}
}
- return $meta_instance->get_instance;
+
+ return $instance;
}
package # hide the package from PAUSE
use base 'Class::MOP::Attribute';
+# alter the way parameters are specified
sub initialize_instance_slot {
- my ($self, $class, $meta_instance, $params) = @_;
+ my ($self, $instance, $params) = @_;
# if the attr has an init_arg, use that, otherwise,
# use the attributes name itself as the init_arg
my $init_arg = $self->init_arg();
# try to fetch the init arg from the %params ...
- my $val;
+ my $class = $self->associated_class;
+ my $val;
$val = $params->{$class->name}->{$init_arg}
if exists $params->{$class->name} &&
exists ${$params->{$class->name}}{$init_arg};
# if nothing was in the %params, we can use the
# attribute's default value (if it has one)
if (!defined $val && $self->has_default) {
- $val = $self->default($meta_instance->get_instance);
+ $val = $self->default($instance);
}
- # now add this to the instance structure
- $meta_instance->get_slot_value(
- $meta_instance->get_instance,
- $class->name
- )->{$self->name} = $val;
-}
-sub generate_accessor_method {
- my ($self, $attr_name) = @_;
- my $class_name = $self->associated_class->name;
- eval qq{sub {
- \$_[0]->{'$class_name'}->{'$attr_name'} = \$_[1] if scalar(\@_) == 2;
- \$_[0]->{'$class_name'}->{'$attr_name'};
- }};
-}
-
-sub generate_reader_method {
- my ($self, $attr_name) = @_;
- my $class_name = $self->associated_class->name;
- eval qq{sub {
- Carp::confess "Cannot assign a value to a read-only accessor" if \@_ > 1;
- \$_[0]->{'$class_name'}->{'$attr_name'};
- }};
-}
-
-sub generate_writer_method {
- my ($self, $attr_name) = @_;
- my $class_name = $self->associated_class->name;
- eval qq{sub {
- \$_[0]->{'$class_name'}->{'$attr_name'} = \$_[1];
- }};
+ # now add this to the instance structure
+ my $meta_instance = $self->associated_class->get_meta_instance;
+ $meta_instance->set_slot_value_with_init( $instance, $self->slot_name, $val );
}
-sub generate_predicate_method {
- my ($self, $attr_name) = @_;
- my $class_name = $self->associated_class->name;
- eval qq{sub {
- defined \$_[0]->{'$class_name'}->{'$attr_name'} ? 1 : 0;
- }};
+# mangle the slot name to include the fully qualified attr
+sub slot_name {
+ my $self = shift;
+ $self->associated_class->name . "::" . $self->SUPER::slot_name;
}
-## &remove_attribute is left as an exercise for the reader :)
-
1;
__END__
package # hide the package from PAUSE
- InsideOutClass::Attribute;
+ InsideOutClass::Instance;
use strict;
use warnings;
use Carp 'confess';
use Scalar::Util 'refaddr';
-use base 'Class::MOP::Attribute';
-
-sub initialize_instance_slot {
- my ($self, $class, $meta_instance, $params) = @_;
- # if the attr has an init_arg, use that, otherwise,
- # use the attributes name itself as the init_arg
- my $init_arg = $self->init_arg();
- # try to fetch the init arg from the %params ...
- my $val;
- $val = $params->{$init_arg} if exists $params->{$init_arg};
- # if nothing was in the %params, we can use the
- # attribute's default value (if it has one)
- if (!defined $val && $self->has_default) {
- $val = $self->default($meta_instance->get_instance);
- }
- # now add this to the instance structure
- $class->get_package_variable('%' . $self->name)->{ refaddr($meta_instance->get_instance) } = $val;
+use base 'Class::MOP::Instance';
+
+sub create_instance {
+ my ( $self, $class ) = @_;
+ my $x;
+ bless \$x, $class || $self->{meta}->name;
}
-sub generate_accessor_method {
- my ($self, $attr_name) = @_;
- $attr_name = ($self->associated_class->name . '::' . $attr_name);
- eval 'sub {
- $' . $attr_name . '{ refaddr($_[0]) } = $_[1] if scalar(@_) == 2;
- $' . $attr_name . '{ refaddr($_[0]) };
- }';
+sub add_slot {
+ my ( $self, $slot_name ) = @_;
+ $self->{containers}{$slot_name} = do {
+ my $fqn = $self->{meta}->name . "::" . $slot_name;
+ no strict 'refs';
+ \%$fqn;
+ };
+ $self->SUPER::add_slot( $slot_name );
}
-sub generate_reader_method {
- my ($self, $attr_name) = @_;
- eval 'sub {
- confess "Cannot assign a value to a read-only accessor" if @_ > 1;
- $' . ($self->associated_class->name . '::' . $attr_name) . '{ refaddr($_[0]) };
- }';
+sub get_slot_value {
+ my ( $self, $instance, $slot_name ) = @_;
+ confess "$self is no instance" unless ref $self;
+ $self->{containers}{$slot_name}{refaddr $instance};
}
-sub generate_writer_method {
- my ($self, $attr_name) = @_;
- eval 'sub {
- $' . ($self->associated_class->name . '::' . $attr_name) . '{ refaddr($_[0]) } = $_[1];
- }';
+sub set_slot_value {
+ my ( $self, $instance, $slot_name, $value ) = @_;
+ $self->{containers}{$slot_name}{refaddr $instance} = $value;
}
-sub generate_predicate_method {
- my ($self, $attr_name) = @_;
- eval 'sub {
- defined($' . ($self->associated_class->name . '::' . $attr_name) . '{ refaddr($_[0]) }) ? 1 : 0;
- }';
+sub initialize_slot { }
+
+sub slot_initialized {
+ my ( $self, $instance, $slot_name ) = @_;
+ exists $self->{containers}{$slot_name}{refaddr $instance};
}
-## &remove_attribute is left as an exercise for the reader :)
+## &remove_slot is left as an exercise for the reader :)
1;
# tell our metaclass to use the
# InsideOut attribute metclass
# to construct all it's attributes
- ':attribute_metaclass' => 'InsideOutClass::Attribute'
+ ':instance_metaclass' => 'InsideOutClass::Instance'
);
__PACKAGE__->meta->add_attribute('foo' => (
class technique. What follows is a brief explaination of the code
found in this module.
-We must create a subclass of B<Class::MOP::Attribute> and override
-the instance initialization and method generation code. This requires
-overloading C<initialize_instance_slot>, C<generate_accessor_method>,
-C<generate_reader_method>, C<generate_writer_method> and
-C<generate_predicate_method>. All other aspects are taken care of with
-the existing B<Class::MOP::Attribute> infastructure.
+We must create a subclass of B<Class::MOP::Instance> and override
+the slot operations. This requires
+overloading C<get_slot_value>, C<set_slot_value>, C<slot_initialized>, and
+C<initialize_slot>, as well as their inline counterparts. Additionally we
+overload C<add_slot> in order to initialize the global hash containing the
+actual slot values.
And that is pretty much all. Of course I am ignoring need for
inside-out objects to be C<DESTROY>-ed, and some other details as
-well, but this is an example. A real implementation is left as an
-exercise to the reader.
+well (threading, etc), but this is an example. A real implementation is left as
+an exercise to the reader.
=head1 AUTHOR
Stevan Little E<lt>stevan@iinteractive.comE<gt>
+=head1 SEE ALSO
+
+L<Tie::RefHash::Weak>
+
=head1 COPYRIGHT AND LICENSE
Copyright 2006 by Infinity Interactive, Inc.
use base 'Class::MOP::Attribute';
sub initialize_instance_slot {
- my ($self, $class, $meta_instance, $params) = @_;
+ my ($self, $instance, $params) = @_;
+
# if the attr has an init_arg, use that, otherwise,
# use the attributes name itself as the init_arg
my $init_arg = $self->init_arg();
- # try to fetch the init arg from the %params ...
- my $val;
- $val = $params->{$init_arg} if exists $params->{$init_arg};
- # now add this to the instance structure
- # only if we have found a value at all
- $meta_instance->add_slot($self->name, $val) if defined $val;
-}
+ if ( exists $params->{$init_arg} ) {
+ my $val = $params->{$init_arg};
+ my $meta_instance = $self->associated_class->get_meta_instance;
+ $meta_instance->set_slot_value_with_init( $instance, $self->slot_name, $val);
+ }
+}
sub generate_accessor_method {
- my ($self, $attr_name) = @_;
+ my $attr = shift;
+
+ my $slot_name = $attr->slot_name;
+ my $meta_instance = $attr->associated_class->get_meta_instance;
+
sub {
if (scalar(@_) == 2) {
- $_[0]->{$attr_name} = $_[1];
+ $meta_instance->set_slot_value_with_init( $_[0], $slot_name, $_[1] );
}
else {
- if (!exists $_[0]->{$attr_name}) {
- my $attr = $self->associated_class->get_attribute($attr_name);
- $_[0]->{$attr_name} = $attr->has_default ? $attr->default($_[0]) : undef;
- }
- $_[0]->{$attr_name};
+ unless ( $meta_instance->slot_initialized( $_[0], $slot_name ) ) {
+ my $value = $attr->has_default ? $attr->default($_[0]) : undef;
+ $meta_instance->set_slot_value_with_init( $_[0], $slot_name, $value );
+ }
+
+ $meta_instance->get_slot_value( $_[0], $slot_name );
}
};
}
sub generate_reader_method {
- my ($self, $attr_name) = @_;
+ my $attr = shift;
+
+ my $slot_name = $attr->slot_name;
+ my $meta_instance = $attr->associated_class->get_meta_instance;
+
sub {
confess "Cannot assign a value to a read-only accessor" if @_ > 1;
- if (!exists $_[0]->{$attr_name}) {
- my $attr = $self->associated_class->get_attribute($attr_name);
- $_[0]->{$attr_name} = $attr->has_default ? $attr->default($_[0]) : undef;
- }
- $_[0]->{$attr_name};
+
+ unless ( $meta_instance->slot_initialized( $_[0], $slot_name ) ) {
+ my $value = $attr->has_default ? $attr->default($_[0]) : undef;
+ $meta_instance->set_slot_value_with_init( $_[0], $slot_name, $value );
+ }
+
+ $meta_instance->get_slot_value( $_[0], $slot_name );
};
}
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
-=cut
\ No newline at end of file
+=cut
}
sub initialize_instance_slot {
- my ($self, $class, $meta_instance, $params) = @_;
+ my ($self, $instance, $params) = @_;
my $init_arg = $self->{init_arg};
# try to fetch the init arg from the %params ...
my $val;
# if nothing was in the %params, we can use the
# attribute's default value (if it has one)
if (!defined $val && defined $self->{default}) {
- $val = $self->default($meta_instance->get_instance);
- }
- $meta_instance->add_slot($self->name, $val);
+ $val = $self->default($instance);
+ }
+
+ my $meta_instance = $self->associated_class->get_meta_instance;
+ $meta_instance->set_slot_value_with_init( $instance, $self->slot_name, $val );
}
# NOTE:
$self->{associated_class} = undef;
}
+# slot management
+
+sub slot_name { # when attr <-> slot mapping is 1:1
+ my $self = shift;
+ $self->name;
+}
+
+# slot alocation
+
+sub allocate_slots {
+ my $self = shift;
+ my $meta_instance = $self->associated_class->get_meta_instance;
+ $meta_instance->add_slot( $self->slot_name );
+}
+
+sub deallocate_slots {
+ my $self = shift;
+ my $meta_instance = $self->associated_class->get_meta_instance;
+ $meta_instance->remove_slot( $self->slot_name );
+}
+
## Method generation helpers
sub generate_accessor_method {
my ($self, $attr_name) = @_;
- my $meta_instance = $self->associated_class->instance_metaclass;
+ my $meta_instance = $self->associated_class->get_meta_instance;
+ my $slot_name = $self->slot_name;
+
sub {
- $meta_instance->set_slot_value($_[0], $attr_name, $_[1]) if scalar(@_) == 2;
- $meta_instance->get_slot_value($_[0], $attr_name);
+ $meta_instance->set_slot_value($_[0], $slot_name, $_[1]) if scalar(@_) == 2;
+ $meta_instance->get_slot_value($_[0], $slot_name);
};
}
sub generate_reader_method {
my ($self, $attr_name) = @_;
- my $meta_instance = $self->associated_class->instance_metaclass;
+ my $meta_instance = $self->associated_class->get_meta_instance;
+ my $slot_name = $self->slot_name;
sub {
confess "Cannot assign a value to a read-only accessor" if @_ > 1;
- $meta_instance->get_slot_value($_[0], $attr_name);
+ $meta_instance->get_slot_value($_[0], $slot_name);
};
}
sub generate_writer_method {
my ($self, $attr_name) = @_;
- my $meta_instance = $self->associated_class->instance_metaclass;
+ my $meta_instance = $self->associated_class->get_meta_instance;
+ my $slot_name = $self->slot_name;
sub {
- $meta_instance->set_slot_value($_[0], $attr_name, $_[1]);
+ $meta_instance->set_slot_value($_[0], $slot_name, $_[1]);
};
}
sub generate_predicate_method {
my ($self, $attr_name) = @_;
- my $meta_instance = $self->associated_class->instance_metaclass;
+ my $meta_instance = $self->associated_class->get_meta_instance;
+ my $slot_name = $self->slot_name;
sub {
- $meta_instance->has_slot_value($_[0], $attr_name);
+ defined $meta_instance->get_slot_value($_[0], $slot_name);
};
}
=item B<detach_from_class>
+=item B<slot_name>
+
+=item B<allocate_slots>
+
+=item B<deallocate_slots>
+
=back
=head2 Attribute Accessor generation
my $package_name = $options{':package'};
(defined $package_name && $package_name)
|| confess "You must pass a package name";
- # NOTE:
- # return the metaclass if we have it cached,
- # and it is still defined (it has not been
- # reaped by DESTROY yet, which can happen
- # annoyingly enough during global destruction)
+ # NOTE:
+ # return the metaclass if we have it cached,
+ # and it is still defined (it has not been
+ # reaped by DESTROY yet, which can happen
+ # annoyingly enough during global destruction)
return $METAS{$package_name}
- if exists $METAS{$package_name} && defined $METAS{$package_name};
+ if exists $METAS{$package_name} && defined $METAS{$package_name};
$class = blessed($class) || $class;
# now create the metaclass
my $meta;
sub construct_instance {
my ($class, %params) = @_;
- my $meta_instance = $class->instance_metaclass->new($class);
+
+ my $instance = $class->get_meta_instance->create_instance();
+
foreach my $attr ($class->compute_all_applicable_attributes()) {
- $attr->initialize_instance_slot($class, $meta_instance, \%params);
+ $attr->initialize_instance_slot($instance, \%params);
}
- return $meta_instance->get_instance;
+ return $instance;
+}
+
+sub get_meta_instance {
+ my $class = shift;
+ # make it work,.. *then* make it right ... # yeah that was my plan, i just thought we'll make it async
+ $class->{meta_instance} ||= $class->instance_metaclass->new( $class );
}
sub clone_object {
|| confess "Your code block must be a CODE reference";
my $full_method_name = ($self->name . '::' . $method_name);
- $method = $self->method_metaclass->wrap($method) unless blessed($method);
-
+ $method = $self->method_metaclass->wrap($method) unless blessed($method);
+
no strict 'refs';
no warnings 'redefine';
*{$full_method_name} = subname $full_method_name => $method;
}
{
- my $fetch_and_prepare_method = sub {
- my ($self, $method_name) = @_;
- # fetch it locally
- my $method = $self->get_method($method_name);
- # if we dont have local ...
- unless ($method) {
- # make sure this method even exists ...
- ($self->find_next_method_by_name($method_name))
- || confess "The method '$method_name' is not found in the inherience hierarchy for this class";
- # if so, then create a local which just
- # calls the next applicable method ...
- $self->add_method($method_name => sub {
- $self->find_next_method_by_name($method_name)->(@_);
- });
- $method = $self->get_method($method_name);
- }
-
- # now make sure we wrap it properly
- # (if it isnt already)
- unless ($method->isa('Class::MOP::Method::Wrapped')) {
- $method = Class::MOP::Method::Wrapped->wrap($method);
- $self->add_method($method_name => $method);
- }
- return $method;
- };
-
- sub add_before_method_modifier {
- my ($self, $method_name, $method_modifier) = @_;
- (defined $method_name && $method_name)
- || confess "You must pass in a method name";
- my $method = $fetch_and_prepare_method->($self, $method_name);
- $method->add_before_modifier(subname ':before' => $method_modifier);
- }
-
- sub add_after_method_modifier {
- my ($self, $method_name, $method_modifier) = @_;
- (defined $method_name && $method_name)
- || confess "You must pass in a method name";
- my $method = $fetch_and_prepare_method->($self, $method_name);
- $method->add_after_modifier(subname ':after' => $method_modifier);
- }
-
- sub add_around_method_modifier {
- my ($self, $method_name, $method_modifier) = @_;
- (defined $method_name && $method_name)
- || confess "You must pass in a method name";
- my $method = $fetch_and_prepare_method->($self, $method_name);
- $method->add_around_modifier(subname ':around' => $method_modifier);
- }
+ my $fetch_and_prepare_method = sub {
+ my ($self, $method_name) = @_;
+ # fetch it locally
+ my $method = $self->get_method($method_name);
+ # if we dont have local ...
+ unless ($method) {
+ # make sure this method even exists ...
+ ($self->find_next_method_by_name($method_name))
+ || confess "The method '$method_name' is not found in the inherience hierarchy for this class";
+ # if so, then create a local which just
+ # calls the next applicable method ...
+ $self->add_method($method_name => sub {
+ $self->find_next_method_by_name($method_name)->(@_);
+ });
+ $method = $self->get_method($method_name);
+ }
+
+ # now make sure we wrap it properly
+ # (if it isnt already)
+ unless ($method->isa('Class::MOP::Method::Wrapped')) {
+ $method = Class::MOP::Method::Wrapped->wrap($method);
+ $self->add_method($method_name => $method);
+ }
+ return $method;
+ };
+
+ sub add_before_method_modifier {
+ my ($self, $method_name, $method_modifier) = @_;
+ (defined $method_name && $method_name)
+ || confess "You must pass in a method name";
+ my $method = $fetch_and_prepare_method->($self, $method_name);
+ $method->add_before_modifier(subname ':before' => $method_modifier);
+ }
+
+ sub add_after_method_modifier {
+ my ($self, $method_name, $method_modifier) = @_;
+ (defined $method_name && $method_name)
+ || confess "You must pass in a method name";
+ my $method = $fetch_and_prepare_method->($self, $method_name);
+ $method->add_after_modifier(subname ':after' => $method_modifier);
+ }
+
+ sub add_around_method_modifier {
+ my ($self, $method_name, $method_modifier) = @_;
+ (defined $method_name && $method_name)
+ || confess "You must pass in a method name";
+ my $method = $fetch_and_prepare_method->($self, $method_name);
+ $method->add_around_modifier(subname ':around' => $method_modifier);
+ }
# NOTE:
# the methods above used to be named like this:
|| confess "Your code block must be a CODE reference";
my $full_method_name = ($self->name . '::' . $method_name);
- $method = $self->method_metaclass->wrap($method) unless blessed($method);
+ $method = $self->method_metaclass->wrap($method) unless blessed($method);
no strict 'refs';
no warnings 'redefine';
no strict 'refs';
return 0 if !defined(&{$sub_name});
- my $method = \&{$sub_name};
+ my $method = \&{$sub_name};
return 0 if (svref_2object($method)->GV->STASH->NAME || '') ne $self->name &&
- (svref_2object($method)->GV->NAME || '') ne '__ANON__';
-
- # at this point we are relatively sure
- # it is our method, so we bless/wrap it
- $self->method_metaclass->wrap($method) unless blessed($method);
+ (svref_2object($method)->GV->NAME || '') ne '__ANON__';
+
+ # at this point we are relatively sure
+ # it is our method, so we bless/wrap it
+ $self->method_metaclass->wrap($method) unless blessed($method);
return 1;
}
(defined $method_name && $method_name)
|| confess "You must define a method name";
- return unless $self->has_method($method_name);
+ return unless $self->has_method($method_name);
no strict 'refs';
return \&{$self->name . '::' . $method_name};
sub find_next_method_by_name {
my ($self, $method_name) = @_;
(defined $method_name && $method_name)
- || confess "You must define a method name to find";
+ || confess "You must define a method name to find";
# keep a record of what we have seen
# here, this will handle all the
# inheritence issues because we are
# using the &class_precedence_list
my %seen_class;
- my @cpl = $self->class_precedence_list();
- shift @cpl; # discard ourselves
+ my @cpl = $self->class_precedence_list();
+ shift @cpl; # discard ourselves
foreach my $class (@cpl) {
next if $seen_class{$class};
$seen_class{$class}++;
# fetch the meta-class ...
my $meta = $self->initialize($class);
- return $meta->get_method($method_name)
- if $meta->has_method($method_name);
+ return $meta->get_method($method_name)
+ if $meta->has_method($method_name);
}
- return;
+ return;
}
## Attributes
($attribute->isa('Class::MOP::Attribute'))
|| confess "Your attribute must be an instance of Class::MOP::Attribute (or a subclass)";
$attribute->attach_to_class($self);
- $attribute->install_accessors();
+ $attribute->install_accessors();
+ $attribute->allocate_slots;
+
$self->get_attribute_map->{$attribute->name} = $attribute;
}
my $removed_attribute = $self->get_attribute_map->{$attribute_name};
return unless defined $removed_attribute;
delete $self->get_attribute_map->{$attribute_name};
- $removed_attribute->remove_accessors();
- $removed_attribute->detach_from_class();
+ $removed_attribute->remove_accessors();
+ $removed_attribute->deallocate_slots();
+ $removed_attribute->detach_from_class();
return $removed_attribute;
}
}
confess "Could not get the package variable ($variable) because : $e" if $e;
# if we didn't die, then we can return it
- return $ref;
+ return $ref;
}
sub remove_package_variable {
=item B<instance_metaclass>
+=item B<get_meta_instance>
+
=item B<new_object (%params)>
This is a convience method for creating a new object of the class, and
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
-=cut
\ No newline at end of file
+=cutchistian
\ No newline at end of file
}
sub new {
- my $class = shift;
- my $meta = shift;
+ my ( $class, $meta ) = @_;
bless {
- instance => (bless {} => $meta->name)
+ meta => $meta,
+ instance_layout => {}
} => $class;
}
+sub create_instance {
+ my ( $self, $class ) = @_;
+
+ # rely on autovivification
+ $self->bless_instance_structure( {}, $class );
+}
+
+sub bless_instance_structure {
+ my ( $self, $instance_structure, $class ) = @_;
+ $class ||= $self->{meta}->name;
+ bless $instance_structure, $class;
+}
+
+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;
+}
+
+# operations on meta instance
+
sub add_slot {
- my ($self, $slot_name, $value) = @_;
- return $self->{instance}->{$slot_name} = $value;
+ my ($self, $slot_name ) = @_;
+ confess "The slot '$slot_name' already exists"
+ if 0 && $self->has_slot_recursively( $slot_name );
+ $self->{instance_layout}->{$slot_name} = undef;
}
sub has_slot {
my ($self, $slot_name) = @_;
- exists $self->{instance}->{$slot_name} ? 1 : 0;
+ 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 );
+ delete $self->{instance_layout}->{$slot_name};
+}
+
+
+# operations on created instances
+
sub get_slot_value {
my ($self, $instance, $slot_name) = @_;
return $instance->{$slot_name};
}
+# can be called only after initialize_slot_value
sub set_slot_value {
my ($self, $instance, $slot_name, $value) = @_;
+ $slot_name or confess "must provide slot name";
$instance->{$slot_name} = $value;
}
-sub has_slot_value {
+# 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_slot {
+ my ( $self, $instance, $slot_name ) = @_;
+}
+
+sub slot_initialized {
my ($self, $instance, $slot_name) = @_;
- defined $instance->{$slot_name} ? 1 : 0;
+ exists $instance->{$slot_name} ? 1 : 0;
}
-sub get_instance { (shift)->{instance} }
+
+# inlinable operation snippets
+
+sub inline_get_slot_value {
+ 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 . " = $value",
+}
+
+sub inline_set_slot_value_with_init {
+ my ( $self, $instance, $slot_name, $value) = @_;
+ $self->inline_set_slot_value( $instance, $slot_name, $value ) . ";";
+}
+
+sub inline_initialize_slot {
+ return "";
+}
+
+sub inline_slot_initialized {
+ my ($self, $instance, $slot_name) = @_;
+ "exists " . $self->inline_get_slot_value;
+}
+
+sub _inline_slot_lvalue {
+ my ($self, $instance, $slot_name) = @_;
+ $self->inline_slot_value;
+}
1;
=item B<has_slot_value>
-=item B<get_instance>
-
=back
=head2 Introspection
use strict;
use warnings;
-use Test::More tests => 140;
+use Test::More tests => 142;
use Test::Exception;
BEGIN {
initialize create create_anon_class
- instance_metaclass
+ instance_metaclass get_meta_instance
new_object clone_object
construct_instance construct_class_instance clone_instance
check_metaclass_compatability
use strict;
use warnings;
-use Test::More tests => 40;
+use Test::More tests => 43;
use Test::Exception;
BEGIN {
process_accessors
install_accessors
remove_accessors
+
+ slot_name
+ allocate_slots
+ deallocate_slots
);
is_deeply(
# but that is getting a little excessive so I
# wont worry about it for now. Maybe if I get
# bored I will do it.
-}
\ No newline at end of file
+}
package Foo;
use metaclass 'Class::MOP::Class' => (
- ':attribute_metaclass' => 'InsideOutClass::Attribute'
+ ':instance_metaclass' => 'InsideOutClass::Instance'
);
Foo->meta->add_attribute('foo' => (