$options{type_constraint} = $constraint;
}
}
+ if (exists $options{coerce} && $options{coerce} && $options{isa}) {
+ my $coercion = Moose::Util::TypeConstraints::find_type_coercion($options{isa});
+ (defined $coercion)
+ || confess "Cannot find coercion for type " . $options{isa};
+ $options{coerce} = $coercion;
+ }
$meta->add_attribute($name, %options)
});
use base 'Class::MOP::Attribute';
Moose::Meta::Attribute->meta->add_attribute(
+ Class::MOP::Attribute->new('coerce' => (
+ reader => 'coerce',
+ predicate => 'has_coercion'
+ ))
+);
+
+Moose::Meta::Attribute->meta->add_attribute(
Class::MOP::Attribute->new('weak_ref' => (
reader => 'weak_ref',
predicate => {
Moose::Meta::Attribute->meta->add_before_method_modifier('new' => sub {
my (undef, undef, %options) = @_;
+ if (exists $options{coerce} && $options{coerce}) {
+ (exists $options{type_constraint})
+ || confess "You cannot have coercion without specifying a type constraint";
+ confess "You cannot have a weak reference to a coerced value"
+ if $options{weak_ref};
+ }
(reftype($options{type_constraint}) && reftype($options{type_constraint}) eq 'CODE')
|| confess "Type cosntraint parameter must be a code-ref, not " . $options{type_constraint}
if exists $options{type_constraint};
};
}
else {
- return sub {
- if (scalar(@_) == 2) {
- (defined $self->type_constraint->($_[1]))
- || confess "Attribute ($attr_name) does not pass the type contraint with '$_[1]'"
- if defined $_[1];
- $_[0]->{$attr_name} = $_[1];
- }
- $_[0]->{$attr_name};
- };
+ if ($self->has_coercion) {
+ return sub {
+ if (scalar(@_) == 2) {
+ my $val = $self->coerce->($_[1]);
+ (defined $self->type_constraint->($val))
+ || confess "Attribute ($attr_name) does not pass the type contraint with '$val'"
+ if defined $val;
+ $_[0]->{$attr_name} = $val;
+ }
+ $_[0]->{$attr_name};
+ };
+ }
+ else {
+ return sub {
+ if (scalar(@_) == 2) {
+ (defined $self->type_constraint->($_[1]))
+ || confess "Attribute ($attr_name) does not pass the type contraint with '$_[1]'"
+ if defined $_[1];
+ $_[0]->{$attr_name} = $_[1];
+ }
+ $_[0]->{$attr_name};
+ };
+ }
}
}
else {
=item B<weak_ref>
+=item B<coerce>
+
+=item B<has_coercion>
+
=back
=head1 BUGS
my $pkg = shift || caller();
return if $pkg eq ':no_export';
no strict 'refs';
- foreach my $export (qw(type subtype coerce as where to)) {
+ foreach my $export (qw(type subtype as where to coerce)) {
*{"${pkg}::${export}"} = \&{"${export}"};
}
}
$TYPES{$type_name} = $type_constraint;
}
+ sub dump_type_constraints {
+ require Data::Dumper;
+ $Data::Dumper::Deparse = 1;
+ Data::Dumper::Dumper(\%TYPES);
+ }
+
sub export_type_contstraints_as_functions {
my $pkg = caller();
no strict 'refs';
}
}
-sub coerce {
+sub coerce ($@) {
my ($type_name, @coercion_map) = @_;
+ #use Data::Dumper;
+ #warn Dumper \@coercion_map;
my @coercions;
while (@coercion_map) {
my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
=item B<export_type_contstraints_as_functions>
+=item B<dump_type_constraints>
+
=back
=head2 Type Constraint Constructors
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 10;
+use Test::Exception;
+
+use Scalar::Util 'isweak';
+
+BEGIN {
+ use_ok('Moose');
+}
+
+{
+ package HTTPHeader;
+ use strict;
+ use warnings;
+ use Moose;
+
+ has 'array' => (is => 'ro');
+ has 'hash' => (is => 'ro');
+
+ package Engine;
+ use strict;
+ use warnings;
+ use Moose;
+
+ coerce 'HTTPHeader'
+ => as ArrayRef
+ => to { HTTPHeader->new(array => $_[0]) }
+ => as HashRef
+ => to { HTTPHeader->new(hash => $_[0]) };
+
+ has 'header' => (is => 'rw', isa => 'HTTPHeader', coerce => 1);
+}
+
+my $engine = Engine->new();
+isa_ok($engine, 'Engine');
+
+# try with arrays
+
+$engine->header([ 1, 2, 3 ]);
+isa_ok($engine->header, 'HTTPHeader');
+
+is_deeply(
+ $engine->header->array,
+ [ 1, 2, 3 ],
+ '... got the right array value of the header');
+ok(!defined($engine->header->hash), '... no hash value set');
+
+# try with hash
+
+$engine->header({ one => 1, two => 2, three => 3 });
+isa_ok($engine->header, 'HTTPHeader');
+
+is_deeply(
+ $engine->header->hash,
+ { one => 1, two => 2, three => 3 },
+ '... got the right hash value of the header');
+ok(!defined($engine->header->array), '... no array value set');
+
+dies_ok {
+ $engine->header("Foo");
+} '... dies with the wrong type, even after coercion';
+
+lives_ok {
+ $engine->header(HTTPHeader->new);
+} '... lives with the right type, even after coercion';
+
+
+
+
use_ok('Moose::Util::TypeConstraints', (':no_export'));
}
+#diag Moose::Util::TypeConstraints::dump_type_constraints();
\ No newline at end of file