Add Moose::_get_caller for more backwards compat
[gitmo/Moose.git] / lib / Moose / Exporter.pm
CommitLineData
5bd4db9b 1package Moose::Exporter;
2
3use strict;
4use warnings;
5
6use Class::MOP;
cd00320f 7use namespace::clean 0.08 ();
5bd4db9b 8use Sub::Exporter;
9
10
0338a411 11my %EXPORT_SPEC;
1a601f52 12
a5c426fc 13sub build_import_methods {
14 my $class = shift;
15 my %args = @_;
16
17 my $exporting_package = caller();
18
0338a411 19 $EXPORT_SPEC{$exporting_package} = \%args;
a5c426fc 20
f5324cca 21 my $exports = $class->_process_exports(
1a601f52 22 exporting_package => $exporting_package,
f5324cca 23 %args,
24 );
25
26 my $exporter = Sub::Exporter::build_exporter(
27 {
28 exports => $exports,
29 groups => { default => [':all'] }
30 }
1a601f52 31 );
a5c426fc 32
1a601f52 33 my $import = $class->_make_import_sub(
f5324cca 34 $exporter,
35 $args{init_meta_args},
1a601f52 36 );
a5c426fc 37
f5324cca 38 my $unimport = $class->_make_unimport_sub( [ keys %{$exports} ] );
a5c426fc 39
40 no strict 'refs';
1a601f52 41 *{ $exporting_package . '::import' } = $import;
a5c426fc 42 *{ $exporting_package . '::unimport' } = $unimport;
43}
44
f5324cca 45sub _process_exports {
5bd4db9b 46 my $class = shift;
47 my %args = @_;
48
a5c426fc 49 my $exporting_package = $args{exporting_package};
5bd4db9b 50
51 my %exports;
97a93056 52 for my $name ( @{ $args{with_caller} } ) {
e05b7c8e 53 my $sub
54 = do { no strict 'refs'; \&{ $exporting_package . '::' . $name } };
97a93056 55
e05b7c8e 56 $exports{$name}
57 = $class->_make_wrapped_sub( $exporting_package, $name, $sub );
97a93056 58 }
59
60 for my $name ( @{ $args{as_is} } ) {
5bd4db9b 61 my $sub;
97a93056 62
5bd4db9b 63 if ( ref $name ) {
64 $sub = $name;
65 $name = ( Class::MOP::get_code_info($name) )[1];
66 }
67 else {
e05b7c8e 68 $sub = do {
69 no strict 'refs';
70 \&{ $exporting_package . '::' . $name };
71 };
5bd4db9b 72 }
73
e05b7c8e 74 $exports{$name} = sub {$sub};
5bd4db9b 75 }
76
f5324cca 77 return \%exports;
5bd4db9b 78}
79
e05b7c8e 80{
81 # This variable gets closed over in each export _generator_. Then
82 # in the generator we grab the value and close over it _again_ in
83 # the real export, so it gets captured each time the generator
84 # runs.
85 #
86 # In the meantime, we arrange for the import method we generate to
87 # set this variable to the caller each time it is called.
88 #
89 # This is all a bit confusing, but it works.
90 my $CALLER;
91
92 sub _make_wrapped_sub {
93 my $class = shift;
94 my $exporting_package = shift;
95 my $name = shift;
96 my $sub = shift;
1a601f52 97
e05b7c8e 98 # We need to set the package at import time, so that when
99 # package Foo imports has(), we capture "Foo" as the
100 # package. This lets other packages call Foo::has() and get
101 # the right package. This is done for backwards compatibility
102 # with existing production code, not because this is a good
103 # idea ;)
104 return sub {
105 my $caller = $CALLER;
106 Class::MOP::subname( $exporting_package . '::'
107 . $name => sub { $sub->( $caller, @_ ) } );
108 };
109 }
f5324cca 110
e05b7c8e 111 sub _make_import_sub {
112 my $class = shift;
113 my $exporter = shift;
114 my $init_meta_args = shift;
1a601f52 115
e05b7c8e 116 return sub {
1a601f52 117
e05b7c8e 118 # It's important to leave @_ as-is for the benefit of
119 # Sub::Exporter.
120 my $class = $_[0];
1a601f52 121
e05b7c8e 122 $CALLER = Moose::Exporter::_get_caller(@_);
1a601f52 123
e05b7c8e 124 # this works because both pragmas set $^H (see perldoc
125 # perlvar) which affects the current compilation -
126 # i.e. the file who use'd us - which is why we don't need
127 # to do anything special to make it affect that file
128 # rather than this one (which is already compiled)
129
130 strict->import;
131 warnings->import;
132
133 # we should never export to main
134 if ( $CALLER eq 'main' ) {
135 warn
136 qq{$class does not export its sugar to the 'main' package.\n};
137 return;
138 }
1a601f52 139
e05b7c8e 140 if ( $class->can('_init_meta') ) {
141 $class->_init_meta(
142 for_class => $CALLER,
143 %{ $init_meta_args || {} }
144 );
145 }
146
147 goto $exporter;
148 };
149 }
1a601f52 150}
151
152sub _get_caller {
153 # 1 extra level because it's called by import so there's a layer
154 # of indirection
155 my $offset = 1;
156
157 return
158 ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
159 : ( ref $_[1] && defined $_[1]->{into_level} )
160 ? caller( $offset + $_[1]->{into_level} )
161 : caller($offset);
162}
163
164sub _make_unimport_sub {
165 my $class = shift;
166 my $exported = shift;
167
168 # [12:24] <mst> yes. that's horrible. I know. but it should work.
169 #
170 # This will hopefully be replaced in the future once
171 # namespace::clean has an API for it.
172 return sub {
173 @_ = ( 'namespace::clean', @{$exported} );
174
175 goto &namespace::clean::import;
176 };
177}
178
5bd4db9b 1791;
2f29843c 180
181__END__
182
183=head1 NAME
184
185Moose::Exporter - make an import() and unimport() just like Moose.pm
186
187=head1 SYNOPSIS
188
189 package MyApp::Moose;
190
191 use strict;
192 use warnings;
193
194 use Moose ();
195 use Moose::Exporter;
196
197 Moose::Exporter->build_export_methods(
198 export => [ 'sugar1', 'sugar2', \&Some::Random::thing ],
199 init_meta_args => { metaclass_class => 'MyApp::Meta::Class' ],
200 );
201
202 # then later ...
203 package MyApp::User;
204
205 use MyApp::Moose;
206
207 has 'name';
208 sugar1 'do your thing';
209 thing;
210
211 no MyApp::Moose;
212
213=head1 DESCRIPTION
214
215This module encapsulates the logic to export sugar functions like
216C<Moose.pm>. It does this by building custom C<import> and C<unimport>
217methods for your module, based on a spec your provide.
218
219It also lets your "stack" Moose-alike modules so you can export
220Moose's sugar as well as your own, along with sugar from any random
221C<MooseX> module, as long as they all use C<Moose::Exporter>.
222
223=head1 METHODS
224
225This module provides exactly one public method:
226
227=head2 Moose::Exporter->build_import_methods(...)
228
229When you call this method, C<Moose::Exporter> build custom C<import>
230and C<unimport> methods for your module. The import method will export
231the functions you specify, and you can also tell it to export
232functions exported by some other module (like C<Moose.pm>).
233
234The C<unimport> method cleans the callers namespace of all the
235exported functions.
236
237This method accepts the following parameters:
238
239=over 4
240
97a93056 241=item * with_caller => [ ... ]
242
243This a list of function I<names only> to be exported wrapped and then
244exported. The wrapper will pass the name of the calling package as the
245first argument to the function. Many sugar functions need to know
246their caller so they can get the calling package's metaclass object.
247
248=item * as_is => [ ... ]
2f29843c 249
250This a list of function names or sub references to be exported
251as-is. You can identify a subroutine by reference, which is handy to
252re-export some other module's functions directly by reference
253(C<\&Some::Package::function>).
254
255=item * init_meta_args
256
257...
258
259=back
260
261=head1 AUTHOR
262
263Dave Rolsky E<lt>autarch@urth.orgE<gt>
264
265This is largely a reworking of code in Moose.pm originally written by
266Stevan Little and others.
267
268=head1 COPYRIGHT AND LICENSE
269
270Copyright 2008 by Infinity Interactive, Inc.
271
272L<http://www.iinteractive.com>
273
274This library is free software; you can redistribute it and/or modify
275it under the same terms as Perl itself.
276
277=cut