Commit | Line | Data |
04d80e2a |
1 | |
2 | =pod |
3 | |
1f476b5f |
4 | =begin testing-SETUP |
5 | |
0adca353 |
6 | use Test::Requires { |
7 | 'DateTime' => '0', |
8 | 'DateTime::Calendar::Mayan' => '0', |
9 | }; |
1f476b5f |
10 | |
11 | =end testing-SETUP |
12 | |
04d80e2a |
13 | =head1 NAME |
14 | |
31098197 |
15 | Moose::Cookbook::Basics::Recipe11 - Extending a non-Moose base class |
04d80e2a |
16 | |
17 | =head1 SYNOPSIS |
18 | |
1f476b5f |
19 | package My::DateTime; |
04d80e2a |
20 | |
1f476b5f |
21 | use Moose; |
22 | extends qw( DateTime Moose::Object ); |
04d80e2a |
23 | |
1f476b5f |
24 | use DateTime::Calendar::Mayan; |
04d80e2a |
25 | |
1f476b5f |
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', |
04d80e2a |
34 | ); |
35 | |
1f476b5f |
36 | sub new { |
04d80e2a |
37 | my $class = shift; |
38 | |
1f476b5f |
39 | my $obj = $class->SUPER::new(@_); |
40 | |
41 | return $class->meta->new_object( |
42 | __INSTANCE__ => $obj, |
43 | @_, |
44 | ); |
04d80e2a |
45 | } |
46 | |
1f476b5f |
47 | after 'set' => sub { |
48 | $_[0]->_clear_mayan_date; |
49 | }; |
04d80e2a |
50 | |
1f476b5f |
51 | sub _build_mayan_date { |
52 | DateTime::Calendar::Mayan->from_object( object => $_[0] ); |
04d80e2a |
53 | } |
54 | |
55 | =head1 DESCRIPTION |
56 | |
1f476b5f |
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>. |
04d80e2a |
61 | |
1f476b5f |
62 | You might also want to check out L<MooseX::NonMoose>, which does all |
63 | the grunt work for you. |
04d80e2a |
64 | |
1f476b5f |
65 | There are a couple pieces worth noting: |
04d80e2a |
66 | |
1f476b5f |
67 | use Moose; |
68 | extends qw( DateTime Moose::Object ); |
04d80e2a |
69 | |
1f476b5f |
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. |
04d80e2a |
72 | |
1f476b5f |
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>. |
04d80e2a |
76 | |
1f476b5f |
77 | The constructor demonstrates a particular hack/pattern (hacktern?) for |
78 | working with non-Moose parent classes: |
04d80e2a |
79 | |
1f476b5f |
80 | sub new { |
81 | my $class = shift; |
04d80e2a |
82 | |
1f476b5f |
83 | my $obj = $class->SUPER::new(@_); |
04d80e2a |
84 | |
1f476b5f |
85 | return $class->meta->new_object( |
86 | __INSTANCE__ => $obj, |
87 | @_, |
88 | ); |
89 | } |
04d80e2a |
90 | |
1f476b5f |
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. |
04d80e2a |
95 | |
1f476b5f |
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. |
04d80e2a |
98 | |
99 | =head1 CONCLUSION |
100 | |
1f476b5f |
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. |
04d80e2a |
105 | |
1f476b5f |
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. |
04d80e2a |
110 | |
111 | =head1 AUTHOR |
112 | |
113 | Dave Rolsky E<lt>autarch@urth.orgE<gt> |
114 | |
115 | =head1 COPYRIGHT AND LICENSE |
116 | |
1f476b5f |
117 | Copyright 2009 by Infinity Interactive, Inc. |
04d80e2a |
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 | |
1f476b5f |
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 | |
04d80e2a |
137 | =cut |