Commit | Line | Data |
d5e84b86 |
1 | |
2 | =pod |
3 | |
5547fba7 |
4 | =begin testing-SETUP |
c79239a2 |
5 | |
0adca353 |
6 | use Test::Requires { |
7 | 'Test::Output' => '0', |
8 | }; |
c79239a2 |
9 | |
5547fba7 |
10 | =end testing-SETUP |
c79239a2 |
11 | |
d5e84b86 |
12 | =head1 NAME |
13 | |
c8d5f1e1 |
14 | Moose::Cookbook::Extending::Recipe3 - Providing an alternate base object class |
d5e84b86 |
15 | |
16 | =head1 SYNOPSIS |
17 | |
18 | package MyApp::Base; |
19 | use Moose; |
20 | |
21 | extends 'Moose::Object'; |
22 | |
23 | before 'new' => sub { warn "Making a new " . $_[0] }; |
24 | |
25 | no Moose; |
26 | |
27 | package MyApp::UseMyBase; |
28 | use Moose (); |
554b7648 |
29 | use Moose::Exporter; |
d5e84b86 |
30 | |
aedcb7d9 |
31 | Moose::Exporter->setup_import_methods( also => 'Moose' ); |
d5e84b86 |
32 | |
554b7648 |
33 | sub init_meta { |
34 | shift; |
a8de959b |
35 | return Moose->init_meta( @_, base_class => 'MyApp::Base' ); |
d5e84b86 |
36 | } |
37 | |
38 | =head1 DESCRIPTION |
39 | |
9ac00c2b |
40 | A common extension is to provide an alternate base class. One way to |
41 | do that is to make a C<MyApp::base> and add C<S<extends |
42 | 'MyApp::Base'>> to every class in your application. That's pretty |
43 | tedious. Instead, you can create a Moose-alike module that sets the |
44 | base object class to C<MyApp::Base> for you. |
d5e84b86 |
45 | |
46 | Then, instead of writing C<S<use Moose>> you can write C<S<use |
47 | MyApp::UseMyBase>>. |
48 | |
49 | In this particular example, our base class issues some debugging |
9ac00c2b |
50 | output every time a new object is created, but you can think of some |
51 | more interesting things to do with your own base class. |
d5e84b86 |
52 | |
5a87a5ca |
53 | This uses the magic of L<Moose::Exporter>. When we call C<< |
54 | Moose::Exporter->setup_import_methods( also => 'Moose' ) >> it builds |
55 | C<import> and C<unimport> methods for you. The C<< also => 'Moose' >> |
56 | bit says that we want to export everything that Moose does. |
554b7648 |
57 | |
58 | The C<import> method that gets created will call our C<init_meta> |
5a87a5ca |
59 | method, passing it C<< for_caller => $caller >> as its |
9ac00c2b |
60 | arguments. The C<$caller> is set to the class that actually imported |
61 | us in the first place. |
554b7648 |
62 | |
63 | See the L<Moose::Exporter> docs for more details on its API. |
64 | |
65 | =head1 USING MyApp::UseMyBase |
66 | |
67 | To actually use our new base class, we simply use C<MyApp::UseMyBase> |
68 | I<instead> of C<Moose>. We get all the Moose sugar plus our new base |
69 | class. |
70 | |
71 | package Foo; |
72 | |
73 | use MyApp::UseMyBase; |
74 | |
75 | has 'size' => ( is => 'rw' ); |
76 | |
77 | no MyApp::UseMyBase; |
78 | |
9ac00c2b |
79 | =head1 CONCLUSION |
80 | |
81 | This is an awful lot of magic for a simple base class. You will often |
82 | want to combine a metaclass trait with a base class extension, and |
83 | that's when this technique is useful. |
84 | |
d5e84b86 |
85 | =head1 AUTHOR |
86 | |
87 | Dave Rolsky E<lt>autarch@urth.orgE<gt> |
88 | |
89 | =head1 COPYRIGHT AND LICENSE |
90 | |
7e0492d3 |
91 | Copyright 2006-2010 by Infinity Interactive, Inc. |
d5e84b86 |
92 | |
93 | L<http://www.iinteractive.com> |
94 | |
95 | This library is free software; you can redistribute it and/or modify |
96 | it under the same terms as Perl itself. |
97 | |
c79239a2 |
98 | =begin testing |
99 | |
100 | { |
101 | package Foo; |
102 | |
103 | MyApp::UseMyBase->import; |
104 | |
105 | has( 'size' => ( is => 'rw' ) ); |
106 | } |
107 | |
108 | ok( Foo->isa('MyApp::Base'), 'Foo isa MyApp::Base' ); |
109 | |
110 | ok( Foo->can('size'), 'Foo has a size method' ); |
111 | |
112 | my $foo; |
8b23f9f8 |
113 | stderr_like( |
c79239a2 |
114 | sub { $foo = Foo->new( size => 2 ) }, |
8b23f9f8 |
115 | qr/^Making a new Foo/, |
c79239a2 |
116 | 'got expected warning when calling Foo->new' |
117 | ); |
118 | |
119 | is( $foo->size(), 2, '$foo->size is 2' ); |
120 | |
121 | =end testing |
122 | |
d5e84b86 |
123 | =cut |