0.19
* Moose::Util::TypeConstraints
- - type now supports messages as well
+ - 'type' now supports messages as well
thanks to phaylon for finding this
- added tests for this
- - added list_all_type_constraints and
- list_all_builtin_type_constraints
+ - added &list_all_type_constraints and
+ &list_all_builtin_type_constraints
functions to facilitate introspection.
* Moose::Meta::Attribute
things like &new) thanks to ashleyb
for finding this
- added tests and docs for this
- - added the "documentation" attributes
+ - added the 'documentation' attributes
so that you can actually document your
attributes and inspect them through the
meta-object.
- added tests and docs for this
+ * Moose::Meta::Class
+ - when loading custom attribute metaclasses
+ it will first look in for the class in the
+ Moose::Meta::Attribute::Custom::$name, and
+ then default to just loading $name.
+ - added tests and docs for this
+
* Moose::Meta::TypeConstraint
- type constraints now stringify to their names.
- added test for this
This tells the accessor whether to automatically dereference the value returned.
This is only legal if your C<isa> option is either an C<ArrayRef> or C<HashRef>.
+=item I<metaclass =E<gt> $metaclass_name>
+
+This tells the class to use a custom attribute metaclass for this particular
+attribute. Custom attribute metaclasses are useful for extending the capabilities
+of the I<has> keyword, they are the simplest way to extend the MOP, but they are
+still a fairly advanced topic and too much to cover here. I will try and write a
+recipe on it soon.
+
+The default behavior here is to just load C<$metaclass_name>, however, we also
+have a way to alias to a shorter name. This will first look to see if
+B<Moose::Meta::Attribute::Custom::$metaclass_name> exists, if it does it will
+then check to see if that has the method C<register_implemenetation> which
+should return the actual name of the custom attribute metaclass. If there is
+no C<register_implemenetation> method, it will just default to using
+B<Moose::Meta::Attribute::Custom::$metaclass_name> as the metaclass name.
+
=item I<trigger =E<gt> $code>
The trigger option is a CODE reference which will be called after the value of
use Carp 'confess';
use Scalar::Util 'weaken', 'blessed', 'reftype';
-our $VERSION = '0.11';
+our $VERSION = '0.12';
our $AUTHORITY = 'cpan:STEVAN';
use Moose::Meta::Method::Overriden;
}
else {
if ($options{metaclass}) {
- Class::MOP::load_class($options{metaclass});
- $self->add_attribute($options{metaclass}->new($name, %options));
+ my $metaclass_name = $options{metaclass};
+ eval {
+ my $possible_full_name = 'Moose::Meta::Attribute::Custom::' . $metaclass_name;
+ Class::MOP::load_class($possible_full_name);
+ $metaclass_name = $possible_full_name->can('register_implementation')
+ ? $possible_full_name->register_implementation
+ : $possible_full_name;
+ };
+ if ($@) {
+ Class::MOP::load_class($metaclass_name);
+ }
+ $self->add_attribute($metaclass_name->new($name, %options));
}
else {
$self->add_attribute($name, %options);
use strict;
use warnings;
-use Test::More tests => 11;
+use Test::More tests => 17;
use Test::Exception;
BEGIN {
has 'foo' => (metaclass => 'Foo::Meta::Attribute');
}
+{
+ my $foo = Foo->new;
+ isa_ok($foo, 'Foo');
-my $foo = Foo->new;
-isa_ok($foo, 'Foo');
-
-my $foo_attr = Foo->meta->get_attribute('foo');
-isa_ok($foo_attr, 'Foo::Meta::Attribute');
-isa_ok($foo_attr, 'Moose::Meta::Attribute');
-
-is($foo_attr->name, 'foo', '... got the right name for our meta-attribute');
-ok($foo_attr->has_accessor, '... our meta-attrubute created the accessor for us');
+ my $foo_attr = Foo->meta->get_attribute('foo');
+ isa_ok($foo_attr, 'Foo::Meta::Attribute');
+ isa_ok($foo_attr, 'Moose::Meta::Attribute');
-ok($foo_attr->has_type_constraint, '... our meta-attrubute created the type_constraint for us');
+ is($foo_attr->name, 'foo', '... got the right name for our meta-attribute');
+ ok($foo_attr->has_accessor, '... our meta-attrubute created the accessor for us');
-my $foo_attr_type_constraint = $foo_attr->type_constraint;
-isa_ok($foo_attr_type_constraint, 'Moose::Meta::TypeConstraint');
+ ok($foo_attr->has_type_constraint, '... our meta-attrubute created the type_constraint for us');
-is($foo_attr_type_constraint->name, 'Foo', '... got the right type constraint name');
-is($foo_attr_type_constraint->parent->name, 'Object', '... got the right type constraint parent name');
+ my $foo_attr_type_constraint = $foo_attr->type_constraint;
+ isa_ok($foo_attr_type_constraint, 'Moose::Meta::TypeConstraint');
+ is($foo_attr_type_constraint->name, 'Foo', '... got the right type constraint name');
+ is($foo_attr_type_constraint->parent->name, 'Object', '... got the right type constraint parent name');
+}
{
package Bar::Meta::Attribute;
use Moose;
} '... the attribute metaclass need not be a Moose::Meta::Attribute as long as it behaves';
}
+{
+ package Moose::Meta::Attribute::Custom::Foo;
+ sub register_implementation { 'Foo::Meta::Attribute' }
+
+ package Moose::Meta::Attribute::Custom::Bar;
+ use Moose;
+
+ extends 'Moose::Meta::Attribute';
+
+ package Another::Foo;
+ use Moose;
+
+ ::lives_ok {
+ has 'foo' => (metaclass => 'Foo');
+ } '... the attribute metaclass alias worked correctly';
+
+ ::lives_ok {
+ has 'bar' => (metaclass => 'Bar');
+ } '... the attribute metaclass alias worked correctly';
+}
+
+{
+ my $foo_attr = Another::Foo->meta->get_attribute('foo');
+ isa_ok($foo_attr, 'Foo::Meta::Attribute');
+ isa_ok($foo_attr, 'Moose::Meta::Attribute');
+
+ my $bar_attr = Another::Foo->meta->get_attribute('bar');
+ isa_ok($bar_attr, 'Moose::Meta::Attribute::Custom::Bar');
+ isa_ok($bar_attr, 'Moose::Meta::Attribute');
+}
+
+