I realized that all the "with caller" wrapper stuff is pointless. We
[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
1a601f52 21 my ( $exporter, $exported ) = $class->_build_exporter(
22 exporting_package => $exporting_package,
23 %args
24 );
a5c426fc 25
1a601f52 26 my $import = $class->_make_import_sub(
2f29843c 27 $exporting_package,
28 $args{init_meta_args},
1a601f52 29 $exporter
30 );
a5c426fc 31
1a601f52 32 my $unimport = $class->_make_unimport_sub($exported);
a5c426fc 33
34 no strict 'refs';
1a601f52 35 *{ $exporting_package . '::import' } = $import;
a5c426fc 36 *{ $exporting_package . '::unimport' } = $unimport;
37}
38
5bd4db9b 39my %EXPORTED;
a5c426fc 40sub _build_exporter {
5bd4db9b 41 my $class = shift;
42 my %args = @_;
43
a5c426fc 44 my $exporting_package = $args{exporting_package};
5bd4db9b 45
0338a411 46 my @exported_names;
5bd4db9b 47 my %exports;
2f29843c 48 for my $name ( @{ $args{export} } ) {
5bd4db9b 49 my $sub;
5bd4db9b 50 if ( ref $name ) {
51 $sub = $name;
52 $name = ( Class::MOP::get_code_info($name) )[1];
53 }
54 else {
a5c426fc 55 $sub = do { no strict 'refs'; \&{ $exporting_package . '::' . $name } };
5bd4db9b 56
0338a411 57 push @exported_names, $name;
5bd4db9b 58 }
59
60 $exports{$name} = sub { $sub };
2f29843c 61
62 push @exported_names, $name;
5bd4db9b 63 }
64
0338a411 65 my $exporter = Sub::Exporter::build_exporter(
5bd4db9b 66 {
67 exports => \%exports,
68 groups => { default => [':all'] }
69 }
70 );
5bd4db9b 71
0338a411 72 return $exporter, \@exported_names;
5bd4db9b 73}
74
1a601f52 75sub _make_import_sub {
76 my $class = shift;
77 my $exporting_package = shift;
78 my $init_meta_args = shift;
79 my $exporter = shift;
80
81 return sub {
82 my $caller = Moose::Exporter->_get_caller(@_);
83
84 # this works because both pragmas set $^H (see perldoc perlvar)
85 # which affects the current compilation - i.e. the file who use'd
86 # us - which is why we don't need to do anything special to make
87 # it affect that file rather than this one (which is already compiled)
88
89 strict->import;
90 warnings->import;
91
92 # we should never export to main
93 if ( $caller eq 'main' ) {
94 warn
95 qq{$exporting_package does not export its sugar to the 'main' package.\n};
96 return;
97 }
98
99 if ( $exporting_package->can('_init_meta') ) {
100 $exporting_package->_init_meta(
2f29843c 101 %{ $init_meta_args || {} },
1a601f52 102 for_class => $caller,
1a601f52 103 );
104 }
105
106 goto $exporter;
107 };
108}
109
110sub _get_caller {
111 # 1 extra level because it's called by import so there's a layer
112 # of indirection
113 my $offset = 1;
114
115 return
116 ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
117 : ( ref $_[1] && defined $_[1]->{into_level} )
118 ? caller( $offset + $_[1]->{into_level} )
119 : caller($offset);
120}
121
122sub _make_unimport_sub {
123 my $class = shift;
124 my $exported = shift;
125
126 # [12:24] <mst> yes. that's horrible. I know. but it should work.
127 #
128 # This will hopefully be replaced in the future once
129 # namespace::clean has an API for it.
130 return sub {
131 @_ = ( 'namespace::clean', @{$exported} );
132
133 goto &namespace::clean::import;
134 };
135}
136
5bd4db9b 1371;
2f29843c 138
139__END__
140
141=head1 NAME
142
143Moose::Exporter - make an import() and unimport() just like Moose.pm
144
145=head1 SYNOPSIS
146
147 package MyApp::Moose;
148
149 use strict;
150 use warnings;
151
152 use Moose ();
153 use Moose::Exporter;
154
155 Moose::Exporter->build_export_methods(
156 export => [ 'sugar1', 'sugar2', \&Some::Random::thing ],
157 init_meta_args => { metaclass_class => 'MyApp::Meta::Class' ],
158 );
159
160 # then later ...
161 package MyApp::User;
162
163 use MyApp::Moose;
164
165 has 'name';
166 sugar1 'do your thing';
167 thing;
168
169 no MyApp::Moose;
170
171=head1 DESCRIPTION
172
173This module encapsulates the logic to export sugar functions like
174C<Moose.pm>. It does this by building custom C<import> and C<unimport>
175methods for your module, based on a spec your provide.
176
177It also lets your "stack" Moose-alike modules so you can export
178Moose's sugar as well as your own, along with sugar from any random
179C<MooseX> module, as long as they all use C<Moose::Exporter>.
180
181=head1 METHODS
182
183This module provides exactly one public method:
184
185=head2 Moose::Exporter->build_import_methods(...)
186
187When you call this method, C<Moose::Exporter> build custom C<import>
188and C<unimport> methods for your module. The import method will export
189the functions you specify, and you can also tell it to export
190functions exported by some other module (like C<Moose.pm>).
191
192The C<unimport> method cleans the callers namespace of all the
193exported functions.
194
195This method accepts the following parameters:
196
197=over 4
198
199=item * export => [ ... ]
200
201This a list of function names or sub references to be exported
202as-is. You can identify a subroutine by reference, which is handy to
203re-export some other module's functions directly by reference
204(C<\&Some::Package::function>).
205
206=item * init_meta_args
207
208...
209
210=back
211
212=head1 AUTHOR
213
214Dave Rolsky E<lt>autarch@urth.orgE<gt>
215
216This is largely a reworking of code in Moose.pm originally written by
217Stevan Little and others.
218
219=head1 COPYRIGHT AND LICENSE
220
221Copyright 2008 by Infinity Interactive, Inc.
222
223L<http://www.iinteractive.com>
224
225This library is free software; you can redistribute it and/or modify
226it under the same terms as Perl itself.
227
228=cut