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