use strict;
use warnings;
-use Carp 'confess';
-use Scalar::Util 'weaken';
+use MRO::Compat;
+
+use Carp 'confess';
+use Scalar::Util 'weaken';
use Class::MOP::Class;
use Class::MOP::Attribute;
use Class::MOP::Immutable;
-our $VERSION = '0.49';
-our $AUTHORITY = 'cpan:STEVAN';
+BEGIN {
+ our $VERSION = '0.56';
+ our $AUTHORITY = 'cpan:STEVAN';
+
+ *IS_RUNNING_ON_5_10 = ($] < 5.009_005)
+ ? sub () { 0 }
+ : sub () { 1 };
-use XSLoader;
-XSLoader::load( 'Class::MOP', $VERSION );
+ # NOTE:
+ # we may not use this yet, but once
+ # the get_code_info XS gets merged
+ # upstream to it, we will always use
+ # it. But for now it is just kinda
+ # extra overhead.
+ # - SL
+ require Sub::Identify;
+
+ # stash these for a sec, and see how things go
+ my $_PP_subname = sub { $_[1] };
+ my $_PP_get_code_info = sub ($) {
+ return (
+ Sub::Identify::stash_name($_[0]),
+ Sub::Identify::sub_name($_[0])
+ )
+ };
+
+ if ($ENV{CLASS_MOP_NO_XS} == 1) {
+ # NOTE:
+ # this is if you really want things
+ # to be slow, then you can force the
+ # no-XS rule this way, otherwise we
+ # make an effort to load as much of
+ # the XS as possible.
+ # - SL
+ no warnings 'prototype', 'redefine';
+ # get this from MRO::Compat ...
+ *check_package_cache_flag = \&MRO::Compat::__get_pkg_gen_pp;
+ # our own version of Sub::Name
+ *subname = $_PP_subname;
+ # and the Sub::Identify version of the get_code_info
+ *get_code_info = $_PP_get_code_info;
+ }
+ else {
+ # now try our best to get as much
+ # of the XS loaded as possible
+ {
+ local $@;
+ eval {
+ require XSLoader;
+ XSLoader::load( 'Class::MOP', $VERSION );
+ };
+ die $@ if $@ && $@ !~ /object version|loadable object/;
+
+ # okay, so the XS failed to load, so
+ # use the pure perl one instead.
+ *get_code_info = $_PP_get_code_info if $@;
+ }
+
+ # get it from MRO::Compat
+ *check_package_cache_flag = \&mro::get_pkg_gen;
+
+ # now try and load the Sub::Name
+ # module and use that as a means
+ # for naming our CVs, if not, we
+ # use the workaround instead.
+ if ( eval { require Sub::Name } ) {
+ *subname = sub {
+ #warn "Class::MOP::subname called with @_";
+ Sub::Name::subname(@_);
+ };
+ }
+ else {
+ *subname = $_PP_subname;
+ }
+ }
+}
{
# Metaclasses are singletons, so we cache them here.
}
sub is_class_loaded {
- my $class = shift;
- no strict 'refs';
- return 1 if defined ${"${class}::VERSION"} || defined @{"${class}::ISA"};
- foreach (keys %{"${class}::"}) {
- next if substr($_, -2, 2) eq '::';
- return 1 if defined &{"${class}::$_"};
- }
- return 0;
+ my $class = shift;
+ no strict 'refs';
+ return 1 if defined ${"${class}::VERSION"} || defined @{"${class}::ISA"};
+ foreach my $symbol (keys %{"${class}::"}) {
+ next if substr($symbol, -2, 2) eq '::';
+ return 1 if defined &{"${class}::${symbol}"};
+ }
+ return 0;
}
# rather than re-produce it here
'namespace' => \&Class::MOP::Package::namespace
},
- # NOTE:
- # protect this from silliness
- init_arg => '!............( DO NOT DO THIS )............!',
+ init_arg => undef,
default => sub { \undef }
))
);
# rather than re-produce it here
'version' => \&Class::MOP::Module::version
},
- # NOTE:
- # protect this from silliness
- init_arg => '!............( DO NOT DO THIS )............!',
+ init_arg => undef,
default => sub { \undef }
))
);
# rather than re-produce it here
'authority' => \&Class::MOP::Module::authority
},
- # NOTE:
- # protect this from silliness
- init_arg => '!............( DO NOT DO THIS )............!',
+ init_arg => undef,
default => sub { \undef }
))
);
# rather than re-produce it here
'superclasses' => \&Class::MOP::Class::superclasses
},
- # NOTE:
- # protect this from silliness
- init_arg => '!............( DO NOT DO THIS )............!',
+ init_arg => undef,
default => sub { \undef }
))
);
);
Class::MOP::Attribute->meta->add_attribute(
+ Class::MOP::Attribute->new('$!initializer' => (
+ init_arg => 'initializer',
+ reader => { 'initializer' => \&Class::MOP::Attribute::initializer },
+ predicate => { 'has_initializer' => \&Class::MOP::Attribute::has_initializer },
+ ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
Class::MOP::Attribute->new('$!writer' => (
init_arg => 'writer',
reader => { 'writer' => \&Class::MOP::Attribute::writer },
} else {
(Class::MOP::Attribute::is_default_a_coderef(\%options))
|| confess("References are not allowed as default values, you must ".
- "wrap then in a CODE reference (ex: sub { [] } and not [])")
+ "wrap the default of '$name' in a CODE reference (ex: sub { [] } and not [])")
if exists $options{default} && ref $options{default};
}
# return the new object
))
);
+Class::MOP::Method->meta->add_attribute(
+ Class::MOP::Attribute->new('$!package_name' => (
+ init_arg => 'package_name',
+ reader => { 'package_name' => \&Class::MOP::Method::package_name },
+ ))
+);
+
+Class::MOP::Method->meta->add_attribute(
+ Class::MOP::Attribute->new('$!name' => (
+ init_arg => 'name',
+ reader => { 'name' => \&Class::MOP::Method::name },
+ ))
+);
+
+Class::MOP::Method->meta->add_method('wrap' => sub {
+ my $class = shift;
+ my $code = shift;
+ my %options = @_;
+
+ ('CODE' eq (Scalar::Util::reftype($code) || ''))
+ || confess "You must supply a CODE reference to bless, not (" . ($code || 'undef') . ")";
+
+ # return the new object
+ $class->meta->new_object(body => $code, %options);
+});
+
+Class::MOP::Method->meta->add_method('clone' => sub {
+ my $self = shift;
+ $self->meta->clone_object($self, @_);
+});
+
## --------------------------------------------------------
## Class::MOP::Method::Wrapped
Class::MOP::Attribute->new('$!is_inline' => (
init_arg => 'is_inline',
reader => { 'is_inline' => \&Class::MOP::Method::Generated::is_inline },
+ default => 0,
))
);
+Class::MOP::Method::Generated->meta->add_method('new' => sub {
+ my ($class, %options) = @_;
+ my $self = $class->meta->new_object(%options);
+ $self->initialize_body;
+ $self;
+});
+
## --------------------------------------------------------
## Class::MOP::Method::Accessor
))
);
+Class::MOP::Method::Accessor->meta->add_method('new' => sub {
+ my $class = shift;
+ my %options = @_;
+
+ (exists $options{attribute})
+ || confess "You must supply an attribute to construct with";
+
+ (exists $options{accessor_type})
+ || confess "You must supply an accessor_type to construct with";
+
+ (Scalar::Util::blessed($options{attribute}) && $options{attribute}->isa('Class::MOP::Attribute'))
+ || confess "You must supply an attribute which is a 'Class::MOP::Attribute' instance";
+
+ # return the new object
+ my $self = $class->meta->new_object(%options);
+
+ # we don't want this creating
+ # a cycle in the code, if not
+ # needed
+ Scalar::Util::weaken($self->{'$!attribute'});
+
+ $self->initialize_body;
+
+ $self;
+});
+
## --------------------------------------------------------
## Class::MOP::Method::Constructor
reader => {
'options' => \&Class::MOP::Method::Constructor::options
},
+ default => sub { +{} }
))
);
))
);
+Class::MOP::Method::Constructor->meta->add_method('new' => sub {
+ my $class = shift;
+ my %options = @_;
+
+ (Scalar::Util::blessed $options{metaclass} && $options{metaclass}->isa('Class::MOP::Class'))
+ || confess "You must pass a metaclass instance if you want to inline"
+ if $options{is_inline};
+
+ # return the new object
+ my $self = $class->meta->new_object(%options);
+
+ # we don't want this creating
+ # a cycle in the code, if not
+ # needed
+ Scalar::Util::weaken($self->{'$!associated_metaclass'});
+
+ $self->initialize_body;
+
+ $self;
+});
+
## --------------------------------------------------------
## Class::MOP::Instance
=head1 DESCRIPTON
-This module is an attempt to create a meta object protocol for the
+This module is a fully functioning meta object protocol for the
Perl 5 object system. It makes no attempt to change the behavior or
characteristics of the Perl 5 object system, only to create a
protocol for its manipulation and introspection.
=head1 PROTOCOLS
-The protocol is divided into 3 main sub-protocols:
+The protocol is divided into 4 main sub-protocols:
=over 4
This provides a consistent represenation for an attribute of a
Perl 5 class. Since there are so many ways to create and handle
-atttributes in Perl 5 OO, this attempts to provide as much of a
+attributes in Perl 5 OO, this attempts to provide as much of a
unified approach as possible, while giving the freedom and
flexibility to subclass for specialization.
See L<Class::MOP::Method> for more details.
+=item The Instance protocol
+
+This provides a layer of abstraction for creating object instances.
+Since the other layers use this protocol, it is relatively easy to
+change the type of your instances from the default HASH ref to other
+types of references. Several examples are provided in the F<examples/>
+directory included in this distribution.
+
+See L<Class::MOP::Instance> for more details.
+
=back
=head1 FUNCTIONS
+=head2 Constants
+
+=over 4
+
+=item I<IS_RUNNING_ON_5_10>
+
+We set this constant depending on what version perl we are on, this
+allows us to take advantage of new 5.10 features and stay backwards
+compat.
+
+=back
+
=head2 Utility functions
=over 4
This will load a given C<$class_name> and if it does not have an
already initialized metaclass, then it will intialize one for it.
+This function can be used in place of tricks like
+C<eval "use $module"> or using C<require>.
=item B<is_class_loaded ($class_name)>
determine as best it can if the C<$class_name> is loaded, it
is probably correct about 99% of the time.
-=item B<check_package_cache_flag>
+=item B<check_package_cache_flag ($pkg)>
+
+This will return an integer that is managed by C<Class::MOP::Class>
+to determine if a module's symbol table has been altered.
+
+In Perl 5.10 or greater, this flag is package specific. However in
+versions prior to 5.10, this will use the C<PL_sub_generation> variable
+which is not package specific.
=item B<get_code_info ($code)>
+This function returns two values, the name of the package the C<$code>
+is from and the name of the C<$code> itself. This is used by several
+elements of the MOP to detemine where a given C<$code> reference is from.
+
+=item B<subname ($name, $code)>
+
+B<NOTE: DO NOT USE THIS FUNCTION, IT IS FOR INTERNAL USE ONLY!>
+
+If possible, we will load the L<Sub::Name> module and this will function
+as C<Sub::Name::subname> does, otherwise it will just return the C<$code>
+argument.
+
=back
=head2 Metaclass cache functions
=item B<get_metaclass_by_name ($name)>
+This will return a cached B<Class::MOP::Class> instance of nothing
+if no metaclass exist by that C<$name>.
+
=item B<store_metaclass_by_name ($name, $meta)>
+This will store a metaclass in the cache at the supplied C<$key>.
+
=item B<weaken_metaclass ($name)>
+In rare cases it is desireable to store a weakened reference in
+the metaclass cache. This function will weaken the reference to
+the metaclass stored in C<$name>.
+
=item B<does_metaclass_exist ($name)>
+This will return true of there exists a metaclass stored in the
+C<$name> key and return false otherwise.
+
=item B<remove_metaclass_by_name ($name)>
+This will remove a the metaclass stored in the C<$name> key.
+
=back
=head1 SEE ALSO
Yuval (nothingmuch) Kogman
+Scott (konobi) McWhirter
+
=head1 COPYRIGHT AND LICENSE
-Copyright 2006, 2007 by Infinity Interactive, Inc.
+Copyright 2006-2008 by Infinity Interactive, Inc.
L<http://www.iinteractive.com>