Commit | Line | Data |
97da20ef |
1 | package Moose::Cookbook::Extending::Debugging_BaseClassRole; |
daa0fd7d |
2 | |
3 | # ABSTRACT: Providing a role for the base object class |
4 | |
5 | __END__ |
6 | |
f3ce0579 |
7 | |
8 | =pod |
9 | |
6e646af9 |
10 | =begin testing-SETUP |
11 | |
0adca353 |
12 | use Test::Requires { |
13 | 'Test::Output' => '0', |
14 | }; |
6e646af9 |
15 | |
16 | =end testing-SETUP |
17 | |
f3ce0579 |
18 | =head1 SYNOPSIS |
19 | |
20 | package MooseX::Debugging; |
21 | |
f3ce0579 |
22 | use Moose::Exporter; |
f3ce0579 |
23 | |
95056a1e |
24 | Moose::Exporter->setup_import_methods( |
25 | base_class_roles => ['MooseX::Debugging::Role::Object'], |
26 | ); |
f3ce0579 |
27 | |
f3ce0579 |
28 | package MooseX::Debugging::Role::Object; |
29 | |
0df6b748 |
30 | use Moose::Role; |
31 | |
cab0126b |
32 | sub BUILD {} |
33 | after BUILD => sub { |
f3ce0579 |
34 | my $self = shift; |
35 | |
6e646af9 |
36 | warn "Made a new " . ( ref $self ) . " object\n"; |
6a7e3999 |
37 | }; |
f3ce0579 |
38 | |
39 | =head1 DESCRIPTION |
40 | |
41 | In this example, we provide a role for the base object class that adds |
42 | some simple debugging output. Every time an object is created, it |
43 | spits out a warning saying what type of object it was. |
44 | |
45 | Obviously, a real debugging role would do something more interesting, |
46 | but this recipe is all about how we apply that role. |
47 | |
48 | In this case, with the combination of L<Moose::Exporter> and |
8efdbb91 |
49 | L<Moose::Util::MetaRole>, we ensure that when a module does C<S<use |
50 | MooseX::Debugging>>, it automatically gets the debugging role applied |
f3ce0579 |
51 | to its base object class. |
52 | |
871cda31 |
53 | There are a few pieces of code worth looking at more closely. |
54 | |
95056a1e |
55 | Moose::Exporter->setup_import_methods( |
56 | base_class_roles => ['MooseX::Debugging::Role::Object'], |
57 | ); |
871cda31 |
58 | |
edd82429 |
59 | This creates an C<import> method in the C<MooseX::Debugging> package. Since we |
60 | are not actually exporting anything, we do not pass C<setup_import_methods> |
61 | any parameters related to exports, but we need to have an C<import> method to |
62 | ensure that our C<init_meta> method is called. The C<init_meta> is created by |
63 | C<setup_import_methods> for us, since we passed the C<base_class_roles> |
64 | parameter. The generated C<init_meta> will in turn call |
65 | L<Moose::Util::MetaRole::apply_base_class_roles|Moose::Util::MetaRole/apply_base_class_roles>. |
871cda31 |
66 | |
cab0126b |
67 | sub BUILD {} |
68 | after BUILD => sub { |
69 | ... |
70 | }; |
71 | |
72 | Due to the way role composition currently works, if the class that a role is |
73 | composed into contains a C<BUILD> method, then that will override the C<BUILD> |
74 | method in any roles it composes, which is typically not what you want. Using a |
75 | method modifier on C<BUILD> avoids this issue, since method modifiers compose |
76 | together rather than being overridden. Method modifiers require that a method |
77 | exists in order to wrap, however, so we also provide a stub method to wrap if |
78 | no C<BUILD> method exists in the class. |
79 | |
6e646af9 |
80 | =begin testing |
81 | |
82 | { |
83 | package Debugged; |
f3ce0579 |
84 | |
6e646af9 |
85 | use Moose; |
86 | MooseX::Debugging->import; |
87 | } |
88 | |
89 | stderr_is( |
90 | sub { Debugged->new }, |
91 | "Made a new Debugged object\n", |
92 | 'got expected output from debugging role' |
93 | ); |
94 | |
95 | =end testing |
96 | |
97 | =cut |