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