Rename Basics::Recipe6 to Basics::Document_AugmentAndInner
[gitmo/Moose.git] / lib / Moose / Cookbook / Basics / Document_AugmentAndInner.pod
CommitLineData
174418c2 1package Moose::Cookbook::Basics::Document_AugmentAndInner
a909a4df 2
174418c2 3# ABSTRACT: The augment modifier, which turns normal method overriding "inside-out"
daa0fd7d 4
5__END__
a909a4df 6
a909a4df 7
daa0fd7d 8=pod
a909a4df 9
10=head1 SYNOPSIS
f1c9feb4 11
a909a4df 12 package Document::Page;
13 use Moose;
f1c9feb4 14
15 has 'body' => ( is => 'rw', isa => 'Str', default => sub {''} );
16
a909a4df 17 sub create {
18 my $self = shift;
19 $self->open_page;
20 inner();
21 $self->close_page;
22 }
f1c9feb4 23
24 sub append_body {
25 my ( $self, $appendage ) = @_;
26 $self->body( $self->body . $appendage );
a909a4df 27 }
f1c9feb4 28
d876e049 29 sub open_page { (shift)->append_body('<page>') }
f1c9feb4 30 sub close_page { (shift)->append_body('</page>') }
31
d876e049 32 package Document::PageWithHeadersAndFooters;
a909a4df 33 use Moose;
f1c9feb4 34
a909a4df 35 extends 'Document::Page';
f1c9feb4 36
d876e049 37 augment 'create' => sub {
a909a4df 38 my $self = shift;
39 $self->create_header;
40 inner();
41 $self->create_footer;
d876e049 42 };
f1c9feb4 43
a909a4df 44 sub create_header { (shift)->append_body('<header/>') }
f1c9feb4 45 sub create_footer { (shift)->append_body('<footer/>') }
46
d876e049 47 package TPSReport;
a909a4df 48 use Moose;
f1c9feb4 49
d876e049 50 extends 'Document::PageWithHeadersAndFooters';
f1c9feb4 51
d876e049 52 augment 'create' => sub {
a909a4df 53 my $self = shift;
54 $self->create_tps_report;
71181776 55 inner();
a909a4df 56 };
f1c9feb4 57
a909a4df 58 sub create_tps_report {
f1c9feb4 59 (shift)->append_body('<report type="tps"/>');
a909a4df 60 }
f1c9feb4 61
62 # <page><header/><report type="tps"/><footer/></page>
c79239a2 63 my $report_xml = TPSReport->new->create;
a909a4df 64
65=head1 DESCRIPTION
66
71181776 67This recipe shows how the C<augment> method modifier works. This
68modifier reverses the normal subclass to parent method resolution
69order. With an C<augment> modifier the I<least> specific method is
70called first. Each successive call to C<inner> descends the
71inheritance tree, ending at the most specific subclass.
7125b244 72
71181776 73The C<augment> modifier lets you design a parent class that can be
74extended in a specific way. The parent provides generic wrapper
75functionality, and the subclasses fill in the details.
a909a4df 76
71181776 77In the example above, we've created a set of document classes, with
78the most specific being the C<TPSReport> class.
a909a4df 79
71181776 80We start with the least specific class, C<Document::Page>. Its create
81method contains a call to C<inner()>:
a909a4df 82
71181776 83 sub create {
84 my $self = shift;
85 $self->open_page;
86 inner();
87 $self->close_page;
88 }
89
90The C<inner> function is exported by C<Moose>, and is like C<super>
91for augmented methods. When C<inner> is called, Moose finds the next
92method in the chain, which is the C<augment> modifier in
93C<Document::PageWithHeadersAndFooters>. You'll note that we can call
94C<inner> in our modifier:
95
96 augment 'create' => sub {
97 my $self = shift;
98 $self->create_header;
99 inner();
100 $self->create_footer;
101 };
102
103This finds the next most specific modifier, in the C<TPSReport> class.
104
105Finally, in the C<TPSReport> class, the chain comes to an end:
106
107 augment 'create' => sub {
108 my $self = shift;
109 $self->create_tps_report;
110 inner();
111 };
112
113We do call the C<inner> function one more time, but since there is no
114more specific subclass, this is a no-op. Making this call means we can
115easily subclass C<TPSReport> in the future.
116
117=head1 CONCLUSION
118
119The C<augment> modifier is a powerful tool for creating a set of
120nested wrappers. It's not something you will need often, but when you
0367f4bf 121do, it is very handy.
a909a4df 122
c79239a2 123=begin testing
124
125my $tps_report = TPSReport->new;
126isa_ok( $tps_report, 'TPSReport' );
127
128is(
129 $tps_report->create,
130 q{<page><header/><report type="tps"/><footer/></page>},
131 '... got the right TPS report'
132);
133
134=end testing
135
71181776 136=cut