Sinan's BUILD
answer is probably the sanest most straight forward solution. Using BUILDARGS
as dave mentioned is also a reasonable solution.
I felt it worth mentioning that one could use Type Coercions as well. Given a class:
class LineSegment {
has [qw(startX startY endX endY)] => (
isa => 'Num',
is => 'ro',
required => 1
);
}
You can use a set of coercions like so:
class_type 'LineSegment';
subtype StartLength
=> as Hashref
=> where { exists $_->{startX} && $_->{startY} && $_->{length} };
subtype EndLength
=> as Hashref
=> where { exists $_->{endX} && $_->{endY} && $_->{length} };
coerce LineSegment
=> from StartLength
=> via { my ($endX, $endY) = calc_end($_);
LineSegment->new(
startX => $_->{startX},
startY => $_->{startY},
endX => $endX,
endY => $endY,
)};
coerce LineSegment
=> from EndLength
=> via { my ($startX, $startY) = calc_start($_);
LineSegment->new(
startX => $startX,
startY => $startY,
endX => $_->{endX},
endY => $_->{endY},
)};
Then in your code:
use Moose::Util::TypeConstraints;
find_type_constraint('LineSegment')->coerce({
startX => $x,
startY => $y,
length => $length
});
While perhaps overkill for this example, there are several times when a coercion is an elegant solution. For example if you have a pre-existing LineSegment
class you wish to not add a length
attribute to (though BUILDARGS
would work well there too)