tests
[gitmo/Moose.git] / lib / Class / MOP / Package.pm
CommitLineData
38bf2a25 1
2package Class::MOP::Package;
3
4use strict;
5use warnings;
6
0db1c8dc 7use Scalar::Util 'blessed', 'reftype', 'weaken';
38bf2a25 8use Carp 'confess';
0db1c8dc 9use Devel::GlobalDestruction 'in_global_destruction';
38bf2a25 10use Package::Stash;
11
38bf2a25 12use base 'Class::MOP::Object';
13
14# creation ...
15
16sub initialize {
17 my ( $class, @args ) = @_;
18
19 unshift @args, "package" if @args % 2;
20
21 my %options = @args;
0db1c8dc 22 my $package_name = delete $options{package};
38bf2a25 23
24
25 # we hand-construct the class
26 # until we can bootstrap it
27 if ( my $meta = Class::MOP::get_metaclass_by_name($package_name) ) {
28 return $meta;
29 } else {
30 my $meta = ( ref $class || $class )->_new({
31 'package' => $package_name,
32 %options,
33 });
34 Class::MOP::store_metaclass_by_name($package_name, $meta);
35
0db1c8dc 36 Class::MOP::weaken_metaclass($package_name) if $options{weaken};
37
38
38bf2a25 39 return $meta;
40 }
41}
42
43sub reinitialize {
44 my ( $class, @args ) = @_;
45
46 unshift @args, "package" if @args % 2;
47
48 my %options = @args;
49 my $package_name = delete $options{package};
50
51 (defined $package_name && $package_name
52 && (!blessed $package_name || $package_name->isa('Class::MOP::Package')))
53 || confess "You must pass a package name or an existing Class::MOP::Package instance";
54
55 $package_name = $package_name->name
56 if blessed $package_name;
57
58 Class::MOP::remove_metaclass_by_name($package_name);
59
60 $class->initialize($package_name, %options); # call with first arg form for compat
61}
62
0db1c8dc 63sub create {
64 my $class = shift;
65 my @args = @_;
66
67 return $class->initialize(@args);
68}
69
70## ANON packages
71
72{
73 # NOTE:
74 # this should be sufficient, if you have a
75 # use case where it is not, write a test and
76 # I will change it.
77 my $ANON_SERIAL = 0;
78
79 my %ANON_PACKAGE_CACHE;
80
81 # NOTE:
82 # we need a sufficiently annoying prefix
83 # this should suffice for now, this is
84 # used in a couple of places below, so
85 # need to put it up here for now.
86 sub _anon_package_prefix { 'Class::MOP::Package::__ANON__::SERIAL::' }
87
88 sub is_anon {
89 my $self = shift;
90 no warnings 'uninitialized';
91 my $prefix = $self->_anon_package_prefix;
92 $self->name =~ /^$prefix/;
93 }
94
95 sub create_anon {
96 my ($class, %options) = @_;
97
98 my $cache_ok = delete $options{cache};
99
4f629382 100 my $cache_key;
101 if ($cache_ok) {
102 $cache_key = $class->_anon_cache_key(%options);
0db1c8dc 103
4f629382 104 if (defined $ANON_PACKAGE_CACHE{$cache_key}) {
105 return $ANON_PACKAGE_CACHE{$cache_key};
106 }
0db1c8dc 107 }
108
109 $options{weaken} = !$cache_ok unless exists $options{weaken};
110
111 my $package_name = $class->_anon_package_prefix . ++$ANON_SERIAL;
112
113 my $meta = $class->create($package_name, %options);
114
115 if ($cache_ok) {
116 $ANON_PACKAGE_CACHE{$cache_key} = $meta;
117 weaken($ANON_PACKAGE_CACHE{$cache_key});
118 }
119
120 return $meta;
121 }
122
123 sub _anon_cache_key { confess "Packages are not cacheable" }
124
125 sub DESTROY {
126 my $self = shift;
127
128 return if in_global_destruction(); # it'll happen soon anyway and this just makes things more complicated
129
130 $self->_free_anon
131 if $self->is_anon;
132 }
133
134 sub _free_anon {
135 my $self = shift;
136 my $name = $self->name;
137
138 # Moose does a weird thing where it replaces the metaclass for
139 # class when fixing metaclass incompatibility. In that case,
140 # we don't want to clean out the namespace now. We can detect
141 # that because Moose will explicitly update the singleton
142 # cache in Class::MOP.
143 no warnings 'uninitialized';
144 my $current_meta = Class::MOP::get_metaclass_by_name($name);
145 return if $current_meta ne $self;
146
147 my ($first_fragments, $last_fragment) = ($name =~ /^(.*)::(.*)$/);
148
149 no strict 'refs';
150 @{$name . '::ISA'} = ();
151 %{$name . '::'} = ();
152 delete ${$first_fragments . '::'}{$last_fragment . '::'};
153
154 Class::MOP::remove_metaclass_by_name($name);
155 }
156
157}
158
38bf2a25 159sub _new {
160 my $class = shift;
161
162 return Class::MOP::Class->initialize($class)->new_object(@_)
163 if $class ne __PACKAGE__;
164
165 my $params = @_ == 1 ? $_[0] : {@_};
166
167 return bless {
9c1bf11e 168 # Need to quote package to avoid a problem with PPI mis-parsing this
169 # as a package statement.
170 'package' => $params->{package},
38bf2a25 171
172 # NOTE:
173 # because of issues with the Perl API
174 # to the typeglob in some versions, we
175 # need to just always grab a new
176 # reference to the hash in the accessor.
177 # Ideally we could just store a ref and
178 # it would Just Work, but oh well :\
179
180 namespace => \undef,
181
182 } => $class;
183}
184
185# Attributes
186
187# NOTE:
188# all these attribute readers will be bootstrapped
189# away in the Class::MOP bootstrap section
190
191sub _package_stash {
192 $_[0]->{_package_stash} ||= Package::Stash->new($_[0]->name)
193}
194sub namespace {
195 $_[0]->_package_stash->namespace
196}
197
198# Class attributes
199
200# ... these functions have to touch the symbol table itself,.. yuk
201
202sub add_package_symbol {
203 my $self = shift;
204 $self->_package_stash->add_symbol(@_);
205}
206
207sub remove_package_glob {
208 my $self = shift;
209 $self->_package_stash->remove_glob(@_);
210}
211
212# ... these functions deal with stuff on the namespace level
213
214sub has_package_symbol {
215 my $self = shift;
216 $self->_package_stash->has_symbol(@_);
217}
218
219sub get_package_symbol {
220 my $self = shift;
221 $self->_package_stash->get_symbol(@_);
222}
223
224sub get_or_add_package_symbol {
225 my $self = shift;
226 $self->_package_stash->get_or_add_symbol(@_);
227}
228
229sub remove_package_symbol {
230 my $self = shift;
231 $self->_package_stash->remove_symbol(@_);
232}
233
234sub list_all_package_symbols {
235 my $self = shift;
236 $self->_package_stash->list_all_symbols(@_);
237}
238
239sub get_all_package_symbols {
240 my $self = shift;
241 $self->_package_stash->get_all_symbols(@_);
242}
243
2441;
245
246# ABSTRACT: Package Meta Object
247
248__END__
249
250=pod
251
252=head1 DESCRIPTION
253
254The Package Protocol provides an abstraction of a Perl 5 package. A
255package is basically namespace, and this module provides methods for
256looking at and changing that namespace's symbol table.
257
258=head1 METHODS
259
260=over 4
261
262=item B<< Class::MOP::Package->initialize($package_name) >>
263
264This method creates a new C<Class::MOP::Package> instance which
265represents specified package. If an existing metaclass object exists
266for the package, that will be returned instead.
267
268=item B<< Class::MOP::Package->reinitialize($package) >>
269
270This method forcibly removes any existing metaclass for the package
271before calling C<initialize>. In contrast to C<initialize>, you may
272also pass an existing C<Class::MOP::Package> instance instead of just
273a package name as C<$package>.
274
275Do not call this unless you know what you are doing.
276
277=item B<< $metapackage->name >>
278
279This is returns the package's name, as passed to the constructor.
280
281=item B<< $metapackage->namespace >>
282
283This returns a hash reference to the package's symbol table. The keys
284are symbol names and the values are typeglob references.
285
286=item B<< $metapackage->add_package_symbol($variable_name, $initial_value) >>
287
288This method accepts a variable name and an optional initial value. The
289C<$variable_name> must contain a leading sigil.
290
291This method creates the variable in the package's symbol table, and
292sets it to the initial value if one was provided.
293
294=item B<< $metapackage->get_package_symbol($variable_name) >>
295
296Given a variable name, this method returns the variable as a reference
297or undef if it does not exist. The C<$variable_name> must contain a
298leading sigil.
299
300=item B<< $metapackage->get_or_add_package_symbol($variable_name) >>
301
302Given a variable name, this method returns the variable as a reference.
303If it does not exist, a default value will be generated if possible. The
304C<$variable_name> must contain a leading sigil.
305
306=item B<< $metapackage->has_package_symbol($variable_name) >>
307
308Returns true if there is a package variable defined for
309C<$variable_name>. The C<$variable_name> must contain a leading sigil.
310
311=item B<< $metapackage->remove_package_symbol($variable_name) >>
312
313This will remove the package variable specified C<$variable_name>. The
314C<$variable_name> must contain a leading sigil.
315
316=item B<< $metapackage->remove_package_glob($glob_name) >>
317
318Given the name of a glob, this will remove that glob from the
319package's symbol table. Glob names do not include a sigil. Removing
320the glob removes all variables and subroutines with the specified
321name.
322
323=item B<< $metapackage->list_all_package_symbols($type_filter) >>
324
325This will list all the glob names associated with the current
326package. These names do not have leading sigils.
327
328You can provide an optional type filter, which should be one of
329'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
330
331=item B<< $metapackage->get_all_package_symbols($type_filter) >>
332
333This works much like C<list_all_package_symbols>, but it returns a
334hash reference. The keys are glob names and the values are references
335to the value for that name.
336
337=item B<< Class::MOP::Package->meta >>
338
339This will return a L<Class::MOP::Class> instance for this class.
340
341=back
342
343=cut