);
Class::MOP::Attribute->meta->add_attribute(
+ Class::MOP::Attribute->new('clearer' => (
+ reader => 'clearer',
+ predicate => 'has_clearer',
+ ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
Class::MOP::Attribute->new('init_arg' => (
reader => 'init_arg',
predicate => 'has_init_arg',
reader => $options{reader},
writer => $options{writer},
predicate => $options{predicate},
+ clearer => $options{clearer},
init_arg => $options{init_arg},
default => $options{default},
# keep a weakened link to the
sub has_reader { defined($_[0]->{reader}) ? 1 : 0 }
sub has_writer { defined($_[0]->{writer}) ? 1 : 0 }
sub has_predicate { defined($_[0]->{predicate}) ? 1 : 0 }
+sub has_clearer { defined($_[0]->{clearer}) ? 1 : 0 }
sub has_init_arg { defined($_[0]->{init_arg}) ? 1 : 0 }
sub has_default { defined($_[0]->{default}) ? 1 : 0 }
sub reader { $_[0]->{reader} }
sub writer { $_[0]->{writer} }
sub predicate { $_[0]->{predicate} }
+sub clearer { $_[0]->{clearer} }
sub init_arg { $_[0]->{init_arg} }
# end bootstrapped away method section.
};
}
+sub generate_clearer_method {
+ my $self = shift;
+ my $attr_name = $self->name;
+ return sub {
+ Class::MOP::Class->initialize(Scalar::Util::blessed($_[0]))
+ ->get_meta_instance
+ ->deinitialize_slot($_[0], $attr_name);
+ };
+}
+
sub generate_predicate_method_inline {
my $self = shift;
my $attr_name = $self->name;
my $code = eval 'sub {'
. 'defined ' . $meta_instance->inline_get_slot_value('$_[0]', "'$attr_name'") . ' ? 1 : 0'
. '}';
- confess "Could not generate inline accessor because : $@" if $@;
+ confess "Could not generate inline predicate because : $@" if $@;
+
+ return $code;
+}
+
+sub generate_clearer_method_inline {
+ my $self = shift;
+ my $attr_name = $self->name;
+ my $meta_instance = $self->associated_class->instance_metaclass;
+
+ my $code = eval 'sub {'
+ . $meta_instance->inline_deinitialize_slot('$_[0]', "'$attr_name'")
+ . '}';
+ confess "Could not generate inline clearer because : $@" if $@;
return $code;
}
my ($self, $type, $accessor, $generate_as_inline_methods) = @_;
if (reftype($accessor)) {
(reftype($accessor) eq 'HASH')
- || confess "bad accessor/reader/writer/predicate format, must be a HASH ref";
+ || confess "bad accessor/reader/writer/predicate/clearer format, must be a HASH ref";
my ($name, $method) = %{$accessor};
return ($name, Class::MOP::Attribute::Accessor->wrap($method));
}
$self->process_accessors('predicate' => $self->predicate(), $inline)
) if $self->has_predicate();
+ $class->add_method(
+ $self->process_accessors('clearer' => $self->clearer(), $inline)
+ ) if $self->has_clearer();
+
return;
}
$_remove_accessor->($self->reader(), $self->associated_class()) if $self->has_reader();
$_remove_accessor->($self->writer(), $self->associated_class()) if $self->has_writer();
$_remove_accessor->($self->predicate(), $self->associated_class()) if $self->has_predicate();
+ $_remove_accessor->($self->clearer(), $self->associated_class()) if $self->has_clearer();
return;
}
=back
-The I<accessor>, I<reader>, I<writer> and I<predicate> keys can
-contain either; the name of the method and an appropriate default
-one will be generated for you, B<or> a HASH ref containing exactly one
-key (which will be used as the name of the method) and one value,
-which should contain a CODE reference which will be installed as
-the method itself.
+The I<accessor>, I<reader>, I<writer>, I<predicate> and I<clearer> keys can
+contain either; the name of the method and an appropriate default one will be
+generated for you, B<or> a HASH ref containing exactly one key (which will be
+used as the name of the method) and one value, which should contain a CODE
+reference which will be installed as the method itself.
=over 4
C<undef>. It will return true (C<1>) if the attribute's value is
defined, and false (C<0>) otherwise.
+=item I<clearer>
+
+This is the a method that will uninitialize the attr, reverting lazy values
+back to their "unfulfilled" state.
+
=back
=item B<clone (%options)>
=item B<predicate>
+=item B<clearer>
+
=item B<init_arg>
=item B<is_default_a_coderef>
=item B<has_predicate>
+=item B<has_clearer>
+
=item B<has_init_arg>
=item B<has_default>
=item B<generate_predicate_method>
+=item B<generate_clearer_method>
+
=item B<generate_reader_method>
=item B<generate_writer_method>
=item B<generate_predicate_method_inline>
+=item B<generate_clearer_method_inline>
+
=item B<generate_reader_method_inline>
=item B<generate_writer_method_inline>
=item B<remove_accessors>
This allows the attribute to remove the method for it's own
-I<accessor/reader/writer/predicate>. This is called by
+I<accessor/reader/writer/predicate/clearer>. This is called by
C<Class::MOP::Class::remove_attribute>.
=back
=cut
+
$self->set_slot_value($instance, $slot_name, undef);
}
+sub deinitialize_slot {
+ my ( $self, $instance, $slot_name ) = @_;
+ delete $instance->{$slot_name};
+}
+
sub initialize_all_slots {
my ($self, $instance) = @_;
foreach my $slot_name ($self->get_all_slots) {
}
}
+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} ? 1 : 0;
$self->inline_set_slot_value($instance, $slot_name, 'undef'),
}
+sub inline_deinitialize_slot {
+ my ($self, $instance, $slot_name) = @_;
+ "delete " . $self->inline_slot_access($instance, $slot_name);
+}
sub inline_is_slot_initialized {
my ($self, $instance, $slot_name) = @_;
"exists " . $self->inline_slot_access($instance, $slot_name) . " ? 1 : 0";
=item B<initialize_slot ($instance_structure, $slot_name)>
+=item B<deinitialize_slot ($instance_structure, $slot_name)>
+
=item B<initialize_all_slots ($instance_structure)>
+=item B<deinitialize_all_slots ($instance_structure)>
+
=item B<is_slot_initialized ($instance_structure, $slot_name)>
=item B<weaken_slot_value ($instance_structure, $slot_name)>
=item B<inline_initialize_slot ($instance_structure, $slot_name)>
+=item B<inline_deinitialize_slot ($instance_structure, $slot_name)>
+
=item B<inline_is_slot_initialized ($instance_structure, $slot_name)>
=item B<inline_weaken_slot_value ($instance_structure, $slot_name)>
use strict;
use warnings;
-use Test::More tests => 48;
+use Test::More tests => 53;
use Test::Exception;
BEGIN {
has_writer writer
has_reader reader
has_predicate predicate
+ has_clearer clearer
has_init_arg init_arg
has_default default is_default_a_coderef
generate_reader_method
generate_writer_method
generate_predicate_method
+ generate_clearer_method
generate_accessor_method_inline
generate_reader_method_inline
generate_writer_method_inline
generate_predicate_method_inline
+ generate_clearer_method_inline
process_accessors
install_accessors
);
is_deeply(
- [ sort @methods ],
[ sort $meta->get_method_list ],
+ [ sort @methods ],
'... our method list matches');
foreach my $method_name (@methods) {
}
my @attributes = qw(
- name accessor reader writer predicate
+ name accessor reader writer predicate clearer
init_arg default associated_class
);
is_deeply(
- [ sort @attributes ],
[ sort $meta->get_attribute_list ],
+ [ sort @attributes ],
'... our attribute list matches');
foreach my $attribute_name (@attributes) {
use strict;
use warnings;
-use Test::More tests => 39;
+use Test::More tests => 47;
use Test::Exception;
use Scalar::Util qw/isweak reftype/;
get_all_slots
initialize_all_slots
+ deinitialize_all_slots
get_slot_value
set_slot_value
initialize_slot
+ deinitialize_slot
is_slot_initialized
weaken_slot_value
strengthen_slot_value
inline_get_slot_value
inline_set_slot_value
inline_initialize_slot
+ inline_deinitialize_slot
inline_is_slot_initialized
inline_weaken_slot_value
inline_strengthen_slot_value
is_deeply($i_foo, $i_foo_2, '... but the same structure');
}
+ok(!$mi_foo->is_slot_initialized( $i_foo, "moosen" ), "slot not initialized");
+
ok(!defined($mi_foo->get_slot_value( $i_foo, "moosen" )), "... no value for slot");
+$mi_foo->initialize_slot( $i_foo, "moosen" );
+
+ok($mi_foo->is_slot_initialized( $i_foo, "moosen" ), "slot initialized");
+
+ok(!defined($mi_foo->get_slot_value( $i_foo, "moosen" )), "... but no value for slot");
+
$mi_foo->set_slot_value( $i_foo, "moosen", "the value" );
is($mi_foo->get_slot_value( $i_foo, "moosen" ), "the value", "... get slot value");
is( reftype( $mi_foo->get_slot_value( $i_foo, "moosen" ) ), "ARRAY", "weak value can be strengthened" );
+$mi_foo->deinitialize_slot( $i_foo, "moosen" );
+
+ok(!$mi_foo->is_slot_initialized( $i_foo, "moosen" ), "slot deinitialized");
+
+ok(!defined($mi_foo->get_slot_value( $i_foo, "moosen" )), "... no value for slot");
+