1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
=pod
=begin testing-SETUP
BEGIN {
eval 'use DateTime; use DateTime::Calendar::Mayan;';
if ($@) {
diag 'DateTime & DateTime::Calendar::Mayan required for this test';
ok(1);
exit 0;
}
}
=end testing-SETUP
=head1 NAME
Moose::Cookbook::Basics::Recipe11 - Extending a non-Moose base class
=head1 SYNOPSIS
package My::DateTime;
use Moose;
extends qw( DateTime Moose::Object );
use DateTime::Calendar::Mayan;
has 'mayan_date' => (
is => 'ro',
isa => 'DateTime::Calendar::Mayan',
init_arg => undef,
lazy => 1,
builder => '_build_mayan_date',
clearer => '_clear_mayan_date',
predicate => 'has_mayan_date',
);
sub new {
my $class = shift;
my $obj = $class->SUPER::new(@_);
return $class->meta->new_object(
__INSTANCE__ => $obj,
@_,
);
}
after 'set' => sub {
$_[0]->_clear_mayan_date;
};
sub _build_mayan_date {
DateTime::Calendar::Mayan->from_object( object => $_[0] );
}
=head1 DESCRIPTION
This recipe demonstrates how to use Moose to subclass a parent which
is not Moose based. This recipe only works if the parent class uses a
blessed hash reference for object instances. If your parent is doing
something funkier, you should check out L<MooseX::InsideOut>.
You might also want to check out L<MooseX::NonMoose>, which does all
the grunt work for you.
There are a couple pieces worth noting:
use Moose;
extends qw( DateTime Moose::Object );
First, we C<use Moose> just like we always do. This lets us declare
attributes and use all the Moose sugar to which we are accustomed.
The C<extends> declaration explicitly include L<Moose::Object> as well
as L<DateTime>. This lets us use methods which are provided by
L<Moose::Object>, like C<does>.
The constructor demonstrates a particular hack/pattern (hacktern?) for
working with non-Moose parent classes:
sub new {
my $class = shift;
my $obj = $class->SUPER::new(@_);
return $class->meta->new_object(
__INSTANCE__ => $obj,
@_,
);
}
We explicitly call C<< $class->meta->new_object >> and pass the
already-created object in the C<__INSTANCE__> key. Internally, Moose
will take the existing object and initialize any attributes defined in
our subclass.
The C<after> modifier works just like we'd expect. The fact that
C<set> is defined in our non-Moose parent does not matter.
=head1 CONCLUSION
Moose can play nice with non-Moose classes when you follow the pattern
shown here. Your subclass has access to all the power of Moose,
including attribute declaration, method modifiers, type constraints
(for new attributes), and roles.
However, you won't be able to easily override a parent's "attributes",
since they're not Moose attributes. Nor will you be able to inline a
constructor, since you need to explicitly use the metaclass's object
constructor.
=head1 AUTHOR
Dave Rolsky E<lt>autarch@urth.orgE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright 2009 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.
=begin testing
my $dt = My::DateTime->new( year => 1970, month => 2, day => 24 );
can_ok( $dt, 'mayan_date' );
isa_ok( $dt->mayan_date, 'DateTime::Calendar::Mayan' );
is( $dt->mayan_date->date, '12.17.16.9.19', 'got expected mayan date' );
$dt->set( year => 2009 );
ok( ! $dt->has_mayan_date, 'mayan_date is cleared after call to ->set' );
=end testing
=cut
|