Add a reference to Extending recipe 1 here, since this one is a
[gitmo/Moose.git] / lib / Moose / Cookbook / Extending / Recipe2.pod
1
2 =pod
3
4 =head1 NAME
5
6 Moose::Cookbook::Extending::Recipe2 - Acting like Moose.pm and providing sugar Moose-style
7
8 =head1 SYNOPSIS
9
10   package MyApp::Mooseish;
11
12   use strict;
13   use warnings;
14
15   our @EXPORT = qw( has_table );
16
17   use base 'Exporter';
18   use Class::MOP;
19   use Moose ();
20
21   sub import {
22     my $caller = caller();
23
24     return if $caller eq 'main';
25
26     Moose::init_meta( $caller,
27                       undef, # object base class
28                       'MyApp::Meta::Class',
29                     );
30
31     Moose->import( { into => $caller }, @_ );
32
33     __PACKAGE__->export_to_level( 1, @_ );
34   }
35
36   sub unimport {
37       my $caller = caller();
38
39       no strict 'refs';
40       foreach my $name (@EXPORT) {
41           if ( defined &{ $caller . '::' . $name } ) {
42               my $keyword = \&{ $caller . '::' . $name };
43
44               my ($pkg_name) = Class::MOP::get_code_info($keyword);
45
46               next if $pkg_name ne __PACKAGE__;
47
48               delete ${ $caller . '::' }{$name};
49           }
50       }
51
52       Moose::unimport( { into_level => 1 } );
53   }
54
55   sub has_table {
56       my $caller = caller();
57
58       $caller->meta()->table(shift);
59   }
60
61 =head1 DESCRIPTION
62
63 The code above shows what it takes to provide an import-based
64 interface just like C<Moose.pm>. This recipe builds on
65 L<Moose::Cookbook::Extending::Recipe1>. Instead of providing our own
66 object base class, we provide our own metaclass class, and we also
67 export a sugar subroutine C<has_table()>.
68
69 Given the above code, you can now replace all instances of C<use
70 Moose> with C<use MyApp::Mooseish>. Similarly, C<no Moose> is now
71 replaced with C<no MyApp::Mooseish>.
72
73 =head1 WARNING
74
75 This recipe covers a fairly undocumented and ugly part of Moose, and
76 the techniques described here may be deprecated in a future
77 release. If this happens, there will be plenty of warning, as a number
78 of C<MooseX> modules on CPAN already use these techniques.
79
80 =head1 HOW IT IS USED
81
82 The purpose of all this code is to provide a Moose-like
83 interface. Here's what it would look like in actual use:
84
85   package MyApp::User;
86
87   use MyApp::Mooseish;
88
89   has_table 'User';
90
91   has 'username';
92   has 'password';
93
94   sub login { ... }
95
96   no MyApp::Mooseish;
97
98 All of the normal Moose sugar (C<has()>, C<with()>, etc) is available
99 when you C<use MyApp::Mooseish>.
100
101 =head1 DISSECTION
102
103 The first bit of magic is the call to C<Moose::init_meta()>. What this
104 does is create a metaclass for the specified class. Normally, this is
105 called by C<Moose.pm> in its own C<import()> method. However, we can
106 call it first in order to provide an alternate metaclass class. We
107 could also provide an alternate base object class to replace
108 C<Moose::Object> (see L<Moose::Cookbook::Extending::Recipe1> for an
109 example).
110
111 The C<Moose::init_meta()> call takes three parameters. The first is
112 the class for which we are initializing a metaclass object. The second
113 is the base object, which is L<Moose::Object> by default. The third
114 argument is the metaclass class, which is C<Moose::Meta::Class> by
115 default.
116
117 The next bit of magic is this:
118
119   Moose->import( { into => $caller } );
120
121 This use of "into" is actually part of the C<Sub::Exporter> API, which
122 C<Moose.pm> uses internally to export things like C<has()> and
123 C<extends()>.
124
125 Finally, we call C<< __PACKAGE__->export_to_level() >>. This method
126 actually comes from C<Exporter>.
127
128 This is all a bit fragile since it doesn't stack terribly well. You
129 can basically only have one Moose-alike module. This may be fixed in
130 the still-notional C<MooseX::Exporter> module someday.
131
132 The C<unimport()> subroutine is basically a copy of the C<unimport()>
133 from C<Moose.pm>. You can copy this verbatim into your code. Again,
134 this doesn't stack well.
135
136 Finally, we have our C<has_table()> subroutine. This provides a bit of
137 sugar that looks a lot like C<has()>.
138
139 =head1 AUTHOR
140
141 Dave Rolsky E<lt>autarch@urth.orgE<gt>
142
143 =head1 COPYRIGHT AND LICENSE
144
145 Copyright 2006-2008 by Infinity Interactive, Inc.
146
147 L<http://www.iinteractive.com>
148
149 This library is free software; you can redistribute it and/or modify
150 it under the same terms as Perl itself.
151
152 =pod