use Scalar::Util 'blessed', 'weaken', 'reftype';
use Carp 'confess';
-our $VERSION = '0.05';
+our $VERSION = '0.06';
use Moose::Util::TypeConstraints ();
# options which are not directly used
# but we store them for metadata purposes
-__PACKAGE__->meta->add_attribute('isa' => (
- reader => 'isa_metadata',
- predicate => 'has_isa_metadata',
-));
-__PACKAGE__->meta->add_attribute('does' => (
- reader => 'does_metadata',
- predicate => 'has_does_metadata',
-));
-__PACKAGE__->meta->add_attribute('is' => (
- reader => 'is_metadata',
- predicate => 'has_is_metadata',
-));
+__PACKAGE__->meta->add_attribute('isa' => (reader => '_isa_metadata'));
+__PACKAGE__->meta->add_attribute('does' => (reader => '_does_metadata'));
+__PACKAGE__->meta->add_attribute('is' => (reader => '_is_metadata'));
# these are actual options for the attrs
__PACKAGE__->meta->add_attribute('required' => (reader => 'is_required' ));
sub new {
my ($class, $name, %options) = @_;
$class->_process_options($name, \%options);
- my $self = $class->SUPER::new($name, %options);
- return $self;
+ return $class->SUPER::new($name, %options);
}
sub clone_and_inherit_options {
}
elsif ($options->{is} eq 'rw') {
$options->{accessor} = $name;
+ ((reftype($options->{trigger}) || '') eq 'CODE')
+ || confess "Trigger must be a CODE ref"
+ if exists $options->{trigger};
}
else {
confess "I do not understand this option (is => " . $options->{is} . ")"
}
}
- # process and check trigger here ...
-
-
if (exists $options->{isa}) {
if (exists $options->{does}) {
if ref $val && $self->is_weak_ref;
}
+## Accessor inline subroutines
+
sub _inline_check_constraint {
my ($self, $value) = @_;
return '' unless $self->has_type_constraint;
EOF
}
+sub _inline_check_coercion {
+ my $self = shift;
+ return '' unless $self->should_coerce;
+ return 'my $val = $attr->type_constraint->coercion->coerce($_[1]);'
+}
+
+sub _inline_check_required {
+ my $self = shift;
+ return '' unless $self->is_required;
+ return 'defined($_[1]) || confess "Attribute ($attr_name) is required, so cannot be set to undef";'
+}
+
+sub _inline_check_lazy {
+ my $self = shift;
+ return '' unless $self->is_lazy;
+ return '$_[0]->{$attr_name} = ($attr->has_default ? $attr->default($_[0]) : undef)'
+ . 'unless exists $_[0]->{$attr_name};';
+}
+
+
sub _inline_store {
my ($self, $instance, $value) = @_;
my $inv = '$_[0]';
my $code = 'sub { '
. 'if (scalar(@_) == 2) {'
- . ($attr->is_required ?
- 'defined($_[1]) || confess "Attribute ($attr_name) is required, so cannot be set to undef";'
- : '')
- . ($attr->should_coerce ?
- 'my $val = $attr->type_constraint->coercion->coerce($_[1]);'
- : '')
+ . $attr->_inline_check_required
+ . $attr->_inline_check_coercion
. $attr->_inline_check_constraint($value_name)
. $attr->_inline_store($inv, $value_name)
. $attr->_inline_trigger($inv, $value_name)
. ' }'
- . ($attr->is_lazy ?
- '$_[0]->{$attr_name} = ($attr->has_default ? $attr->default($_[0]) : undef)'
- . 'unless exists $_[0]->{$attr_name};'
- : '')
+ . $attr->_inline_check_lazy
. 'return ' . $attr->_inline_auto_deref($attr->_inline_get($inv))
. ' }';
my $sub = eval $code;
- warn "Could not create accessor for '$attr_name' because $@ \n code: $code" if $@;
confess "Could not create accessor for '$attr_name' because $@ \n code: $code" if $@;
return $sub;
}
my $value_name = $attr->should_coerce ? '$val' : '$_[1]';
my $inv = '$_[0]';
my $code = 'sub { '
- . ($attr->is_required ?
- 'defined($_[1]) || confess "Attribute ($attr_name) is required, so cannot be set to undef";'
- : '')
- . ($attr->should_coerce ?
- 'my $val = $attr->type_constraint->coercion->coerce($_[1]);'
- : '')
+ . $attr->_inline_check_required
+ . $attr->_inline_check_coercion
. $attr->_inline_check_constraint($value_name)
. $attr->_inline_store($inv, $value_name)
. $attr->_inline_trigger($inv, $value_name)
}
sub generate_reader_method {
- my $self = shift;
- my $attr_name = $self->slots;
+ my $attr = shift;
+ my $attr_name = $attr->slots;
my $code = 'sub {'
. 'confess "Cannot assign a value to a read-only accessor" if @_ > 1;'
- . ($self->is_lazy ?
- '$_[0]->{$attr_name} = ($self->has_default ? $self->default($_[0]) : undef)'
- . 'unless exists $_[0]->{$attr_name};'
- : '')
- . 'return ' . $self->_inline_auto_deref( '$_[0]->{$attr_name}' ) . ';'
+ . $attr->_inline_check_lazy
+ . 'return ' . $attr->_inline_auto_deref( '$_[0]->{$attr_name}' ) . ';'
. '}';
my $sub = eval $code;
confess "Could not create reader for '$attr_name' because $@ \n code: $code" if $@;
return;
}
+# private methods to help delegation ...
+
sub _canonicalize_handles {
my $self = shift;
my $handles = $self->handles;
sub _find_delegate_metaclass {
my $self = shift;
- if ($self->has_isa_metadata) {
- my $class = $self->isa_metadata;
+ if (my $class = $self->_isa_metadata) {
# if the class does have
# a meta method, use it
return $class->meta if $class->can('meta');
# our own metaclass
return Moose::Meta::Class->initialize($class);
}
- elsif ($self->has_does_metadata) {
+ elsif (my $role = $self->_does_metadata) {
# our role will always have
# a meta method
- return $self->does_metadata->meta;
+ return $role->meta;
}
else {
confess "Cannot find delegate metaclass for attribute " . $self->name;
=item B<new>
-=item B<clone_and_inherit_options>
-
=item B<initialize_instance_slot>
=item B<generate_accessor_method>
=over 4
+=item B<clone_and_inherit_options>
+
+This is to support the C<has '+foo'> feature, it clones an attribute
+from a superclass and allows a very specific set of changes to be made
+to the attribute.
+
=item B<has_type_constraint>
Returns true if this meta-attribute has a type constraint.
Stevan Little E<lt>stevan@iinteractive.comE<gt>
+Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
+
=head1 COPYRIGHT AND LICENSE
Copyright 2006 by Infinity Interactive, Inc.