use MRO::Compat;
-use Carp 'confess';
-use Scalar::Util 'weaken';
+use Carp 'confess';
+use Scalar::Util 'weaken';
use Class::MOP::Class;
use Class::MOP::Attribute;
our $VERSION = '0.56';
our $AUTHORITY = 'cpan:STEVAN';
- use XSLoader;
- XSLoader::load( 'Class::MOP', $VERSION );
-
*IS_RUNNING_ON_5_10 = ($] < 5.009_005)
? sub () { 0 }
- : sub () { 1 };
-
- # get it from MRO::Compat now ...
- *check_package_cache_flag = \&mro::get_pkg_gen;
+ : sub () { 1 };
- # UNCOMMENT ME TO TEST WITHOUT XS
- #no warnings 'prototype', 'redefine';
- #*check_package_cache_flag = \&MRO::Compat::__get_pkg_gen_pp
+ # NOTE:
+ # we may not use this yet, but once
+ # the get_code_info XS gets merged
+ # upstream to it, we will always use
+ # it. But for now it is just kinda
+ # extra overhead.
+ # - SL
+ require Sub::Identify;
+
+ # stash these for a sec, and see how things go
+ my $_PP_subname = sub { $_[1] };
+ my $_PP_get_code_info = sub ($) {
+ return (
+ Sub::Identify::stash_name($_[0]),
+ Sub::Identify::sub_name($_[0])
+ )
+ };
+
+ if ($ENV{CLASS_MOP_NO_XS} == 1) {
+ # NOTE:
+ # this is if you really want things
+ # to be slow, then you can force the
+ # no-XS rule this way, otherwise we
+ # make an effort to load as much of
+ # the XS as possible.
+ # - SL
+ no warnings 'prototype', 'redefine';
+ # get this from MRO::Compat ...
+ *check_package_cache_flag = \&MRO::Compat::__get_pkg_gen_pp;
+ # our own version of Sub::Name
+ *subname = $_PP_subname;
+ # and the Sub::Identify version of the get_code_info
+ *get_code_info = $_PP_get_code_info;
+ }
+ else {
+ # now try our best to get as much
+ # of the XS loaded as possible
+ {
+ local $@;
+ eval {
+ require XSLoader;
+ XSLoader::load( 'Class::MOP', $VERSION );
+ };
+ die $@ if $@ && $@ !~ /object version|loadable object/;
+
+ # okay, so the XS failed to load, so
+ # use the pure perl one instead.
+ *get_code_info = $_PP_get_code_info if $@;
+ }
+
+ # get it from MRO::Compat
+ *check_package_cache_flag = \&mro::get_pkg_gen;
+
+ # now try and load the Sub::Name
+ # module and use that as a means
+ # for naming our CVs, if not, we
+ # use the workaround instead.
+ if ( eval { require Sub::Name } ) {
+ *subname = sub {
+ #warn "Class::MOP::subname called with @_";
+ Sub::Name::subname(@_);
+ };
+ }
+ else {
+ *subname = $_PP_subname;
+ }
+ }
}
{
))
);
+Class::MOP::Method->meta->add_attribute(
+ Class::MOP::Attribute->new('$!package_name' => (
+ init_arg => 'package_name',
+ reader => { 'package_name' => \&Class::MOP::Method::package_name },
+ ))
+);
+
+Class::MOP::Method->meta->add_attribute(
+ Class::MOP::Attribute->new('$!name' => (
+ init_arg => 'name',
+ reader => { 'name' => \&Class::MOP::Method::name },
+ ))
+);
+
+Class::MOP::Method->meta->add_method('wrap' => sub {
+ my $class = shift;
+ my $code = shift;
+ my %options = @_;
+
+ ('CODE' eq (Scalar::Util::reftype($code) || ''))
+ || confess "You must supply a CODE reference to bless, not (" . ($code || 'undef') . ")";
+
+ # return the new object
+ $class->meta->new_object(body => $code, %options);
+});
+
+Class::MOP::Method->meta->add_method('clone' => sub {
+ my $self = shift;
+ $self->meta->clone_object($self, @_);
+});
+
## --------------------------------------------------------
## Class::MOP::Method::Wrapped
Class::MOP::Attribute->new('$!is_inline' => (
init_arg => 'is_inline',
reader => { 'is_inline' => \&Class::MOP::Method::Generated::is_inline },
+ default => 0,
))
);
+Class::MOP::Method::Generated->meta->add_method('new' => sub {
+ my ($class, %options) = @_;
+ my $self = $class->meta->new_object(%options);
+ $self->initialize_body;
+ $self;
+});
+
## --------------------------------------------------------
## Class::MOP::Method::Accessor
))
);
+Class::MOP::Method::Accessor->meta->add_method('new' => sub {
+ my $class = shift;
+ my %options = @_;
+
+ (exists $options{attribute})
+ || confess "You must supply an attribute to construct with";
+
+ (exists $options{accessor_type})
+ || confess "You must supply an accessor_type to construct with";
+
+ (Scalar::Util::blessed($options{attribute}) && $options{attribute}->isa('Class::MOP::Attribute'))
+ || confess "You must supply an attribute which is a 'Class::MOP::Attribute' instance";
+
+ # return the new object
+ my $self = $class->meta->new_object(%options);
+
+ # we don't want this creating
+ # a cycle in the code, if not
+ # needed
+ Scalar::Util::weaken($self->{'$!attribute'});
+
+ $self->initialize_body;
+
+ $self;
+});
+
## --------------------------------------------------------
## Class::MOP::Method::Constructor
reader => {
'options' => \&Class::MOP::Method::Constructor::options
},
+ default => sub { +{} }
))
);
))
);
+Class::MOP::Method::Constructor->meta->add_method('new' => sub {
+ my $class = shift;
+ my %options = @_;
+
+ (Scalar::Util::blessed $options{metaclass} && $options{metaclass}->isa('Class::MOP::Class'))
+ || confess "You must pass a metaclass instance if you want to inline"
+ if $options{is_inline};
+
+ # return the new object
+ my $self = $class->meta->new_object(%options);
+
+ # we don't want this creating
+ # a cycle in the code, if not
+ # needed
+ Scalar::Util::weaken($self->{'$!associated_metaclass'});
+
+ $self->initialize_body;
+
+ $self;
+});
+
## --------------------------------------------------------
## Class::MOP::Instance
is from and the name of the C<$code> itself. This is used by several
elements of the MOP to detemine where a given C<$code> reference is from.
+=item B<subname ($name, $code)>
+
+B<NOTE: DO NOT USE THIS FUNCTION, IT IS FOR INTERNAL USE ONLY!>
+
+If possible, we will load the L<Sub::Name> module and this will function
+as C<Sub::Name::subname> does, otherwise it will just return the C<$code>
+argument.
+
=back
=head2 Metaclass cache functions
(reftype($accessor) eq 'HASH')
|| confess "bad accessor/reader/writer/predicate/clearer format, must be a HASH ref";
my ($name, $method) = %{$accessor};
- $method = $self->accessor_metaclass->wrap($method);
+ $method = $self->accessor_metaclass->wrap(
+ $method,
+ package_name => $self->associated_class->name,
+ name => $name,
+ );
$self->associate_method($method);
return ($name, $method);
}
attribute => $self,
is_inline => $inline_me,
accessor_type => $type,
+ package_name => $self->associated_class->name,
+ name => $accessor,
);
};
confess "Could not create the '$type' method for " . $self->name . " because : $@" if $@;
use Carp 'confess';
use Scalar::Util 'blessed', 'reftype', 'weaken';
-use Sub::Name 'subname';
our $VERSION = '0.31';
our $AUTHORITY = 'cpan:STEVAN';
my $body;
if (blessed($method)) {
$body = $method->body;
+ if ($method->package_name ne $self->name &&
+ $method->name ne $method_name) {
+ warn "Hello there, got somethig for you."
+ . " Method says " . $method->package_name . " " . $method->name
+ . " Class says " . $self->name . " " . $method_name;
+ $method = $method->clone(
+ package_name => $self->name,
+ name => $method_name
+ ) if $method->can('clone');
+ }
}
else {
$body = $method;
('CODE' eq (reftype($body) || ''))
|| confess "Your code block must be a CODE reference";
- $method = $self->method_metaclass->wrap($body);
+ $method = $self->method_metaclass->wrap(
+ $body => (
+ package_name => $self->name,
+ name => $method_name
+ )
+ );
}
$self->get_method_map->{$method_name} = $method;
-
- my $full_method_name = ($self->name . '::' . $method_name);
- $self->add_package_symbol("&${method_name}" => subname $full_method_name => $body);
+
+ my $full_method_name = ($self->name . '::' . $method_name);
+ $self->add_package_symbol("&${method_name}" =>
+ Class::MOP::subname($full_method_name => $body)
+ );
$self->update_package_cache_flag;
}
(defined $method_name && $method_name)
|| confess "You must pass in a method name";
my $method = $fetch_and_prepare_method->($self, $method_name);
- $method->add_before_modifier(subname ':before' => $method_modifier);
+ $method->add_before_modifier(
+ Class::MOP::subname(':before' => $method_modifier)
+ );
}
sub add_after_method_modifier {
(defined $method_name && $method_name)
|| confess "You must pass in a method name";
my $method = $fetch_and_prepare_method->($self, $method_name);
- $method->add_after_modifier(subname ':after' => $method_modifier);
+ $method->add_after_modifier(
+ Class::MOP::subname(':after' => $method_modifier)
+ );
}
sub add_around_method_modifier {
(defined $method_name && $method_name)
|| confess "You must pass in a method name";
my $method = $fetch_and_prepare_method->($self, $method_name);
- $method->add_around_modifier(subname ':around' => $method_modifier);
+ $method->add_around_modifier(
+ Class::MOP::subname(':around' => $method_modifier)
+ );
}
# NOTE:
use Carp 'confess';
use Scalar::Util 'blessed';
-use Sub::Name 'subname';
our $VERSION = '0.06';
our $AUTHORITY = 'cpan:STEVAN';
$metaclass->add_method(
$options{constructor_name},
$constructor_class->new(
- options => \%options,
- metaclass => $metaclass,
- is_inline => 1,
+ options => \%options,
+ metaclass => $metaclass,
+ is_inline => 1,
+ package_name => $metaclass->name,
+ name => $options{constructor_name}
)
) unless $metaclass->has_method($options{constructor_name});
}
my $destructor_class = $options{destructor_class};
my $destructor = $destructor_class->new(
- options => \%options,
- metaclass => $metaclass,
+ options => \%options,
+ metaclass => $metaclass,
+ package_name => $metaclass->name,
+ name => 'DESTROY'
);
$metaclass->add_method('DESTROY' => $destructor)
use Carp 'confess';
use Scalar::Util 'reftype', 'blessed';
-our $VERSION = '0.06';
+our $VERSION = '0.07';
our $AUTHORITY = 'cpan:STEVAN';
use base 'Class::MOP::Object';
# construction
sub wrap {
- my $class = shift;
- my $code = shift;
+ my ( $class, $code, %params ) = @_;
+
('CODE' eq (reftype($code) || ''))
|| confess "You must supply a CODE reference to bless, not (" . ($code || 'undef') . ")";
+
bless {
- '&!body' => $code
+ '&!body' => $code,
+ '$!package_name' => $params{package_name},
+ '$!name' => $params{name},
} => blessed($class) || $class;
}
# informational
-# NOTE:
-# this may not be the same name
-# as the class you got it from
-# This gets the package stash name
-# associated with the actual CODE-ref
sub package_name {
- my $code = (shift)->body;
- (Class::MOP::get_code_info($code))[0];
+ my $self = shift;
+ $self->{'$!package_name'} ||= (Class::MOP::get_code_info($self->body))[0];
}
-# NOTE:
-# this may not be the same name
-# as the method name it is stored
-# with. This gets the name associated
-# with the actual CODE-ref
sub name {
- my $code = (shift)->body;
- (Class::MOP::get_code_info($code))[1];
+ my $self = shift;
+ $self->{'$!name'} ||= (Class::MOP::get_code_info($self->body))[1];
}
sub fully_qualified_name {
- my $code = shift;
- $code->package_name . '::' . $code->name;
+ my $code = shift;
+ $code->package_name . '::' . $code->name;
}
+# NOTE:
+# the Class::MOP bootstrap
+# will create this for us
+# - SL
+# sub clone { ... }
+
1;
__END__
=over 4
-=item B<wrap ($code)>
+=item B<wrap ($code, %params)>
This is the basic constructor, it returns a B<Class::MOP::Method>
-instance which wraps the given C<$code> reference.
+instance which wraps the given C<$code> reference. You can also
+set the C<package_name> and C<name> attributes using the C<%params>.
+If these are not set, then thier accessors will attempt to figure
+it out using the C<Class::MOP::get_code_info> function.
+
+=item B<clone (%params)>
+
+This will make a copy of the object, allowing you to override
+any values by stuffing them in C<%params>.
=back
my $self = bless {
# from our superclass
'&!body' => undef,
+ '$!package_name' => $options{package_name},
+ '$!name' => $options{name},
# specific to this subclass
'$!attribute' => $options{attribute},
'$!is_inline' => ($options{is_inline} || 0),
my $self = bless {
# from our superclass
- '&!body' => undef,
+ '&!body' => undef,
+ '$!package_name' => $options{package_name},
+ '$!name' => $options{name},
# specific to this subclass
'%!options' => $options{options} || {},
'$!associated_metaclass' => $options{metaclass},
my $self = bless {
# from our superclass
'&!body' => undef,
+ '$!package_name' => $options{package_name},
+ '$!name' => $options{name},
# specific to this subclass
'$!is_inline' => ($options{is_inline} || 0),
} => $class;
use Carp 'confess';
use Scalar::Util 'reftype', 'blessed';
-use Sub::Name 'subname';
our $VERSION = '0.02';
our $AUTHORITY = 'cpan:STEVAN';
};
sub wrap {
- my $class = shift;
- my $code = shift;
+ my ( $class, $code, %params ) = @_;
+
(blessed($code) && $code->isa('Class::MOP::Method'))
|| confess "Can only wrap blessed CODE";
+
my $modifier_table = {
cache => undef,
orig => $code,
},
};
$_build_wrapped_method->($modifier_table);
- my $method = $class->SUPER::wrap(sub { $modifier_table->{cache}->(@_) });
+ my $method = $class->SUPER::wrap(
+ sub { $modifier_table->{cache}->(@_) },
+ # get these from the original
+ # unless explicitly overriden
+ package_name => $params{package_name} || $code->package_name,
+ name => $params{name} || $code->name,
+ );
$method->{'%!modifier_table'} = $modifier_table;
$method;
}