Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,172 @@
package Class::MOP::Class::Immutable::Trait;
our $VERSION = '2.2014';
use strict;
use warnings;
use MRO::Compat;
use Module::Runtime 'use_module';
# the original class of the metaclass instance
sub _get_mutable_metaclass_name { $_[0]{__immutable}{original_class} }
sub is_mutable { 0 }
sub is_immutable { 1 }
sub _immutable_metaclass { ref $_[1] }
sub _immutable_read_only {
my $name = shift;
__throw_exception( CallingReadOnlyMethodOnAnImmutableInstance => method_name => $name );
}
sub _immutable_cannot_call {
my $name = shift;
__throw_exception( CallingMethodOnAnImmutableInstance => method_name => $name );
}
for my $name (qw/superclasses/) {
no strict 'refs';
*{__PACKAGE__."::$name"} = sub {
my $orig = shift;
my $self = shift;
_immutable_read_only($name) if @_;
$self->$orig;
};
}
for my $name (qw/add_method alias_method remove_method add_attribute remove_attribute remove_package_symbol add_package_symbol/) {
no strict 'refs';
*{__PACKAGE__."::$name"} = sub { _immutable_cannot_call($name) };
}
sub class_precedence_list {
my $orig = shift;
my $self = shift;
@{ $self->{__immutable}{class_precedence_list}
||= [ $self->$orig ] };
}
sub linearized_isa {
my $orig = shift;
my $self = shift;
@{ $self->{__immutable}{linearized_isa} ||= [ $self->$orig ] };
}
sub get_all_methods {
my $orig = shift;
my $self = shift;
@{ $self->{__immutable}{get_all_methods} ||= [ $self->$orig ] };
}
sub get_all_method_names {
my $orig = shift;
my $self = shift;
@{ $self->{__immutable}{get_all_method_names} ||= [ $self->$orig ] };
}
sub get_all_attributes {
my $orig = shift;
my $self = shift;
@{ $self->{__immutable}{get_all_attributes} ||= [ $self->$orig ] };
}
sub get_meta_instance {
my $orig = shift;
my $self = shift;
$self->{__immutable}{get_meta_instance} ||= $self->$orig;
}
sub _method_map {
my $orig = shift;
my $self = shift;
$self->{__immutable}{_method_map} ||= $self->$orig;
}
# private method, for this file only -
# if we declare a method here, it will behave differently depending on what
# class this trait is applied to, so we won't have a reliable parameter list.
sub __throw_exception {
my ($exception_type, @args_to_exception) = @_;
die use_module( "Moose::Exception::$exception_type" )->new( @args_to_exception );
}
1;
# ABSTRACT: Implements immutability for metaclass objects
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Class::Immutable::Trait - Implements immutability for metaclass objects
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This class provides a pseudo-trait that is applied to immutable metaclass
objects. In reality, it is simply a parent class.
It implements caching and read-only-ness for various metaclass methods.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,95 @@
package Class::MOP::Deprecated;
our $VERSION = '2.2014';
use strict;
use warnings;
use Package::DeprecationManager -deprecations => {
'Class::Load wrapper functions' => '2.1100',
};
1;
# ABSTRACT: Manages deprecation warnings for Class::MOP
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Deprecated - Manages deprecation warnings for Class::MOP
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
use Class::MOP::Deprecated -api_version => $version;
=head1 FUNCTIONS
This module manages deprecation warnings for features that have been
deprecated in Class::MOP.
If you specify C<< -api_version => $version >>, you can use deprecated features
without warnings. Note that this special treatment is limited to the package
that loads C<Class::MOP::Deprecated>.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,533 @@
package Class::MOP::Instance;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'isweak', 'weaken', 'blessed';
use parent 'Class::MOP::Object';
# make this not a valid method name, to avoid (most) attribute conflicts
my $RESERVED_MOP_SLOT = '<<MOP>>';
sub BUILDARGS {
my ($class, @args) = @_;
if ( @args == 1 ) {
unshift @args, "associated_metaclass";
} elsif ( @args >= 2 && blessed($args[0]) && $args[0]->isa("Class::MOP::Class") ) {
# compat mode
my ( $meta, @attrs ) = @args;
@args = ( associated_metaclass => $meta, attributes => \@attrs );
}
my %options = @args;
# FIXME lazy_build
$options{slots} ||= [ map { $_->slots } @{ $options{attributes} || [] } ];
$options{slot_hash} = { map { $_ => undef } @{ $options{slots} } }; # FIXME lazy_build
return \%options;
}
sub new {
my $class = shift;
my $options = $class->BUILDARGS(@_);
# FIXME replace with a proper constructor
my $instance = $class->_new(%$options);
# FIXME weak_ref => 1,
weaken($instance->{'associated_metaclass'});
return $instance;
}
sub _new {
my $class = shift;
return Class::MOP::Class->initialize($class)->new_object(@_)
if $class ne __PACKAGE__;
my $params = @_ == 1 ? $_[0] : {@_};
return bless {
# NOTE:
# I am not sure that it makes
# sense to pass in the meta
# The ideal would be to just
# pass in the class name, but
# that is placing too much of
# an assumption on bless(),
# which is *probably* a safe
# assumption,.. but you can
# never tell <:)
'associated_metaclass' => $params->{associated_metaclass},
'attributes' => $params->{attributes},
'slots' => $params->{slots},
'slot_hash' => $params->{slot_hash},
} => $class;
}
sub _class_name { $_[0]->{_class_name} ||= $_[0]->associated_metaclass->name }
sub create_instance {
my $self = shift;
bless {}, $self->_class_name;
}
sub clone_instance {
my ($self, $instance) = @_;
my $clone = $self->create_instance;
for my $attr ($self->get_all_attributes) {
next unless $attr->has_value($instance);
for my $slot ($attr->slots) {
my $val = $self->get_slot_value($instance, $slot);
$self->set_slot_value($clone, $slot, $val);
$self->weaken_slot_value($clone, $slot)
if $self->slot_value_is_weak($instance, $slot);
}
}
$self->_set_mop_slot($clone, $self->_get_mop_slot($instance))
if $self->_has_mop_slot($instance);
return $clone;
}
# operations on meta instance
sub get_all_slots {
my $self = shift;
return @{$self->{'slots'}};
}
sub get_all_attributes {
my $self = shift;
return @{$self->{attributes}};
}
sub is_valid_slot {
my ($self, $slot_name) = @_;
exists $self->{'slot_hash'}->{$slot_name};
}
# operations on created instances
sub get_slot_value {
my ($self, $instance, $slot_name) = @_;
$instance->{$slot_name};
}
sub set_slot_value {
my ($self, $instance, $slot_name, $value) = @_;
$instance->{$slot_name} = $value;
}
sub initialize_slot {
my ($self, $instance, $slot_name) = @_;
return;
}
sub deinitialize_slot {
my ( $self, $instance, $slot_name ) = @_;
delete $instance->{$slot_name};
}
sub initialize_all_slots {
my ($self, $instance) = @_;
foreach my $slot_name ($self->get_all_slots) {
$self->initialize_slot($instance, $slot_name);
}
}
sub deinitialize_all_slots {
my ($self, $instance) = @_;
foreach my $slot_name ($self->get_all_slots) {
$self->deinitialize_slot($instance, $slot_name);
}
}
sub is_slot_initialized {
my ($self, $instance, $slot_name, $value) = @_;
exists $instance->{$slot_name};
}
sub weaken_slot_value {
my ($self, $instance, $slot_name) = @_;
weaken $instance->{$slot_name};
}
sub slot_value_is_weak {
my ($self, $instance, $slot_name) = @_;
isweak $instance->{$slot_name};
}
sub strengthen_slot_value {
my ($self, $instance, $slot_name) = @_;
$self->set_slot_value($instance, $slot_name, $self->get_slot_value($instance, $slot_name));
}
sub rebless_instance_structure {
my ($self, $instance, $metaclass) = @_;
# we use $_[1] here because of t/cmop/rebless_overload.t regressions
# on 5.8.8
bless $_[1], $metaclass->name;
}
sub is_dependent_on_superclasses {
return; # for meta instances that require updates on inherited slot changes
}
sub _get_mop_slot {
my ($self, $instance) = @_;
$self->get_slot_value($instance, $RESERVED_MOP_SLOT);
}
sub _has_mop_slot {
my ($self, $instance) = @_;
$self->is_slot_initialized($instance, $RESERVED_MOP_SLOT);
}
sub _set_mop_slot {
my ($self, $instance, $value) = @_;
$self->set_slot_value($instance, $RESERVED_MOP_SLOT, $value);
}
sub _clear_mop_slot {
my ($self, $instance) = @_;
$self->deinitialize_slot($instance, $RESERVED_MOP_SLOT);
}
# inlinable operation snippets
sub is_inlinable { 1 }
sub inline_create_instance {
my ($self, $class_variable) = @_;
'bless {} => ' . $class_variable;
}
sub inline_slot_access {
my ($self, $instance, $slot_name) = @_;
sprintf q[%s->{"%s"}], $instance, quotemeta($slot_name);
}
sub inline_get_is_lvalue { 1 }
sub inline_get_slot_value {
my ($self, $instance, $slot_name) = @_;
$self->inline_slot_access($instance, $slot_name);
}
sub inline_set_slot_value {
my ($self, $instance, $slot_name, $value) = @_;
$self->inline_slot_access($instance, $slot_name) . " = $value",
}
sub inline_initialize_slot {
my ($self, $instance, $slot_name) = @_;
return '';
}
sub inline_deinitialize_slot {
my ($self, $instance, $slot_name) = @_;
"delete " . $self->inline_slot_access($instance, $slot_name);
}
sub inline_is_slot_initialized {
my ($self, $instance, $slot_name) = @_;
"exists " . $self->inline_slot_access($instance, $slot_name);
}
sub inline_weaken_slot_value {
my ($self, $instance, $slot_name) = @_;
sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name);
}
sub inline_strengthen_slot_value {
my ($self, $instance, $slot_name) = @_;
$self->inline_set_slot_value($instance, $slot_name, $self->inline_slot_access($instance, $slot_name));
}
sub inline_rebless_instance_structure {
my ($self, $instance, $class_variable) = @_;
"bless $instance => $class_variable";
}
sub _inline_get_mop_slot {
my ($self, $instance) = @_;
$self->inline_get_slot_value($instance, $RESERVED_MOP_SLOT);
}
sub _inline_set_mop_slot {
my ($self, $instance, $value) = @_;
$self->inline_set_slot_value($instance, $RESERVED_MOP_SLOT, $value);
}
sub _inline_clear_mop_slot {
my ($self, $instance) = @_;
$self->inline_deinitialize_slot($instance, $RESERVED_MOP_SLOT);
}
1;
# ABSTRACT: Instance Meta Object
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Instance - Instance Meta Object
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
The Instance Protocol controls the creation of object instances, and
the storage of attribute values in those instances.
Using this API directly in your own code violates encapsulation, and
we recommend that you use the appropriate APIs in L<Class::MOP::Class>
and L<Class::MOP::Attribute> instead. Those APIs in turn call the
methods in this class as appropriate.
This class also participates in generating inlined code by providing
snippets of code to access an object instance.
=head1 METHODS
=head2 Object construction
=over 4
=item B<< Class::MOP::Instance->new(%options) >>
This method creates a new meta-instance object.
It accepts the following keys in C<%options>:
=over 8
=item * associated_metaclass
The L<Class::MOP::Class> object for which instances will be created.
=item * attributes
An array reference of L<Class::MOP::Attribute> objects. These are the
attributes which can be stored in each instance.
=back
=back
=head2 Creating and altering instances
=over 4
=item B<< $metainstance->create_instance >>
This method returns a reference blessed into the associated
metaclass's class.
The default is to use a hash reference. Subclasses can override this.
=item B<< $metainstance->clone_instance($instance) >>
Given an instance, this method creates a new object by making
I<shallow> clone of the original.
=back
=head2 Introspection
=over 4
=item B<< $metainstance->associated_metaclass >>
This returns the L<Class::MOP::Class> object associated with the
meta-instance object.
=item B<< $metainstance->get_all_slots >>
This returns a list of slot names stored in object instances. In
almost all cases, slot names correspond directly attribute names.
=item B<< $metainstance->is_valid_slot($slot_name) >>
This will return true if C<$slot_name> is a valid slot name.
=item B<< $metainstance->get_all_attributes >>
This returns a list of attributes corresponding to the attributes
passed to the constructor.
=back
=head2 Operations on Instance Structures
It's important to understand that the meta-instance object is a
different entity from the actual instances it creates. For this
reason, any operations on the C<$instance_structure> always require
that the object instance be passed to the method.
=over 4
=item B<< $metainstance->get_slot_value($instance_structure, $slot_name) >>
=item B<< $metainstance->set_slot_value($instance_structure, $slot_name, $value) >>
=item B<< $metainstance->initialize_slot($instance_structure, $slot_name) >>
=item B<< $metainstance->deinitialize_slot($instance_structure, $slot_name) >>
=item B<< $metainstance->initialize_all_slots($instance_structure) >>
=item B<< $metainstance->deinitialize_all_slots($instance_structure) >>
=item B<< $metainstance->is_slot_initialized($instance_structure, $slot_name) >>
=item B<< $metainstance->weaken_slot_value($instance_structure, $slot_name) >>
=item B<< $metainstance->slot_value_is_weak($instance_structure, $slot_name) >>
=item B<< $metainstance->strengthen_slot_value($instance_structure, $slot_name) >>
=item B<< $metainstance->rebless_instance_structure($instance_structure, $new_metaclass) >>
The exact details of what each method does should be fairly obvious
from the method name.
=back
=head2 Inlinable Instance Operations
=over 4
=item B<< $metainstance->is_inlinable >>
This is a boolean that indicates whether or not slot access operations
can be inlined. By default it is true, but subclasses can override
this.
=item B<< $metainstance->inline_create_instance($class_variable) >>
This method expects a string that, I<when inlined>, will become a
class name. This would literally be something like C<'$class'>, not an
actual class name.
It returns a snippet of code that creates a new object for the
class. This is something like C< bless {}, $class_name >.
=item B<< $metainstance->inline_get_is_lvalue >>
Returns whether or not C<inline_get_slot_value> is a valid lvalue. This can be
used to do extra optimizations when generating inlined methods.
=item B<< $metainstance->inline_slot_access($instance_variable, $slot_name) >>
=item B<< $metainstance->inline_get_slot_value($instance_variable, $slot_name) >>
=item B<< $metainstance->inline_set_slot_value($instance_variable, $slot_name, $value) >>
=item B<< $metainstance->inline_initialize_slot($instance_variable, $slot_name) >>
=item B<< $metainstance->inline_deinitialize_slot($instance_variable, $slot_name) >>
=item B<< $metainstance->inline_is_slot_initialized($instance_variable, $slot_name) >>
=item B<< $metainstance->inline_weaken_slot_value($instance_variable, $slot_name) >>
=item B<< $metainstance->inline_strengthen_slot_value($instance_variable, $slot_name) >>
These methods all expect two arguments. The first is the name of a
variable, than when inlined, will represent the object
instance. Typically this will be a literal string like C<'$_[0]'>.
The second argument is a slot name.
The method returns a snippet of code that, when inlined, performs some
operation on the instance.
=item B<< $metainstance->inline_rebless_instance_structure($instance_variable, $class_variable) >>
This takes the name of a variable that will, when inlined, represent the object
instance, and the name of a variable that will represent the class to rebless
into, and returns code to rebless an instance into a class.
=back
=head2 Introspection
=over 4
=item B<< Class::MOP::Instance->meta >>
This will return a L<Class::MOP::Class> instance for this class.
It should also be noted that L<Class::MOP> will actually bootstrap
this module by installing a number of attribute meta-objects into its
metaclass.
=back
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,356 @@
package Class::MOP::Method;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'weaken', 'reftype', 'blessed';
use parent 'Class::MOP::Object';
# NOTE:
# if poked in the right way,
# they should act like CODE refs.
use overload
'&{}' => sub { $_[0]->body },
'bool' => sub { 1 },
'""' => sub { overload::StrVal($_[0]) },
fallback => 1;
# construction
sub wrap {
my ( $class, @args ) = @_;
unshift @args, 'body' if @args % 2 == 1;
my %params = @args;
my $code = $params{body};
if (blessed($code) && $code->isa(__PACKAGE__)) {
my $method = $code->clone;
delete $params{body};
Class::MOP::class_of($class)->rebless_instance($method, %params);
return $method;
}
elsif (!ref $code || 'CODE' ne reftype($code)) {
$class->_throw_exception( WrapTakesACodeRefToBless => params => \%params,
class => $class,
code => $code
);
}
($params{package_name} && $params{name})
|| $class->_throw_exception( PackageNameAndNameParamsNotGivenToWrap => params => \%params,
class => $class,
code => $code
);
my $self = $class->_new(\%params);
weaken($self->{associated_metaclass}) if $self->{associated_metaclass};
return $self;
}
sub _new {
my $class = shift;
return Class::MOP::Class->initialize($class)->new_object(@_)
if $class ne __PACKAGE__;
my $params = @_ == 1 ? $_[0] : {@_};
return bless {
'body' => $params->{body},
'associated_metaclass' => $params->{associated_metaclass},
'package_name' => $params->{package_name},
'name' => $params->{name},
'original_method' => $params->{original_method},
} => $class;
}
## accessors
sub associated_metaclass { shift->{'associated_metaclass'} }
sub attach_to_class {
my ( $self, $class ) = @_;
$self->{associated_metaclass} = $class;
weaken($self->{associated_metaclass});
}
sub detach_from_class {
my $self = shift;
delete $self->{associated_metaclass};
}
sub fully_qualified_name {
my $self = shift;
$self->package_name . '::' . $self->name;
}
sub original_method { (shift)->{'original_method'} }
sub _set_original_method { $_[0]->{'original_method'} = $_[1] }
# It's possible that this could cause a loop if there is a circular
# reference in here. That shouldn't ever happen in normal
# circumstances, since original method only gets set when clone is
# called. We _could_ check for such a loop, but it'd involve some sort
# of package-lexical variable, and wouldn't be terribly subclassable.
sub original_package_name {
my $self = shift;
$self->original_method
? $self->original_method->original_package_name
: $self->package_name;
}
sub original_name {
my $self = shift;
$self->original_method
? $self->original_method->original_name
: $self->name;
}
sub original_fully_qualified_name {
my $self = shift;
$self->original_method
? $self->original_method->original_fully_qualified_name
: $self->fully_qualified_name;
}
sub execute {
my $self = shift;
$self->body->(@_);
}
# We used to go through use Class::MOP::Class->clone_instance to do this, but
# this was awfully slow. This method may be called a number of times when
# classes are loaded (especially during Moose role application), so it is
# worth optimizing. - DR
sub clone {
my $self = shift;
my $clone = bless { %{$self}, @_ }, blessed($self);
weaken($clone->{associated_metaclass}) if $clone->{associated_metaclass};
$clone->_set_original_method($self);
return $clone;
}
sub _inline_throw_exception {
my ( $self, $exception_type, $throw_args ) = @_;
return
'die Module::Runtime::use_module("Moose::Exception::'
. $exception_type
. '")->new('
. ( $throw_args || '' ) . ')';
}
1;
# ABSTRACT: Method Meta Object
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Method - Method Meta Object
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
The Method Protocol is very small, since methods in Perl 5 are just
subroutines in a specific package. We provide a very basic
introspection interface.
=head1 METHODS
=over 4
=item B<< Class::MOP::Method->wrap($code, %options) >>
This is the constructor. It accepts a method body in the form of
either a code reference or a L<Class::MOP::Method> instance, followed
by a hash of options.
The options are:
=over 8
=item * name
The method name (without a package name). This is required if C<$code>
is a coderef.
=item * package_name
The package name for the method. This is required if C<$code> is a
coderef.
=item * associated_metaclass
An optional L<Class::MOP::Class> object. This is the metaclass for the
method's class.
=back
=item B<< $metamethod->clone(%params) >>
This makes a shallow clone of the method object. In particular,
subroutine reference itself is shared between all clones of a given
method.
When a method is cloned, the original method object will be available
by calling C<original_method> on the clone.
=item B<< $metamethod->body >>
This returns a reference to the method's subroutine.
=item B<< $metamethod->name >>
This returns the method's name.
=item B<< $metamethod->package_name >>
This returns the method's package name.
=item B<< $metamethod->fully_qualified_name >>
This returns the method's fully qualified name (package name and
method name).
=item B<< $metamethod->associated_metaclass >>
This returns the L<Class::MOP::Class> object for the method, if one
exists.
=item B<< $metamethod->original_method >>
If this method object was created as a clone of some other method
object, this returns the object that was cloned.
=item B<< $metamethod->original_name >>
This returns the method's original name, wherever it was first
defined.
If this method is a clone of a clone (of a clone, etc.), this method
returns the name from the I<first> method in the chain of clones.
=item B<< $metamethod->original_package_name >>
This returns the method's original package name, wherever it was first
defined.
If this method is a clone of a clone (of a clone, etc.), this method
returns the package name from the I<first> method in the chain of
clones.
=item B<< $metamethod->original_fully_qualified_name >>
This returns the method's original fully qualified name, wherever it
was first defined.
If this method is a clone of a clone (of a clone, etc.), this method
returns the fully qualified name from the I<first> method in the chain
of clones.
=item B<< $metamethod->is_stub >>
Returns true if the method is just a stub:
sub foo;
=item B<< $metamethod->attach_to_class($metaclass) >>
Given a L<Class::MOP::Class> object, this method sets the associated
metaclass for the method. This will overwrite any existing associated
metaclass.
=item B<< $metamethod->detach_from_class >>
Removes any associated metaclass object for the method.
=item B<< $metamethod->execute(...) >>
This executes the method. Any arguments provided will be passed on to
the method itself.
=item B<< Class::MOP::Method->meta >>
This will return a L<Class::MOP::Class> instance for this class.
It should also be noted that L<Class::MOP> will actually bootstrap
this module by installing a number of attribute meta-objects into its
metaclass.
=back
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,404 @@
package Class::MOP::Method::Accessor;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'blessed', 'weaken';
use Try::Tiny;
use parent 'Class::MOP::Method::Generated';
sub new {
my $class = shift;
my %options = @_;
(exists $options{attribute})
|| $class->_throw_exception( MustSupplyAnAttributeToConstructWith => params => \%options,
class => $class,
);
(exists $options{accessor_type})
|| $class->_throw_exception( MustSupplyAnAccessorTypeToConstructWith => params => \%options,
class => $class,
);
(blessed($options{attribute}) && $options{attribute}->isa('Class::MOP::Attribute'))
|| $class->_throw_exception( MustSupplyAClassMOPAttributeInstance => params => \%options,
class => $class
);
($options{package_name} && $options{name})
|| $class->_throw_exception( MustSupplyPackageNameAndName => params => \%options,
class => $class
);
my $self = $class->_new(\%options);
# we don't want this creating
# a cycle in the code, if not
# needed
weaken($self->{'attribute'});
$self->_initialize_body;
return $self;
}
sub _new {
my $class = shift;
return Class::MOP::Class->initialize($class)->new_object(@_)
if $class ne __PACKAGE__;
my $params = @_ == 1 ? $_[0] : {@_};
return bless {
# inherited from Class::MOP::Method
body => $params->{body},
associated_metaclass => $params->{associated_metaclass},
package_name => $params->{package_name},
name => $params->{name},
original_method => $params->{original_method},
# inherit from Class::MOP::Generated
is_inline => $params->{is_inline} || 0,
definition_context => $params->{definition_context},
# defined in this class
attribute => $params->{attribute},
accessor_type => $params->{accessor_type},
} => $class;
}
## accessors
sub associated_attribute { (shift)->{'attribute'} }
sub accessor_type { (shift)->{'accessor_type'} }
## factory
sub _initialize_body {
my $self = shift;
my $method_name = join "_" => (
'_generate',
$self->accessor_type,
'method',
($self->is_inline ? 'inline' : ())
);
$self->{'body'} = $self->$method_name();
}
## generators
sub _generate_accessor_method {
my $self = shift;
my $attr = $self->associated_attribute;
return sub {
if (@_ >= 2) {
$attr->set_value($_[0], $_[1]);
}
$attr->get_value($_[0]);
};
}
sub _generate_accessor_method_inline {
my $self = shift;
my $attr = $self->associated_attribute;
return try {
$self->_compile_code([
'sub {',
'if (@_ > 1) {',
$attr->_inline_set_value('$_[0]', '$_[1]'),
'}',
$attr->_inline_get_value('$_[0]'),
'}',
]);
}
catch {
$self->_throw_exception( CouldNotGenerateInlineAttributeMethod => instance => $self,
error => $_,
option => "accessor"
);
};
}
sub _generate_reader_method {
my $self = shift;
my $attr = $self->associated_attribute;
my $class = $attr->associated_class;
return sub {
$self->_throw_exception( CannotAssignValueToReadOnlyAccessor => class_name => $class->name,
value => $_[1],
attribute => $attr
)
if @_ > 1;
$attr->get_value($_[0]);
};
}
sub _generate_reader_method_inline {
my $self = shift;
my $attr = $self->associated_attribute;
my $attr_name = $attr->name;
return try {
$self->_compile_code([
'sub {',
'if (@_ > 1) {',
$self->_inline_throw_exception( CannotAssignValueToReadOnlyAccessor =>
'class_name => ref $_[0],'.
'value => $_[1],'.
"attribute_name => '".$attr_name."'",
) . ';',
'}',
$attr->_inline_get_value('$_[0]'),
'}',
]);
}
catch {
$self->_throw_exception( CouldNotGenerateInlineAttributeMethod => instance => $self,
error => $_,
option => "reader"
);
};
}
sub _generate_writer_method {
my $self = shift;
my $attr = $self->associated_attribute;
return sub {
$attr->set_value($_[0], $_[1]);
};
}
sub _generate_writer_method_inline {
my $self = shift;
my $attr = $self->associated_attribute;
return try {
$self->_compile_code([
'sub {',
$attr->_inline_set_value('$_[0]', '$_[1]'),
'}',
]);
}
catch {
$self->_throw_exception( CouldNotGenerateInlineAttributeMethod => instance => $self,
error => $_,
option => "writer"
);
};
}
sub _generate_predicate_method {
my $self = shift;
my $attr = $self->associated_attribute;
return sub {
$attr->has_value($_[0])
};
}
sub _generate_predicate_method_inline {
my $self = shift;
my $attr = $self->associated_attribute;
return try {
$self->_compile_code([
'sub {',
$attr->_inline_has_value('$_[0]'),
'}',
]);
}
catch {
$self->_throw_exception( CouldNotGenerateInlineAttributeMethod => instance => $self,
error => $_,
option => "predicate"
);
};
}
sub _generate_clearer_method {
my $self = shift;
my $attr = $self->associated_attribute;
return sub {
$attr->clear_value($_[0])
};
}
sub _generate_clearer_method_inline {
my $self = shift;
my $attr = $self->associated_attribute;
return try {
$self->_compile_code([
'sub {',
$attr->_inline_clear_value('$_[0]'),
'}',
]);
}
catch {
$self->_throw_exception( CouldNotGenerateInlineAttributeMethod => instance => $self,
error => $_,
option => "clearer"
);
};
}
1;
# ABSTRACT: Method Meta Object for accessors
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Method::Accessor - Method Meta Object for accessors
=head1 VERSION
version 2.2014
=head1 SYNOPSIS
use Class::MOP::Method::Accessor;
my $reader = Class::MOP::Method::Accessor->new(
attribute => $attribute,
is_inline => 1,
accessor_type => 'reader',
);
$reader->body->execute($instance); # call the reader method
=head1 DESCRIPTION
This is a subclass of C<Class::MOP::Method> which is used by
C<Class::MOP::Attribute> to generate accessor code. It handles
generation of readers, writers, predicates and clearers. For each type
of method, it can either create a subroutine reference, or actually
inline code by generating a string and C<eval>'ing it.
=head1 METHODS
=over 4
=item B<< Class::MOP::Method::Accessor->new(%options) >>
This returns a new C<Class::MOP::Method::Accessor> based on the
C<%options> provided.
=over 4
=item * attribute
This is the C<Class::MOP::Attribute> for which accessors are being
generated. This option is required.
=item * accessor_type
This is a string which should be one of "reader", "writer",
"accessor", "predicate", or "clearer". This is the type of method
being generated. This option is required.
=item * is_inline
This indicates whether or not the accessor should be inlined. This
defaults to false.
=item * name
The method name (without a package name). This is required.
=item * package_name
The package name for the method. This is required.
=back
=item B<< $metamethod->accessor_type >>
Returns the accessor type which was passed to C<new>.
=item B<< $metamethod->is_inline >>
Returns a boolean indicating whether or not the accessor is inlined.
=item B<< $metamethod->associated_attribute >>
This returns the L<Class::MOP::Attribute> object which was passed to
C<new>.
=item B<< $metamethod->body >>
The method itself is I<generated> when the accessor object is
constructed.
=back
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,251 @@
package Class::MOP::Method::Constructor;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'blessed', 'weaken';
use Try::Tiny;
use parent 'Class::MOP::Method::Inlined';
sub new {
my $class = shift;
my %options = @_;
(blessed $options{metaclass} && $options{metaclass}->isa('Class::MOP::Class'))
|| $class->_throw_exception( MustSupplyAMetaclass => params => \%options,
class => $class
)
if $options{is_inline};
($options{package_name} && $options{name})
|| $class->_throw_exception( MustSupplyPackageNameAndName => params => \%options,
class => $class
);
my $self = $class->_new(\%options);
# we don't want this creating
# a cycle in the code, if not
# needed
weaken($self->{'associated_metaclass'});
$self->_initialize_body;
return $self;
}
sub _new {
my $class = shift;
return Class::MOP::Class->initialize($class)->new_object(@_)
if $class ne __PACKAGE__;
my $params = @_ == 1 ? $_[0] : {@_};
return bless {
# inherited from Class::MOP::Method
body => $params->{body},
# associated_metaclass => $params->{associated_metaclass}, # overridden
package_name => $params->{package_name},
name => $params->{name},
original_method => $params->{original_method},
# inherited from Class::MOP::Generated
is_inline => $params->{is_inline} || 0,
definition_context => $params->{definition_context},
# inherited from Class::MOP::Inlined
_expected_method_class => $params->{_expected_method_class},
# defined in this subclass
options => $params->{options} || {},
associated_metaclass => $params->{metaclass},
}, $class;
}
## accessors
sub options { (shift)->{'options'} }
sub associated_metaclass { (shift)->{'associated_metaclass'} }
## method
sub _initialize_body {
my $self = shift;
my $method_name = '_generate_constructor_method';
$method_name .= '_inline' if $self->is_inline;
$self->{'body'} = $self->$method_name;
}
sub _eval_environment {
my $self = shift;
return $self->associated_metaclass->_eval_environment;
}
sub _generate_constructor_method {
return sub { Class::MOP::Class->initialize(shift)->new_object(@_) }
}
sub _generate_constructor_method_inline {
my $self = shift;
my $meta = $self->associated_metaclass;
my @source = (
'sub {',
$meta->_inline_new_object,
'}',
);
warn join("\n", @source) if $self->options->{debug};
my $code = try {
$self->_compile_code(\@source);
}
catch {
my $source = join("\n", @source);
$self->_throw_exception( CouldNotEvalConstructor => constructor_method => $self,
source => $source,
error => $_
);
};
return $code;
}
1;
# ABSTRACT: Method Meta Object for constructors
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Method::Constructor - Method Meta Object for constructors
=head1 VERSION
version 2.2014
=head1 SYNOPSIS
use Class::MOP::Method::Constructor;
my $constructor = Class::MOP::Method::Constructor->new(
metaclass => $metaclass,
options => {
debug => 1, # this is all for now
},
);
# calling the constructor ...
$constructor->body->execute($metaclass->name, %params);
=head1 DESCRIPTION
This is a subclass of L<Class::MOP::Method> which generates
constructor methods.
=head1 METHODS
=over 4
=item B<< Class::MOP::Method::Constructor->new(%options) >>
This creates a new constructor object. It accepts a hash reference of
options.
=over 8
=item * metaclass
This should be a L<Class::MOP::Class> object. It is required.
=item * name
The method name (without a package name). This is required.
=item * package_name
The package name for the method. This is required.
=item * is_inline
This indicates whether or not the constructor should be inlined. This
defaults to false.
=back
=item B<< $metamethod->is_inline >>
Returns a boolean indicating whether or not the constructor is
inlined.
=item B<< $metamethod->associated_metaclass >>
This returns the L<Class::MOP::Class> object for the method.
=back
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,142 @@
package Class::MOP::Method::Generated;
our $VERSION = '2.2014';
use strict;
use warnings;
use Eval::Closure;
use parent 'Class::MOP::Method';
## accessors
sub new {
$_[0]->_throw_exception( CannotCallAnAbstractBaseMethod => package_name => __PACKAGE__ );
}
sub _initialize_body {
$_[0]->_throw_exception( NoBodyToInitializeInAnAbstractBaseClass => package_name => __PACKAGE__ );
}
sub _generate_description {
my ( $self, $context ) = @_;
$context ||= $self->definition_context;
my $desc = "generated method";
my $origin = "unknown origin";
if (defined $context) {
if (defined $context->{description}) {
$desc = $context->{description};
}
if (defined $context->{file} || defined $context->{line}) {
$origin = "defined at "
. (defined $context->{file}
? $context->{file} : "<unknown file>")
. " line "
. (defined $context->{line}
? $context->{line} : "<unknown line>");
}
}
return "$desc ($origin)";
}
sub _compile_code {
my ( $self, @args ) = @_;
unshift @args, 'source' if @args % 2;
my %args = @args;
my $context = delete $args{context};
my $environment = $self->can('_eval_environment')
? $self->_eval_environment
: {};
return eval_closure(
environment => $environment,
description => $self->_generate_description($context),
%args,
);
}
1;
# ABSTRACT: Abstract base class for generated methods
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Method::Generated - Abstract base class for generated methods
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This is a C<Class::MOP::Method> subclass which is subclassed by
C<Class::MOP::Method::Accessor> and
C<Class::MOP::Method::Constructor>.
It is not intended to be used directly.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,191 @@
package Class::MOP::Method::Inlined;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'refaddr';
use parent 'Class::MOP::Method::Generated';
sub _uninlined_body {
my $self = shift;
my $super_method
= $self->associated_metaclass->find_next_method_by_name( $self->name )
or return;
if ( $super_method->isa(__PACKAGE__) ) {
return $super_method->_uninlined_body;
}
else {
return $super_method->body;
}
}
sub can_be_inlined {
my $self = shift;
my $metaclass = $self->associated_metaclass;
my $class = $metaclass->name;
# If we don't find an inherited method, this is a rather weird
# case where we have no method in the inheritance chain even
# though we're expecting one to be there
my $inherited_method
= $metaclass->find_next_method_by_name( $self->name );
if ( $inherited_method
&& $inherited_method->isa('Class::MOP::Method::Wrapped') ) {
warn "Not inlining '"
. $self->name
. "' for $class since it "
. "has method modifiers which would be lost if it were inlined\n";
return 0;
}
my $expected_class = $self->_expected_method_class
or return 1;
# if we are shadowing a method we first verify that it is
# compatible with the definition we are replacing it with
my $expected_method = $expected_class->can( $self->name );
if ( ! $expected_method ) {
warn "Not inlining '"
. $self->name
. "' for $class since ${expected_class}::"
. $self->name
. " is not defined\n";
return 0;
}
my $actual_method = $class->can( $self->name )
or return 1;
# the method is what we wanted (probably Moose::Object::new)
return 1
if refaddr($expected_method) == refaddr($actual_method);
# otherwise we have to check that the actual method is an inlined
# version of what we're expecting
if ( $inherited_method->isa(__PACKAGE__) ) {
if ( $inherited_method->_uninlined_body
&& refaddr( $inherited_method->_uninlined_body )
== refaddr($expected_method) ) {
return 1;
}
}
elsif ( refaddr( $inherited_method->body )
== refaddr($expected_method) ) {
return 1;
}
my $warning
= "Not inlining '"
. $self->name
. "' for $class since it is not"
. " inheriting the default ${expected_class}::"
. $self->name . "\n";
if ( $self->isa("Class::MOP::Method::Constructor") ) {
# FIXME kludge, refactor warning generation to a method
$warning
.= "If you are certain you don't need to inline your"
. " constructor, specify inline_constructor => 0 in your"
. " call to $class->meta->make_immutable\n";
}
warn $warning;
return 0;
}
1;
# ABSTRACT: Method base class for methods which have been inlined
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Method::Inlined - Method base class for methods which have been inlined
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This is a L<Class::MOP::Method::Generated> subclass for methods which
can be inlined.
=head1 METHODS
=head2 $metamethod->can_be_inlined
This method returns true if the method in question can be inlined in
the associated metaclass.
If it cannot be inlined, it spits out a warning and returns false.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,169 @@
package Class::MOP::Method::Meta;
our $VERSION = '2.2014';
use strict;
use warnings;
use Carp 'confess';
use Scalar::Util 'blessed', 'weaken';
use constant DEBUG_NO_META => $ENV{DEBUG_NO_META} ? 1 : 0;
use parent 'Class::MOP::Method';
sub _is_caller_mop_internal {
my $self = shift;
my ($caller) = @_;
return $caller =~ /^(?:Class::MOP|metaclass)(?:::|$)/;
}
sub _generate_meta_method {
my $method_self = shift;
my $metaclass = shift;
weaken($metaclass);
sub {
# this will be compiled out if the env var wasn't set
if (DEBUG_NO_META) {
confess "'meta' method called by MOP internals"
# it's okay to call meta methods on metaclasses, since we
# explicitly ask for them
if !$_[0]->isa('Class::MOP::Object')
&& !$_[0]->isa('Class::MOP::Mixin')
# it's okay if the test itself calls ->meta, we only care about
# if the mop internals call ->meta
&& $method_self->_is_caller_mop_internal(scalar caller);
}
# we must re-initialize so that it
# works as expected in subclasses,
# since metaclass instances are
# singletons, this is not really a
# big deal anyway.
$metaclass->initialize(blessed($_[0]) || $_[0])
};
}
sub wrap {
my ($class, @args) = @_;
unshift @args, 'body' if @args % 2 == 1;
my %params = @args;
$class->_throw_exception( CannotOverrideBodyOfMetaMethods => params => \%params,
class => $class
)
if $params{body};
my $metaclass_class = $params{associated_metaclass}->meta;
$params{body} = $class->_generate_meta_method($metaclass_class);
return $class->SUPER::wrap(%params);
}
sub _make_compatible_with {
my $self = shift;
my ($other) = @_;
# XXX: this is pretty gross. the issue here is that CMOP::Method::Meta
# objects are subclasses of CMOP::Method, but when we get to moose, they'll
# need to be compatible with Moose::Meta::Method, which isn't possible. the
# right solution here is to make ::Meta into a role that gets applied to
# whatever the method_metaclass happens to be and get rid of
# _meta_method_metaclass entirely, but that's not going to happen until
# we ditch cmop and get roles into the bootstrapping, so. i'm not
# maintaining the previous behavior of turning them into instances of the
# new method_metaclass because that's equally broken, and at least this way
# any issues will at least be detectable and potentially fixable. -doy
return $self unless $other->_is_compatible_with($self->_real_ref_name);
return $self->SUPER::_make_compatible_with(@_);
}
1;
# ABSTRACT: Method Meta Object for C<meta> methods
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Method::Meta - Method Meta Object for C<meta> methods
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This is a L<Class::MOP::Method> subclass which represents C<meta>
methods installed into classes by Class::MOP.
=head1 METHODS
=over 4
=item B<< Class::MOP::Method::Wrapped->wrap($metamethod, %options) >>
This is the constructor. It accepts a L<Class::MOP::Method> object and
a hash of options. The options accepted are identical to the ones
accepted by L<Class::MOP::Method>, except that C<body> cannot be passed
(it will be generated automatically).
=back
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,331 @@
package Class::MOP::Method::Wrapped;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'blessed';
use Sub::Name 'subname';
use parent 'Class::MOP::Method';
# NOTE:
# this ugly beast is the result of trying
# to micro optimize this as much as possible
# while not completely loosing maintainability.
# At this point it's "fast enough", after all
# you can't get something for nothing :)
my $_build_wrapped_method = sub {
my $modifier_table = shift;
my ($before, $after, $around) = (
$modifier_table->{before},
$modifier_table->{after},
$modifier_table->{around},
);
if (@$before && @$after) {
$modifier_table->{cache} = sub {
for my $c (@$before) { $c->(@_) };
my @rval;
((defined wantarray) ?
((wantarray) ?
(@rval = $around->{cache}->(@_))
:
($rval[0] = $around->{cache}->(@_)))
:
$around->{cache}->(@_));
for my $c (@$after) { $c->(@_) };
return unless defined wantarray;
return wantarray ? @rval : $rval[0];
}
}
elsif (@$before) {
$modifier_table->{cache} = sub {
for my $c (@$before) { $c->(@_) };
return $around->{cache}->(@_);
}
}
elsif (@$after) {
$modifier_table->{cache} = sub {
my @rval;
((defined wantarray) ?
((wantarray) ?
(@rval = $around->{cache}->(@_))
:
($rval[0] = $around->{cache}->(@_)))
:
$around->{cache}->(@_));
for my $c (@$after) { $c->(@_) };
return unless defined wantarray;
return wantarray ? @rval : $rval[0];
}
}
else {
$modifier_table->{cache} = $around->{cache};
}
};
sub wrap {
my ( $class, $code, %params ) = @_;
(blessed($code) && $code->isa('Class::MOP::Method'))
|| $class->_throw_exception( CanOnlyWrapBlessedCode => params => \%params,
class => $class,
code => $code
);
my $modifier_table = {
cache => undef,
orig => $code->body,
before => [],
after => [],
around => {
cache => $code->body,
methods => [],
},
};
$_build_wrapped_method->($modifier_table);
# get these from the original unless explicitly overridden
my $pkg_name = $params{package_name} || $code->package_name;
my $method_name = $params{name} || $code->name;
return $class->SUPER::wrap(
sub {
my $wrapped = subname "${pkg_name}::_wrapped_${method_name}" => $modifier_table->{cache};
return $wrapped->(@_) ;
},
package_name => $pkg_name,
name => $method_name,
original_method => $code,
modifier_table => $modifier_table,
);
}
sub _new {
my $class = shift;
return Class::MOP::Class->initialize($class)->new_object(@_)
if $class ne __PACKAGE__;
my $params = @_ == 1 ? $_[0] : {@_};
return bless {
# inherited from Class::MOP::Method
'body' => $params->{body},
'associated_metaclass' => $params->{associated_metaclass},
'package_name' => $params->{package_name},
'name' => $params->{name},
'original_method' => $params->{original_method},
# defined in this class
'modifier_table' => $params->{modifier_table}
} => $class;
}
sub get_original_method {
my $code = shift;
$code->original_method;
}
sub add_before_modifier {
my $code = shift;
my $modifier = shift;
unshift @{$code->{'modifier_table'}->{before}} => $modifier;
$_build_wrapped_method->($code->{'modifier_table'});
}
sub before_modifiers {
my $code = shift;
return @{$code->{'modifier_table'}->{before}};
}
sub add_after_modifier {
my $code = shift;
my $modifier = shift;
push @{$code->{'modifier_table'}->{after}} => $modifier;
$_build_wrapped_method->($code->{'modifier_table'});
}
sub after_modifiers {
my $code = shift;
return @{$code->{'modifier_table'}->{after}};
}
{
# NOTE:
# this is another possible candidate for
# optimization as well. There is an overhead
# associated with the currying that, if
# eliminated might make around modifiers
# more manageable.
my $compile_around_method = sub {{
my $f1 = pop;
return $f1 unless @_;
my $f2 = pop;
push @_, sub { $f2->( $f1, @_ ) };
redo;
}};
sub add_around_modifier {
my $code = shift;
my $modifier = shift;
unshift @{$code->{'modifier_table'}->{around}->{methods}} => $modifier;
$code->{'modifier_table'}->{around}->{cache} = $compile_around_method->(
@{$code->{'modifier_table'}->{around}->{methods}},
$code->{'modifier_table'}->{orig}
);
$_build_wrapped_method->($code->{'modifier_table'});
}
}
sub around_modifiers {
my $code = shift;
return @{$code->{'modifier_table'}->{around}->{methods}};
}
sub _make_compatible_with {
my $self = shift;
my ($other) = @_;
# XXX: this is pretty gross. the issue here is that CMOP::Method::Wrapped
# objects are subclasses of CMOP::Method, but when we get to moose, they'll
# need to be compatible with Moose::Meta::Method, which isn't possible. the
# right solution here is to make ::Wrapped into a role that gets applied to
# whatever the method_metaclass happens to be and get rid of
# wrapped_method_metaclass entirely, but that's not going to happen until
# we ditch cmop and get roles into the bootstrapping, so. i'm not
# maintaining the previous behavior of turning them into instances of the
# new method_metaclass because that's equally broken, and at least this way
# any issues will at least be detectable and potentially fixable. -doy
return $self unless $other->_is_compatible_with($self->_real_ref_name);
return $self->SUPER::_make_compatible_with(@_);
}
1;
# ABSTRACT: Method Meta Object for methods with before/after/around modifiers
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Method::Wrapped - Method Meta Object for methods with before/after/around modifiers
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This is a L<Class::MOP::Method> subclass which implements before,
after, and around method modifiers.
=head1 METHODS
=head2 Class::MOP::Method::Wrapped->wrap($metamethod, %options)
This is the constructor. It accepts a L<Class::MOP::Method> object and
a hash of options.
The options are:
=over 4
=item * name
The method name (without a package name). This will be taken from the
provided L<Class::MOP::Method> object if it is not provided.
=item * package_name
The package name for the method. This will be taken from the provided
L<Class::MOP::Method> object if it is not provided.
=item * associated_metaclass
An optional L<Class::MOP::Class> object. This is the metaclass for the
method's class.
=back
=head2 $metamethod->get_original_method
This returns the L<Class::MOP::Method> object that was passed to the
constructor.
=head2 $metamethod->add_before_modifier($code)
=head2 $metamethod->add_after_modifier($code)
=head2 $metamethod->add_around_modifier($code)
These methods all take a subroutine reference and apply it as a
modifier to the original method.
=head2 $metamethod->before_modifiers
=head2 $metamethod->after_modifiers
=head2 $metamethod->around_modifiers
These methods all return a list of subroutine references which are
acting as the specified type of modifier.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,113 @@
package Class::MOP::MiniTrait;
our $VERSION = '2.2014';
use strict;
use warnings;
use Module::Runtime 'use_package_optimistically';
sub apply {
my ( $to_class, $trait ) = @_;
for ( grep { !ref } $to_class, $trait ) {
use_package_optimistically($_);
$_ = Class::MOP::Class->initialize($_);
}
for my $meth ( grep { $_->package_name ne 'UNIVERSAL' } $trait->get_all_methods ) {
my $meth_name = $meth->name;
next if index($meth_name, '__') == 0; # skip private subs
if ( $to_class->find_method_by_name($meth_name) ) {
$to_class->add_around_method_modifier( $meth_name, $meth->body );
}
else {
$to_class->add_method( $meth_name, $meth->clone );
}
}
}
# We can't load this with use, since it may be loaded and used from Class::MOP
# (via Class::MOP::Class, etc). However, if for some reason this module is loaded
# _without_ first loading Class::MOP we need to require Class::MOP so we can
# use it and Class::MOP::Class.
require Class::MOP;
1;
# ABSTRACT: Extremely limited trait application
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::MiniTrait - Extremely limited trait application
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This package provides a single function, C<apply>, which does a half-assed job
of applying a trait to a class. It exists solely for use inside Class::MOP and
L<Moose> core classes.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,107 @@
package Class::MOP::Mixin;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'blessed';
use Module::Runtime 'use_module';
sub meta {
require Class::MOP::Class;
Class::MOP::Class->initialize( blessed( $_[0] ) || $_[0] );
}
sub _throw_exception {
my ($class, $exception_type, @args_to_exception) = @_;
die use_module( "Moose::Exception::$exception_type" )->new( @args_to_exception );
}
1;
# ABSTRACT: Base class for mixin classes
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Mixin - Base class for mixin classes
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This class provides a few methods which are useful in all metaclasses.
=head1 METHODS
=head2 Class::MOP::Mixin->meta
This returns a L<Class::MOP::Class> object for the mixin class.
=head2 Class::MOP::Mixin->_throw_exception
Throws an exception in the L<Moose::Exception> family. This should ONLY be
used internally -- any callers outside Class::MOP::* should be using the
version in L<Moose::Util> instead.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,125 @@
package Class::MOP::Mixin::AttributeCore;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'blessed';
use parent 'Class::MOP::Mixin';
sub has_accessor { defined $_[0]->{'accessor'} }
sub has_reader { defined $_[0]->{'reader'} }
sub has_writer { defined $_[0]->{'writer'} }
sub has_predicate { defined $_[0]->{'predicate'} }
sub has_clearer { defined $_[0]->{'clearer'} }
sub has_builder { defined $_[0]->{'builder'} }
sub has_init_arg { defined $_[0]->{'init_arg'} }
sub has_default { exists $_[0]->{'default'} }
sub has_initializer { defined $_[0]->{'initializer'} }
sub has_insertion_order { defined $_[0]->{'insertion_order'} }
sub _set_insertion_order { $_[0]->{'insertion_order'} = $_[1] }
sub has_read_method { $_[0]->has_reader || $_[0]->has_accessor }
sub has_write_method { $_[0]->has_writer || $_[0]->has_accessor }
sub is_default_a_coderef {
# Uber hack because it is called from CMOP::Attribute constructor as
# $class->is_default_a_coderef(\%options)
my ($value) = ref $_[0] ? $_[0]->{'default'} : $_[1]->{'default'};
return unless ref($value);
return ref($value) eq 'CODE'
|| ( blessed($value) && $value->isa('Class::MOP::Method') );
}
sub default {
my ( $self, $instance ) = @_;
if ( defined $instance && $self->is_default_a_coderef ) {
# if the default is a CODE ref, then we pass in the instance and
# default can return a value based on that instance. Somewhat crude,
# but works.
return $self->{'default'}->($instance);
}
$self->{'default'};
}
1;
# ABSTRACT: Core attributes shared by attribute metaclasses
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Mixin::AttributeCore - Core attributes shared by attribute metaclasses
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This class implements the core attributes (aka properties) shared by all
attributes. See the L<Class::MOP::Attribute> documentation for API details.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,171 @@
package Class::MOP::Mixin::HasAttributes;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'blessed';
use parent 'Class::MOP::Mixin';
sub add_attribute {
my $self = shift;
my $attribute
= blessed( $_[0] ) ? $_[0] : $self->attribute_metaclass->new(@_);
( $attribute->isa('Class::MOP::Mixin::AttributeCore') )
|| $self->_throw_exception( AttributeMustBeAnClassMOPMixinAttributeCoreOrSubclass => attribute => $attribute,
class_name => $self->name,
);
$self->_attach_attribute($attribute);
my $attr_name = $attribute->name;
$self->remove_attribute($attr_name)
if $self->has_attribute($attr_name);
my $order = ( scalar keys %{ $self->_attribute_map } );
$attribute->_set_insertion_order($order);
$self->_attribute_map->{$attr_name} = $attribute;
# This method is called to allow for installing accessors. Ideally, we'd
# use method overriding, but then the subclass would be responsible for
# making the attribute, which would end up with lots of code
# duplication. Even more ideally, we'd use augment/inner, but this is
# Class::MOP!
$self->_post_add_attribute($attribute)
if $self->can('_post_add_attribute');
return $attribute;
}
sub has_attribute {
my ( $self, $attribute_name ) = @_;
( defined $attribute_name )
|| $self->_throw_exception( MustDefineAnAttributeName => class_name => $self->name );
exists $self->_attribute_map->{$attribute_name};
}
sub get_attribute {
my ( $self, $attribute_name ) = @_;
( defined $attribute_name )
|| $self->_throw_exception( MustDefineAnAttributeName => class_name => $self->name );
return $self->_attribute_map->{$attribute_name};
}
sub remove_attribute {
my ( $self, $attribute_name ) = @_;
( defined $attribute_name )
|| $self->_throw_exception( MustDefineAnAttributeName => class_name => $self->name );
my $removed_attribute = $self->_attribute_map->{$attribute_name};
return unless defined $removed_attribute;
delete $self->_attribute_map->{$attribute_name};
return $removed_attribute;
}
sub get_attribute_list {
my $self = shift;
keys %{ $self->_attribute_map };
}
sub _restore_metaattributes_from {
my $self = shift;
my ($old_meta) = @_;
for my $attr (sort { $a->insertion_order <=> $b->insertion_order }
map { $old_meta->get_attribute($_) }
$old_meta->get_attribute_list) {
$attr->_make_compatible_with($self->attribute_metaclass);
$self->add_attribute($attr);
}
}
1;
# ABSTRACT: Methods for metaclasses which have attributes
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Mixin::HasAttributes - Methods for metaclasses which have attributes
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This class implements methods for metaclasses which have attributes
(L<Class::MOP::Class> and L<Moose::Meta::Role>). See L<Class::MOP::Class> for
API details.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,304 @@
package Class::MOP::Mixin::HasMethods;
our $VERSION = '2.2014';
use strict;
use warnings;
use Class::MOP::Method::Meta;
use Scalar::Util 'blessed', 'reftype';
use Sub::Name 'subname';
use parent 'Class::MOP::Mixin';
sub _meta_method_class { 'Class::MOP::Method::Meta' }
sub _add_meta_method {
my $self = shift;
my ($name) = @_;
my $existing_method = $self->can('find_method_by_name')
? $self->find_method_by_name($name)
: $self->get_method($name);
return if $existing_method
&& $existing_method->isa($self->_meta_method_class);
$self->add_method(
$name => $self->_meta_method_class->wrap(
name => $name,
package_name => $self->name,
associated_metaclass => $self,
)
);
}
sub wrap_method_body {
my ( $self, %args ) = @_;
( $args{body} && 'CODE' eq reftype $args{body} )
|| $self->_throw_exception( CodeBlockMustBeACodeRef => instance => $self,
params => \%args
);
$self->method_metaclass->wrap(
package_name => $self->name,
%args,
);
}
sub add_method {
my ( $self, $method_name, $method ) = @_;
( defined $method_name && length $method_name )
|| $self->_throw_exception( MustDefineAMethodName => instance => $self );
my $package_name = $self->name;
my $body;
if ( blessed($method) && $method->isa('Class::MOP::Method') ) {
$body = $method->body;
if ( $method->package_name ne $package_name ) {
$method = $method->clone(
package_name => $package_name,
name => $method_name,
);
}
$method->attach_to_class($self);
}
else {
# If a raw code reference is supplied, its method object is not created.
# The method object won't be created until required.
$body = $method;
}
$self->_method_map->{$method_name} = $method;
my ($current_package, $current_name) = Class::MOP::get_code_info($body);
subname($package_name . '::' . $method_name, $body)
unless defined $current_name && $current_name !~ /^__ANON__/;
$self->add_package_symbol("&$method_name", $body);
# we added the method to the method map too, so it's still valid
$self->update_package_cache_flag;
}
sub _code_is_mine {
my ( $self, $code ) = @_;
my ( $code_package, $code_name ) = Class::MOP::get_code_info($code);
return ( $code_package && $code_package eq $self->name )
|| ( $code_package eq 'constant' && $code_name eq '__ANON__' );
}
sub has_method {
my ( $self, $method_name ) = @_;
( defined $method_name && length $method_name )
|| $self->_throw_exception( MustDefineAMethodName => instance => $self );
my $method = $self->_get_maybe_raw_method($method_name);
return if not $method;
return defined($self->_method_map->{$method_name} = $method);
}
sub get_method {
my ( $self, $method_name ) = @_;
( defined $method_name && length $method_name )
|| $self->_throw_exception( MustDefineAMethodName => instance => $self );
my $method = $self->_get_maybe_raw_method($method_name);
return if not $method;
return $method if blessed($method) && $method->isa('Class::MOP::Method');
return $self->_method_map->{$method_name} = $self->wrap_method_body(
body => $method,
name => $method_name,
associated_metaclass => $self,
);
}
sub _get_maybe_raw_method {
my ( $self, $method_name ) = @_;
my $map_entry = $self->_method_map->{$method_name};
return $map_entry if defined $map_entry;
my $code = $self->get_package_symbol("&$method_name");
return unless $code && $self->_code_is_mine($code);
return $code;
}
sub remove_method {
my ( $self, $method_name ) = @_;
( defined $method_name && length $method_name )
|| $self->_throw_exception( MustDefineAMethodName => instance => $self );
my $removed_method = delete $self->_method_map->{$method_name};
$self->remove_package_symbol("&$method_name");
$removed_method->detach_from_class
if blessed($removed_method) && $removed_method->isa('Class::MOP::Method');
# still valid, since we just removed the method from the map
$self->update_package_cache_flag;
return $removed_method;
}
sub get_method_list {
my $self = shift;
return keys %{ $self->_full_method_map };
}
sub _get_local_methods {
my $self = shift;
return values %{ $self->_full_method_map };
}
sub _restore_metamethods_from {
my $self = shift;
my ($old_meta) = @_;
my $package_name = $self->name;
# Check if Perl debugger is enabled
my $debugger_enabled = ($^P & 0x10);
my $debug_method_info;
for my $method ($old_meta->_get_local_methods) {
my $method_name = $method->name;
# Track DB::sub information for this method if debugger is enabled.
# This contains original method filename and line numbers.
$debug_method_info = '';
if ($debugger_enabled) {
$debug_method_info = $DB::sub{$package_name . "::" . $method_name}
}
$method->_make_compatible_with($self->method_metaclass);
$self->add_method($method_name => $method);
# Restore method debug information, which can be clobbered by add_method.
# Note that we handle this here instead of in add_method, because we
# only want to preserve the original debug info in cases where we are
# restoring a method, not overwriting a method.
if ($debugger_enabled && $debug_method_info) {
$DB::sub{$package_name . "::" . $method_name} = $debug_method_info;
}
}
}
sub reset_package_cache_flag { (shift)->{'_package_cache_flag'} = undef }
sub update_package_cache_flag {
my $self = shift;
# NOTE:
# we can manually update the cache number
# since we are actually adding the method
# to our cache as well. This avoids us
# having to regenerate the method_map.
# - SL
$self->{'_package_cache_flag'} = Class::MOP::check_package_cache_flag($self->name);
}
sub _full_method_map {
my $self = shift;
my $pkg_gen = Class::MOP::check_package_cache_flag($self->name);
if (($self->{_package_cache_flag_full} || -1) != $pkg_gen) {
# forcibly reify all method map entries
$self->get_method($_)
for $self->list_all_package_symbols('CODE');
$self->{_package_cache_flag_full} = $pkg_gen;
}
return $self->_method_map;
}
1;
# ABSTRACT: Methods for metaclasses which have methods
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Mixin::HasMethods - Methods for metaclasses which have methods
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This class implements methods for metaclasses which have methods
(L<Class::MOP::Class> and L<Moose::Meta::Role>). See L<Class::MOP::Class> for
API details.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,243 @@
package Class::MOP::Mixin::HasOverloads;
our $VERSION = '2.2014';
use strict;
use warnings;
use Class::MOP::Overload;
use Devel::OverloadInfo 0.005 'overload_info', 'overload_op_info';
use Scalar::Util 'blessed';
use overload ();
use parent 'Class::MOP::Mixin';
sub is_overloaded {
my $self = shift;
Devel::OverloadInfo::is_overloaded($self->name);
}
sub get_overload_list {
my $self = shift;
my $info = $self->_overload_info;
return grep { $_ ne 'fallback' } keys %{$info}
}
sub get_all_overloaded_operators {
my $self = shift;
return map { $self->_overload_for($_) } $self->get_overload_list;
}
sub has_overloaded_operator {
my $self = shift;
my ($op) = @_;
return defined $self->_overload_info_for($op);
}
sub _overload_map {
$_[0]->{_overload_map} ||= {};
}
sub get_overloaded_operator {
my $self = shift;
my ($op) = @_;
return $self->_overload_map->{$op} ||= $self->_overload_for($op);
}
use constant _SET_FALLBACK_EACH_TIME => "$]" < 5.120;
sub add_overloaded_operator {
my $self = shift;
my ( $op, $overload ) = @_;
my %p = ( associated_metaclass => $self );
if ( !ref $overload ) {
%p = (
%p,
operator => $op,
method_name => $overload,
associated_metaclass => $self,
);
$p{method} = $self->get_method($overload)
if $self->has_method($overload);
$overload = Class::MOP::Overload->new(%p);
}
elsif ( !blessed $overload) {
my ($coderef_package, $coderef_name) = Class::MOP::get_code_info($overload);
$overload = Class::MOP::Overload->new(
operator => $op,
coderef => $overload,
coderef_name => $coderef_name,
coderef_package => $coderef_package,
%p,
);
}
$overload->attach_to_class($self);
$self->_overload_map->{$op} = $overload;
my %overload = (
$op => $overload->has_coderef
? $overload->coderef
: $overload->method_name
);
# Perl 5.10 and earlier appear to have a bug where setting a new
# overloading operator wipes out the fallback value unless we pass it each
# time.
if (_SET_FALLBACK_EACH_TIME) {
$overload{fallback} = $self->get_overload_fallback_value;
}
$self->name->overload::OVERLOAD(%overload);
}
sub remove_overloaded_operator {
my $self = shift;
my ($op) = @_;
delete $self->_overload_map->{$op};
# overload.pm provides no api for this - but the problem that makes this
# necessary has been fixed in 5.18
$self->get_or_add_package_symbol('%OVERLOAD')->{dummy}++
if "$]" < 5.017000;
$self->remove_package_symbol('&(' . $op);
}
sub get_overload_fallback_value {
my $self = shift;
return ($self->_overload_info_for('fallback') || {})->{value};
}
sub set_overload_fallback_value {
my $self = shift;
my $value = shift;
$self->name->overload::OVERLOAD( fallback => $value );
}
# We could cache this but we'd need some logic to clear it at all the right
# times, which seems more tedious than it's worth.
sub _overload_info {
my $self = shift;
return overload_info( $self->name ) || {};
}
sub _overload_info_for {
my $self = shift;
my $op = shift;
return overload_op_info( $self->name, $op );
}
sub _overload_for {
my $self = shift;
my $op = shift;
my $map = $self->_overload_map;
return $map->{$op} if $map->{$op};
my $info = $self->_overload_info_for($op);
return unless $info;
my %p = (
operator => $op,
associated_metaclass => $self,
);
if ( $info->{code} && !$info->{method_name} ) {
$p{coderef} = $info->{code};
@p{ 'coderef_package', 'coderef_name' }
= $info->{code_name} =~ /(.+)::([^:]+)/;
}
else {
$p{method_name} = $info->{method_name};
if ( $self->has_method( $p{method_name} ) ) {
$p{method} = $self->get_method( $p{method_name} );
}
}
return $map->{$op} = Class::MOP::Overload->new(%p);
}
1;
# ABSTRACT: Methods for metaclasses which have overloads
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Mixin::HasOverloads - Methods for metaclasses which have overloads
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This class implements methods for metaclasses which have overloads
(L<Class::MOP::Clas> and L<Moose::Meta::Role>). See L<Class::MOP::Class> for
API details.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,209 @@
package Class::MOP::Module;
our $VERSION = '2.2014';
use strict;
use warnings;
use parent 'Class::MOP::Package';
sub _new {
my $class = shift;
return Class::MOP::Class->initialize($class)->new_object(@_)
if $class ne __PACKAGE__;
my $params = @_ == 1 ? $_[0] : {@_};
return bless {
# Need to quote package to avoid a problem with PPI mis-parsing this
# as a package statement.
# from Class::MOP::Package
'package' => $params->{package},
namespace => \undef,
# attributes
version => \undef,
authority => \undef
} => $class;
}
sub version {
my $self = shift;
${$self->get_or_add_package_symbol('$VERSION')};
}
sub authority {
my $self = shift;
${$self->get_or_add_package_symbol('$AUTHORITY')};
}
sub identifier {
my $self = shift;
join '-' => (
$self->name,
($self->version || ()),
($self->authority || ()),
);
}
sub create {
my $class = shift;
my @args = @_;
unshift @args, 'package' if @args % 2 == 1;
my %options = @args;
my $package = delete $options{package};
my $version = delete $options{version};
my $authority = delete $options{authority};
my $meta = $class->SUPER::create($package => %options);
$meta->_instantiate_module($version, $authority);
return $meta;
}
sub _anon_package_prefix { 'Class::MOP::Module::__ANON__::SERIAL::' }
sub _anon_cache_key {
my $class = shift;
my %options = @_;
$class->_throw_exception( PackagesAndModulesAreNotCachable => class_name => $class,
params => \%options,
is_module => 1
);
}
sub _instantiate_module {
my($self, $version, $authority) = @_;
my $package_name = $self->name;
$self->add_package_symbol('$VERSION' => $version)
if defined $version;
$self->add_package_symbol('$AUTHORITY' => $authority)
if defined $authority;
return;
}
1;
# ABSTRACT: Module Meta Object
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Module - Module Meta Object
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
A module is essentially a L<Class::MOP::Package> with metadata, in our
case the version and authority.
=head1 INHERITANCE
B<Class::MOP::Module> is a subclass of L<Class::MOP::Package>.
=head1 METHODS
=head2 Class::MOP::Module->create($package, %options)
Overrides C<create> from L<Class::MOP::Package> to provide these additional
options:
=over 4
=item C<version>
A version number, to be installed in the C<$VERSION> package global variable.
=item C<authority>
An authority, to be installed in the C<$AUTHORITY> package global variable.
This is a legacy field and its use is not recommended.
=back
=head2 $metamodule->version
This is a read-only attribute which returns the C<$VERSION> of the
package, if one exists.
=head2 $metamodule->authority
This is a read-only attribute which returns the C<$AUTHORITY> of the
package, if one exists.
=head2 $metamodule->identifier
This constructs a string which combines the name, version and
authority.
=head2 Class::MOP::Module->meta
This will return a L<Class::MOP::Class> instance for this class.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,196 @@
package Class::MOP::Object;
our $VERSION = '2.2014';
use strict;
use warnings;
use parent 'Class::MOP::Mixin';
use Scalar::Util 'blessed';
use Module::Runtime;
# introspection
sub throw_error {
shift->_throw_exception( Legacy => message => join('', @_) );
}
sub _inline_throw_error {
my ( $self, $message ) = @_;
return 'die Module::Runtime::use_module("Moose::Exception::Legacy")->new(message => ' . $message. ')';
}
sub _new {
Class::MOP::class_of(shift)->new_object(@_);
}
# RANT:
# Cmon, how many times have you written
# the following code while debugging:
#
# use Data::Dumper;
# warn Dumper $obj;
#
# It can get seriously annoying, so why
# not just do this ...
sub dump {
my $self = shift;
require Data::Dumper;
local $Data::Dumper::Maxdepth = shift || 1;
Data::Dumper::Dumper $self;
}
sub _real_ref_name {
my $self = shift;
return blessed($self);
}
sub _is_compatible_with {
my $self = shift;
my ($other_name) = @_;
return $self->isa($other_name);
}
sub _can_be_made_compatible_with {
my $self = shift;
return !$self->_is_compatible_with(@_)
&& defined($self->_get_compatible_metaclass(@_));
}
sub _make_compatible_with {
my $self = shift;
my ($other_name) = @_;
my $new_metaclass = $self->_get_compatible_metaclass($other_name);
unless ( defined $new_metaclass ) {
$self->_throw_exception( CannotMakeMetaclassCompatible => superclass_name => $other_name,
class => $self,
);
}
# can't use rebless_instance here, because it might not be an actual
# subclass in the case of, e.g. moose role reconciliation
$new_metaclass->meta->_force_rebless_instance($self)
if blessed($self) ne $new_metaclass;
return $self;
}
sub _get_compatible_metaclass {
my $self = shift;
my ($other_name) = @_;
return $self->_get_compatible_metaclass_by_subclassing($other_name);
}
sub _get_compatible_metaclass_by_subclassing {
my $self = shift;
my ($other_name) = @_;
my $meta_name = blessed($self) ? $self->_real_ref_name : $self;
if ($meta_name->isa($other_name)) {
return $meta_name;
}
elsif ($other_name->isa($meta_name)) {
return $other_name;
}
return;
}
1;
# ABSTRACT: Base class for metaclasses
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Object - Base class for metaclasses
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
This class is a very minimal base class for metaclasses.
=head1 METHODS
This class provides a few methods which are useful in all metaclasses.
=head2 Class::MOP::???->meta
This returns a L<Class::MOP::Class> object.
=head2 $metaobject->dump($max_depth)
This method uses L<Data::Dumper> to dump the object. You can pass an
optional maximum depth, which will set C<$Data::Dumper::Maxdepth>. The
default maximum depth is 1.
=head2 $metaclass->throw_error($message)
This method calls L<Class::MOP::Mixin/_throw_exception> internally, with an object
of class L<Moose::Exception::Legacy>.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,340 @@
package Class::MOP::Overload;
our $VERSION = '2.2014';
use strict;
use warnings;
use overload ();
use Scalar::Util qw( blessed weaken );
use Try::Tiny;
use parent 'Class::MOP::Object';
my %Operators = (
map { $_ => 1 }
grep { $_ ne 'fallback' }
map { split /\s+/ } values %overload::ops
);
sub new {
my ( $class, %params ) = @_;
unless ( defined $params{operator} ) {
$class->_throw_exception('OverloadRequiresAnOperator');
}
unless ( $Operators{ $params{operator} } ) {
$class->_throw_exception(
'InvalidOverloadOperator',
operator => $params{operator},
);
}
unless ( defined $params{method_name} || $params{coderef} ) {
$class->_throw_exception(
'OverloadRequiresAMethodNameOrCoderef',
operator => $params{operator},
);
}
if ( $params{coderef} ) {
unless ( defined $params{coderef_package}
&& defined $params{coderef_name} ) {
$class->_throw_exception('OverloadRequiresNamesForCoderef');
}
}
if ( $params{method}
&& !try { $params{method}->isa('Class::MOP::Method') } ) {
$class->_throw_exception('OverloadRequiresAMetaMethod');
}
if ( $params{associated_metaclass}
&& !try { $params{associated_metaclass}->isa('Class::MOP::Module') } )
{
$class->_throw_exception('OverloadRequiresAMetaClass');
}
my @optional_attrs
= qw( method_name coderef coderef_package coderef_name method associated_metaclass );
return bless {
operator => $params{operator},
map { defined $params{$_} ? ( $_ => $params{$_} ) : () }
@optional_attrs
},
$class;
}
sub operator { $_[0]->{operator} }
sub method_name { $_[0]->{method_name} }
sub has_method_name { exists $_[0]->{method_name} }
sub method { $_[0]->{method} }
sub has_method { exists $_[0]->{method} }
sub coderef { $_[0]->{coderef} }
sub has_coderef { exists $_[0]->{coderef} }
sub coderef_package { $_[0]->{coderef_package} }
sub has_coderef_package { exists $_[0]->{coderef_package} }
sub coderef_name { $_[0]->{coderef_name} }
sub has_coderef_name { exists $_[0]->{coderef_name} }
sub associated_metaclass { $_[0]->{associated_metaclass} }
sub is_anonymous {
my $self = shift;
return $self->has_coderef && $self->coderef_name eq '__ANON__';
}
sub attach_to_class {
my ( $self, $class ) = @_;
$self->{associated_metaclass} = $class;
weaken $self->{associated_metaclass};
}
sub clone {
my $self = shift;
my $clone = bless { %{$self}, @_ }, blessed($self);
weaken $clone->{associated_metaclass} if $clone->{associated_metaclass};
$clone->_set_original_overload($self);
return $clone;
}
sub original_overload { $_[0]->{original_overload} }
sub _set_original_overload { $_[0]->{original_overload} = $_[1] }
sub _is_equal_to {
my $self = shift;
my $other = shift;
if ( $self->has_coderef ) {
return unless $other->has_coderef;
return $self->coderef == $other->coderef;
}
else {
return $self->method_name eq $other->method_name;
}
}
1;
# ABSTRACT: Overload Meta Object
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Overload - Overload Meta Object
=head1 VERSION
version 2.2014
=head1 SYNOPSIS
my $meta = Class->meta;
my $overload = $meta->get_overloaded_operator('+');
if ( $overload->has_method_name ) {
print 'Method for + is ', $overload->method_name, "\n";
}
else {
print 'Overloading for + is implemented by ',
$overload->coderef_name, " sub\n";
}
=head1 DESCRIPTION
This class provides meta information for overloading in classes and roles.
=head1 INHERITANCE
C<Class::MOP::Overload> is a subclass of L<Class::MOP::Object>.
=head1 METHODS
=head2 Class::MOP::Overload->new(%options)
This method creates a new C<Class::MOP::Overload> object. It accepts a number
of options:
=over 4
=item * operator
This is a string that matches an operator known by the L<overload> module,
such as C<""> or C<+>. This is required.
=item * method_name
The name of the method which implements the overloading. Note that this does
not need to actually correspond to a real method, since it's okay to declare a
not-yet-implemented overloading.
Either this or the C<coderef> option must be passed.
=item * method
A L<Class::MOP::Method> object for the method which implements the
overloading.
This is optional.
=item * coderef
A coderef which implements the overloading.
Either this or the C<method_name> option must be passed.
=item * coderef_package
The package where the coderef was defined.
This is required if C<coderef> is passed.
=item * coderef_name
The name of the coderef. This can be "__ANON__".
This is required if C<coderef> is passed.
=item * associated_metaclass
A L<Class::MOP::Module> object for the associated class or role.
This is optional.
=back
=head2 $overload->operator
Returns the operator for this overload object.
=head2 $overload->method_name
Returns the method name that implements overloading, if it has one.
=head2 $overload->has_method_name
Returns true if the object has a method name.
=head2 $overload->method
Returns the L<Class::MOP::Method> that implements overloading, if it has one.
=head2 $overload->has_method
Returns true if the object has a method.
=head2 $overload->coderef
Returns the coderef that implements overloading, if it has one.
=head2 $overload->has_coderef
Returns true if the object has a coderef.
=head2 $overload->coderef_package
Returns the package for the coderef that implements overloading, if it has
one.
=head2 $overload->has_coderef
Returns true if the object has a coderef package.
=head2 $overload->coderef_name
Returns the sub name for the coderef that implements overloading, if it has
one.
=head2 $overload->has_coderef_name
Returns true if the object has a coderef name.
=head2 $overload->is_anonymous
Returns true if the overloading is implemented by an anonymous coderef.
=head2 $overload->associated_metaclass
Returns the L<Class::MOP::Module> (class or role) that is associated with the
overload object.
=head2 $overload->clone
Clones the overloading object, setting C<original_overload> in the process.
=head2 $overload->original_overload
For cloned objects, this returns the L<Class::MOP::Overload> object from which
they were cloned. This can be used to determine the source of an overloading
in a class that came from a role, for example.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,460 @@
package Class::MOP::Package;
our $VERSION = '2.2014';
use strict;
use warnings;
use Scalar::Util 'blessed', 'weaken';
use Devel::GlobalDestruction 'in_global_destruction';
use Module::Runtime 'module_notional_filename';
use Package::Stash;
use parent 'Class::MOP::Object';
# creation ...
sub initialize {
my ( $class, @args ) = @_;
unshift @args, "package" if @args % 2;
my %options = @args;
my $package_name = delete $options{package};
# we hand-construct the class until we can bootstrap it
if ( my $meta = Class::MOP::get_metaclass_by_name($package_name) ) {
return $meta;
} else {
my $meta = ( ref $class || $class )->_new({
'package' => $package_name,
%options,
});
Class::MOP::store_metaclass_by_name($package_name, $meta);
Class::MOP::weaken_metaclass($package_name) if $options{weaken};
return $meta;
}
}
sub reinitialize {
my ( $class, @args ) = @_;
unshift @args, "package" if @args % 2;
my %options = @args;
my $package_name = delete $options{package};
(defined $package_name && $package_name
&& (!blessed $package_name || $package_name->isa('Class::MOP::Package')))
|| $class->_throw_exception( MustPassAPackageNameOrAnExistingClassMOPPackageInstance => params => \%options,
class => $class
);
$package_name = $package_name->name
if blessed $package_name;
Class::MOP::remove_metaclass_by_name($package_name);
$class->initialize($package_name, %options); # call with first arg form for compat
}
sub create {
my $class = shift;
my @args = @_;
my $meta = $class->initialize(@args);
my $filename = module_notional_filename($meta->name);
$INC{$filename} = '(set by Moose)'
unless exists $INC{$filename};
return $meta;
}
## ANON packages
{
# NOTE:
# this should be sufficient, if you have a
# use case where it is not, write a test and
# I will change it.
my $ANON_SERIAL = 0;
my %ANON_PACKAGE_CACHE;
# NOTE:
# we need a sufficiently annoying prefix
# this should suffice for now, this is
# used in a couple of places below, so
# need to put it up here for now.
sub _anon_package_prefix { 'Class::MOP::Package::__ANON__::SERIAL::' }
sub is_anon {
my $self = shift;
no warnings 'uninitialized';
my $prefix = $self->_anon_package_prefix;
$self->name =~ /^\Q$prefix/;
}
sub create_anon {
my ($class, %options) = @_;
my $cache_ok = delete $options{cache};
$options{weaken} = !$cache_ok unless exists $options{weaken};
my $cache_key;
if ($cache_ok) {
$cache_key = $class->_anon_cache_key(%options);
undef $cache_ok if !defined($cache_key);
}
if ($cache_ok) {
if (defined $ANON_PACKAGE_CACHE{$cache_key}) {
return $ANON_PACKAGE_CACHE{$cache_key};
}
}
my $package_name = $class->_anon_package_prefix . ++$ANON_SERIAL;
my $meta = $class->create($package_name, %options);
if ($cache_ok) {
$ANON_PACKAGE_CACHE{$cache_key} = $meta;
weaken($ANON_PACKAGE_CACHE{$cache_key});
}
return $meta;
}
sub _anon_cache_key {
my $class = shift;
my %options = @_;
$class->_throw_exception( PackagesAndModulesAreNotCachable => class_name => $class,
params => \%options,
is_module => 0
);
}
sub DESTROY {
my $self = shift;
return if in_global_destruction(); # it'll happen soon anyway and this just makes things more complicated
$self->_free_anon
if $self->is_anon;
}
sub _free_anon {
my $self = shift;
my $name = $self->name;
# Moose does a weird thing where it replaces the metaclass for
# class when fixing metaclass incompatibility. In that case,
# we don't want to clean out the namespace now. We can detect
# that because Moose will explicitly update the singleton
# cache in Class::MOP using store_metaclass_by_name, which
# means that the new metaclass will already exist in the cache
# by this point.
# The other options here are that $current_meta can be undef if
# remove_metaclass_by_name is called explicitly (since the hash
# entry is removed first, and then this destructor is called),
# or that $current_meta can be the same as $self, which happens
# when the metaclass goes out of scope (since the weak reference
# in the metaclass cache won't be freed until after this
# destructor runs).
my $current_meta = Class::MOP::get_metaclass_by_name($name);
return if defined($current_meta) && $current_meta ne $self;
my ($first_fragments, $last_fragment) = ($name =~ /^(.*)::(.*)$/);
no strict 'refs';
# clear @ISA first, to avoid a memory leak
# see https://rt.perl.org/rt3/Public/Bug/Display.html?id=92708
@{$name . '::ISA'} = ();
%{$name . '::'} = ();
delete ${$first_fragments . '::'}{$last_fragment . '::'};
Class::MOP::remove_metaclass_by_name($name);
delete $INC{module_notional_filename($name)};
}
}
sub _new {
my $class = shift;
return Class::MOP::Class->initialize($class)->new_object(@_)
if $class ne __PACKAGE__;
my $params = @_ == 1 ? $_[0] : {@_};
return bless {
# Need to quote package to avoid a problem with PPI mis-parsing this
# as a package statement.
'package' => $params->{package},
# NOTE:
# because of issues with the Perl API
# to the typeglob in some versions, we
# need to just always grab a new
# reference to the hash in the accessor.
# Ideally we could just store a ref and
# it would Just Work, but oh well :\
namespace => \undef,
} => $class;
}
# Attributes
# NOTE:
# all these attribute readers will be bootstrapped
# away in the Class::MOP bootstrap section
sub _package_stash {
$_[0]->{_package_stash} ||= Package::Stash->new($_[0]->name)
}
sub namespace {
$_[0]->_package_stash->namespace
}
# Class attributes
# ... these functions have to touch the symbol table itself,.. yuk
sub add_package_symbol {
my $self = shift;
$self->_package_stash->add_symbol(@_);
}
sub remove_package_glob {
my $self = shift;
$self->_package_stash->remove_glob(@_);
}
# ... these functions deal with stuff on the namespace level
sub has_package_symbol {
my $self = shift;
$self->_package_stash->has_symbol(@_);
}
sub get_package_symbol {
my $self = shift;
$self->_package_stash->get_symbol(@_);
}
sub get_or_add_package_symbol {
my $self = shift;
$self->_package_stash->get_or_add_symbol(@_);
}
sub remove_package_symbol {
my $self = shift;
$self->_package_stash->remove_symbol(@_);
}
sub list_all_package_symbols {
my $self = shift;
$self->_package_stash->list_all_symbols(@_);
}
sub get_all_package_symbols {
my $self = shift;
$self->_package_stash->get_all_symbols(@_);
}
1;
# ABSTRACT: Package Meta Object
__END__
=pod
=encoding UTF-8
=head1 NAME
Class::MOP::Package - Package Meta Object
=head1 VERSION
version 2.2014
=head1 DESCRIPTION
The Package Protocol provides an abstraction of a Perl 5 package. A
package is basically namespace, and this module provides methods for
looking at and changing that namespace's symbol table.
=head1 METHODS
=head2 Class::MOP::Package->initialize($package_name, %options)
This method creates a new C<Class::MOP::Package> instance which
represents specified package. If an existing metaclass object exists
for the package, that will be returned instead. No options are valid at the
package level.
=head2 Class::MOP::Package->reinitialize($package, %options)
This method forcibly removes any existing metaclass for the package
before calling C<initialize>. In contrast to C<initialize>, you may
also pass an existing C<Class::MOP::Package> instance instead of just
a package name as C<$package>.
Do not call this unless you know what you are doing.
=head2 Class::MOP::Package->create($package, %options)
Creates a new C<Class::MOP::Package> instance which represents the specified
package, and also does some initialization of that package. Currently, this
just does the same thing as C<initialize>, but is overridden in subclasses,
such as C<Class::MOP::Class>.
=head2 Class::MOP::Package->create_anon(%options)
Creates a new anonymous package. Valid keys for C<%options> are:
=over 4
=item C<cache>
If this will be C<true> (the default is C<false>), the instance will be cached
in C<Class::MOP>'s metaclass cache.
=item C<weaken>
If this is C<true> (the default C<true> when L<cache> is C<false>), the instance
stored in C<Class::MOP>'s metaclass cache will be weakened, so that the
anonymous package will be garbage collected when the returned instance goes out
of scope.
=back
=head2 $metapackage->is_anon
Returns true if the package is an anonymous package.
=head2 $metapackage->name
This is returns the package's name, as passed to the constructor.
=head2 $metapackage->namespace
This returns a hash reference to the package's symbol table. The keys
are symbol names and the values are typeglob references.
=head2 $metapackage->add_package_symbol($variable_name, $initial_value)
This method accepts a variable name and an optional initial value. The
C<$variable_name> must contain a leading sigil.
This method creates the variable in the package's symbol table, and
sets it to the initial value if one was provided.
=head2 $metapackage->get_package_symbol($variable_name)
Given a variable name, this method returns the variable as a reference
or undef if it does not exist. The C<$variable_name> must contain a
leading sigil.
=head2 $metapackage->get_or_add_package_symbol($variable_name)
Given a variable name, this method returns the variable as a reference.
If it does not exist, a default value will be generated if possible. The
C<$variable_name> must contain a leading sigil.
=head2 $metapackage->has_package_symbol($variable_name)
Returns true if there is a package variable defined for
C<$variable_name>. The C<$variable_name> must contain a leading sigil.
=head2 $metapackage->remove_package_symbol($variable_name)
This will remove the package variable specified C<$variable_name>. The
C<$variable_name> must contain a leading sigil.
=head2 $metapackage->remove_package_glob($glob_name)
Given the name of a glob, this will remove that glob from the
package's symbol table. Glob names do not include a sigil. Removing
the glob removes all variables and subroutines with the specified
name.
=head2 $metapackage->list_all_package_symbols($type_filter)
This will list all the glob names associated with the current
package. These names do not have leading sigils.
You can provide an optional type filter, which should be one of
'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
=head2 $metapackage->get_all_package_symbols($type_filter)
This works much like C<list_all_package_symbols>, but it returns a
hash reference. The keys are glob names and the values are references
to the value for that name.
=head2 Class::MOP::Package->meta
This will return a L<Class::MOP::Class> instance for this class.
=head1 AUTHORS
=over 4
=item *
Stevan Little <stevan@cpan.org>
=item *
Dave Rolsky <autarch@urth.org>
=item *
Jesse Luehrs <doy@cpan.org>
=item *
Shawn M Moore <sartak@cpan.org>
=item *
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Hans Dieter Pearcey <hdp@cpan.org>
=item *
Chris Prather <chris@prather.org>
=item *
Matt S Trout <mstrout@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut