inner/augment (mst)
- added tests for this (eilara)
+ * Moose::Meta::Attribute
+ Moose::Meta::Method::Constructor
+ Moose::Meta::Method::Accessor
+ - fixed issue with overload::Overloaded getting called
+ on non-blessed items.
+ - added tests for this
+
+ * Moose::Coookbook::Snacks
+ - these are bits of documentation, not quite as big as
+ Recipes but which have no clear place in the module docs.
+ So they are Snacks! (horray for castaway++)
+
+ +++ Major Refactor of the Type Constraint system +++
+ +++ with new features added as well +++
+
* Moose::Util::TypeConstraint
- no longer uses package variable to keep track of
the type constraints, now uses the an instance of
can track where the type constraints are created
* Moose::Meta::TypeConstraint::Union
- - this is not a subclass of Moose::Meta::TypeConstraint
- which is more correct
+ - this is now been refactored to be a subclass of
+ Moose::Meta::TypeConstraint
+
+ * Moose::Meta::TypeCoercion::Union
+ - this has been added to service the newly refactored
+ Moose::Meta::TypeConstraint::Union and is itself
+ a subclass of Moose::Meta::TypeCoercion
* Moose::Meta::TypeConstraint::Container
- added this module (taken from MooseX::AttributeHelpers)
* Moose::Meta::TypeConstraint::Registry
- added this class to keep track of type constraints
-
- * Moose::Meta::Attribute
- Moose::Meta::Method::Constructor
- Moose::Meta::Method::Accessor
- - fixed issue with overload::Overloaded getting called
- on non-blessed items.
- - added tests for this
-
- * Moose::Coookbook::Snacks
- - these are bits of documentation, not quite as big as
- Recipes but which have no clear place in the module docs.
- So they are Snacks! (horray for castaway++)
0.25 Mon. Aug. 13, 2007
* Moose
lib/Moose/Meta/Method.pm
lib/Moose/Meta/Role.pm
lib/Moose/Meta/TypeCoercion.pm
+lib/Moose/Meta/TypeCoercion/Union.pm
lib/Moose/Meta/TypeConstraint.pm
lib/Moose/Meta/Method/Accessor.pm
lib/Moose/Meta/Method/Constructor.pm
--- /dev/null
+
+package Moose::Meta::TypeCoercion::Union;
+
+use strict;
+use warnings;
+use metaclass;
+
+use Carp 'confess';
+use Scalar::Util 'blessed';
+
+our $VERSION = '0.01';
+our $AUTHORITY = 'cpan:STEVAN';
+
+use base 'Moose::Meta::TypeCoercion';
+
+sub compile_type_coercion {
+ my $self = shift;
+ my $type_constraint = $self->type_constraint;
+
+ (blessed $type_constraint && $type_constraint->isa('Moose::Meta::TypeConstraint::Union'))
+ || confess "You can only a Moose::Meta::TypeCoercion::Union for a " .
+ "Moose::Meta::TypeConstraint::Union, not a $type_constraint";
+
+ $self->_compiled_type_coercion(sub {
+ my $value = shift;
+ # go through all the type constraints
+ # in the union, and check em ...
+ foreach my $type (@{$type_constraint->type_constraints}) {
+ # if they have a coercion first
+ if ($type->has_coercion) {
+ # then try to coerce them ...
+ my $temp = $type->coerce($value);
+ # and if they get something
+ # make sure it still fits within
+ # the union type ...
+ return $temp if $type_constraint->check($temp);
+ }
+ }
+ return undef;
+ });
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Moose::Meta::TypeCoercion::Union - The Moose Type Coercion metaclass for Unions
+
+=head1 DESCRIPTION
+
+For the most part, the only time you will ever encounter an
+instance of this class is if you are doing some serious deep
+introspection. This API should not be considered final, but
+it is B<highly unlikely> that this will matter to a regular
+Moose user.
+
+If you wish to use features at this depth, please come to the
+#moose IRC channel on irc.perl.org and we can talk :)
+
+=head1 METHODS
+
+=over 4
+
+=item B<meta>
+
+=item B<compile_type_coercion>
+
+=back
+
+=head1 BUGS
+
+All complex software has bugs lurking in it, and this module is no
+exception. If you find a bug please either email me, or add the bug
+to cpan-RT.
+
+=head1 AUTHOR
+
+Stevan Little E<lt>stevan@iinteractive.comE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2006, 2007 by Infinity Interactive, Inc.
+
+L<http://www.iinteractive.com>
+
+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
our $VERSION = '0.09';
our $AUTHORITY = 'cpan:STEVAN';
-use Moose::Meta::TypeConstraint::Union;
-use Moose::Meta::TypeConstraint::Container;
-
-__PACKAGE__->meta->add_attribute('name' => (reader => 'name' ));
-__PACKAGE__->meta->add_attribute('parent' => (reader => 'parent' ));
+__PACKAGE__->meta->add_attribute('name' => (reader => 'name'));
+__PACKAGE__->meta->add_attribute('parent' => (
+ reader => 'parent',
+ predicate => 'has_parent',
+));
__PACKAGE__->meta->add_attribute('constraint' => (
reader => 'constraint',
writer => '_set_constraint',
accessor => 'coercion',
predicate => 'has_coercion'
));
-
-# private accessor
-__PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
- accessor => '_compiled_type_constraint'
-));
-
__PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
init_arg => 'optimized',
accessor => 'hand_optimized_type_constraint',
predicate => 'has_hand_optimized_type_constraint',
));
+# private accessors
+
+__PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
+ accessor => '_compiled_type_constraint',
+ predicate => '_has_compiled_type_constraint'
+));
__PACKAGE__->meta->add_attribute('package_defined_in' => (
accessor => '_package_defined_in'
));
sub new {
my $class = shift;
my $self = $class->meta->new_object(@_);
- $self->compile_type_constraint();
+ $self->compile_type_constraint()
+ unless $self->_has_compiled_type_constraint;
return $self;
}
-sub coerce {
- ((shift)->coercion || confess "Cannot coerce without a type coercion")->coerce(@_)
-}
-
-sub _collect_all_parents {
- my $self = shift;
- my @parents;
- my $current = $self->parent;
- while (defined $current) {
- push @parents => $current;
- $current = $current->parent;
- }
- return @parents;
-}
-
-sub compile_type_constraint {
- my $self = shift;
-
- if ($self->has_hand_optimized_type_constraint) {
- my $type_constraint = $self->hand_optimized_type_constraint;
- $self->_compiled_type_constraint(sub {
- return undef unless $type_constraint->($_[0]);
- return 1;
- });
- return;
- }
-
- my $check = $self->constraint;
- (defined $check)
- || confess "Could not compile type constraint '" . $self->name . "' because no constraint check";
- my $parent = $self->parent;
- if (defined $parent) {
- # we have a subtype ...
- # so we gather all the parents in order
- # and grab their constraints ...
- my @parents;
- foreach my $parent ($self->_collect_all_parents) {
- if ($parent->has_hand_optimized_type_constraint) {
- unshift @parents => $parent->hand_optimized_type_constraint;
- last;
- }
- else {
- unshift @parents => $parent->constraint;
- }
- }
-
- # then we compile them to run without
- # having to recurse as we did before
- $self->_compiled_type_constraint(subname $self->name => sub {
- local $_ = $_[0];
- foreach my $parent (@parents) {
- return undef unless $parent->($_[0]);
- }
- return undef unless $check->($_[0]);
- 1;
- });
- }
- else {
- # we have a type ....
- $self->_compiled_type_constraint(subname $self->name => sub {
- local $_ = $_[0];
- return undef unless $check->($_[0]);
- 1;
- });
- }
-}
-
-sub check { $_[0]->_compiled_type_constraint->($_[1]) }
-
+sub coerce { ((shift)->coercion || confess "Cannot coerce without a type coercion")->coerce(@_) }
+sub check { $_[0]->_compiled_type_constraint->($_[1]) }
sub validate {
my ($self, $value) = @_;
if ($self->_compiled_type_constraint->($value)) {
}
}
+## type predicates ...
+
sub is_a_type_of {
my ($self, $type_name) = @_;
($self->name eq $type_name || $self->is_subtype_of($type_name));
return 0;
}
-sub union {
- my ($class, @type_constraints) = @_;
- (scalar @type_constraints >= 2)
- || confess "You must pass in at least 2 Moose::Meta::TypeConstraint instances to make a union";
- (blessed($_) && $_->isa('Moose::Meta::TypeConstraint'))
- || confess "You must pass in only Moose::Meta::TypeConstraint instances to make unions"
- foreach @type_constraints;
- return Moose::Meta::TypeConstraint::Union->new(
- type_constraints => \@type_constraints,
- );
+## compiling the type constraint
+
+sub compile_type_constraint {
+ my $self = shift;
+ $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
}
+## type compilers ...
+
+sub _actually_compile_type_constraint {
+ my $self = shift;
+
+ return $self->_compile_hand_optimized_type_constraint
+ if $self->has_hand_optimized_type_constraint;
+
+ my $check = $self->constraint;
+ (defined $check)
+ || confess "Could not compile type constraint '"
+ . $self->name
+ . "' because no constraint check";
+
+ return $self->_compile_subtype($check)
+ if $self->has_parent;
+
+ return $self->_compile_type($check);
+}
+
+sub _compile_hand_optimized_type_constraint {
+ my $self = shift;
+
+ my $type_constraint = $self->hand_optimized_type_constraint;
+
+ return sub {
+ return undef unless $type_constraint->($_[0]);
+ return 1;
+ };
+}
+
+sub _compile_subtype {
+ my ($self, $check) = @_;
+
+ # so we gather all the parents in order
+ # and grab their constraints ...
+ my @parents;
+ foreach my $parent ($self->_collect_all_parents) {
+ if ($parent->has_hand_optimized_type_constraint) {
+ unshift @parents => $parent->hand_optimized_type_constraint;
+ last;
+ }
+ else {
+ unshift @parents => $parent->constraint;
+ }
+ }
+
+ # then we compile them to run without
+ # having to recurse as we did before
+ return subname $self->name => sub {
+ local $_ = $_[0];
+ foreach my $parent (@parents) {
+ return undef unless $parent->($_[0]);
+ }
+ return undef unless $check->($_[0]);
+ 1;
+ };
+}
+
+sub _compile_type {
+ my ($self, $check) = @_;
+ return subname $self->name => sub {
+ local $_ = $_[0];
+ return undef unless $check->($_[0]);
+ 1;
+ };
+}
+
+## other utils ...
+
+sub _collect_all_parents {
+ my $self = shift;
+ my @parents;
+ my $current = $self->parent;
+ while (defined $current) {
+ push @parents => $current;
+ $current = $current->parent;
+ }
+ return @parents;
+}
+
+## this should get deprecated actually ...
+
+sub union { die "DEPRECATED" }
+
1;
__END__
=item B<parent>
+=item B<has_parent>
+
=item B<constraint>
=item B<has_message>
=back
+=head2 DEPRECATED METHOD
+
=over 4
-=item B<union (@type_constraints)>
+=item B<union>
+
+This was just bad idea on my part,.. use the L<Moose::Meta::TypeConstraint::Union>
+itself instead.
=back
use warnings;
use metaclass;
+use Moose::Meta::TypeCoercion::Union;
+
our $VERSION = '0.06';
our $AUTHORITY = 'cpan:STEVAN';
-# NOTE:
-# this is not really correct, but
-# I think it shoul be here anyway.
-# In truth, this should implement
-# the same abstract base/interface
-# as the TC moule.
-# - SL
use base 'Moose::Meta::TypeConstraint';
__PACKAGE__->meta->add_attribute('type_constraints' => (
));
sub new {
- my $class = shift;
- my $self = $class->meta->new_object(@_);
+ my ($class, %options) = @_;
+ my $self = $class->SUPER::new(
+ name => (join ' | ' => map { $_->name } @{$options{type_constraints}}),
+ parent => undef,
+ message => undef,
+ hand_optimized_type_constraint => undef,
+ compiled_type_constraint => sub {
+ my $value = shift;
+ foreach my $type (@{$options{type_constraints}}) {
+ return 1 if $type->check($value);
+ }
+ return undef;
+ },
+ %options
+ );
+ $self->_set_constraint(sub { $self->check($_[0]) });
+ $self->coercion(Moose::Meta::TypeCoercion::Union->new(
+ type_constraint => $self
+ ));
return $self;
}
-sub name { join ' | ' => map { $_->name } @{$_[0]->type_constraints} }
-
-# NOTE:
-# this should probably never be used
-# but we include it here for completeness
-sub constraint {
- my $self = shift;
- sub { $self->check($_[0]) };
-}
-
-# conform to the TypeConstraint API
-sub parent { undef }
-sub message { undef }
-sub has_message { 0 }
-
-# FIXME:
-# not sure what this should actually do here
-sub coercion { undef }
-
-# this should probably be memoized
-sub has_coercion {
- my $self = shift;
- foreach my $type (@{$self->type_constraints}) {
- return 1 if $type->has_coercion
- }
- return 0;
-}
-
-# NOTE:
-# this feels too simple, and may not always DWIM
-# correctly, especially in the presence of
-# close subtype relationships, however it should
-# work for a fair percentage of the use cases
-sub coerce {
- my $self = shift;
- my $value = shift;
- foreach my $type (@{$self->type_constraints}) {
- if ($type->has_coercion) {
- my $temp = $type->coerce($value);
- return $temp if $self->check($temp);
- }
- }
- return undef;
-}
-
-sub _compiled_type_constraint {
- my $self = shift;
- return sub {
- my $value = shift;
- foreach my $type (@{$self->type_constraints}) {
- return 1 if $type->check($value);
- }
- return undef;
- }
-}
-
-sub check {
- my $self = shift;
- my $value = shift;
- $self->_compiled_type_constraint->($value);
-}
-
sub validate {
- my $self = shift;
- my $value = shift;
+ my ($self, $value) = @_;
my $message;
foreach my $type (@{$self->type_constraints}) {
my $err = $type->validate($value);
return 0;
}
-## hand optimized constraints
-
-# NOTE:
-# it will just use all the hand optimized
-# type constraints from it's list of type
-# constraints automatically, but there is
-# no simple way to optimize it even more
-# (without B::Deparse or something). So
-# we just stop here.
-# - SL
-
-sub has_hand_optimized_type_constraint { 0 }
-sub hand_optimized_type_constraint { undef }
-
1;
__END__
sub enum ($;@);
use Moose::Meta::TypeConstraint;
+use Moose::Meta::TypeConstraint::Union;
+use Moose::Meta::TypeConstraint::Container;
use Moose::Meta::TypeCoercion;
+use Moose::Meta::TypeCoercion::Union;
use Moose::Meta::TypeConstraint::Registry;
my @exports = qw/
sub create_type_constraint_union (@) {
my (@type_constraint_names) = @_;
- return Moose::Meta::TypeConstraint->union(
- map {
- $REGISTRY->get_type_constraint($_)
- } @type_constraint_names
- );
+ (scalar @type_constraint_names >= 2)
+ || confess "You must pass in at least 2 type names to make a union";
+ return Moose::Meta::TypeConstraint::Union->new(
+ type_constraints => [
+ map {
+ $REGISTRY->get_type_constraint($_)
+ } @type_constraint_names
+ ],
+ );
}
sub export_type_constraints_as_functions {
ok(!$Undef->check('String'), '... Undef cannot accept an Str value');
ok($Undef->check(undef), '... Undef can accept an Undef value');
-my $Str_or_Undef = Moose::Meta::TypeConstraint->union($Str, $Undef);
+my $Str_or_Undef = Moose::Meta::TypeConstraint::Union->new(type_constraints => [$Str, $Undef]);
isa_ok($Str_or_Undef, 'Moose::Meta::TypeConstraint::Union');
ok($Str_or_Undef->check(undef), '... (Str | Undef) can accept an Undef value');
ok($HashRef->check({}), '... HashRef can accept an {} value');
ok(!$HashRef->check([]), '... HashRef cannot accept an [] value');
-my $HashOrArray = Moose::Meta::TypeConstraint->union($ArrayRef, $HashRef);
+my $HashOrArray = Moose::Meta::TypeConstraint::Union->new(type_constraints => [$ArrayRef, $HashRef]);
isa_ok($HashOrArray, 'Moose::Meta::TypeConstraint::Union');
ok($HashOrArray->check([]), '... (ArrayRef | HashRef) can accept []');