Class::MOP::Method::Wrapped
Class::MOP::Method::Meta
+ Class::MOP::Method::Overload
/;
$_->meta->make_immutable(
--- /dev/null
+
+package Class::MOP::Method::Overload;
+
+use strict;
+use warnings;
+
+use Carp 'confess';
+
+use base 'Class::MOP::Method';
+
+sub wrap {
+ my $class = shift;
+ my (@args) = @_;
+ unshift @args, 'body' if @args % 2 == 1;
+ my %params = @args;
+
+ confess "op is required"
+ unless exists $params{op};
+
+ return $class->SUPER::wrap(
+ name => "($params{op}",
+ %params,
+ );
+}
+
+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
+ 'op' => $params->{op},
+ } => $class;
+}
+
+1;
use warnings;
use Class::MOP::Method::Meta;
+use Class::MOP::Method::Overload;
use Scalar::Util 'blessed';
use Carp 'confess';
use Sub::Name 'subname';
+use overload ();
+
use base 'Class::MOP::Mixin';
sub _meta_method_class { 'Class::MOP::Method::Meta' }
return $self->_method_map;
}
+# overloading
+
+my $overload_ops;
+sub overload_ops {
+ $overload_ops ||= [map { split /\s+/ } values %overload::ops];
+}
+
+# XXX this could probably stand to be cached, but i figure it should be
+# uncommon enough to not particularly matter
+sub _overload_map {
+ my $self = shift;
+
+ return {} unless overload::Overloaded($self->name);
+
+ my %map;
+ for my $op (@{ $self->overload_ops }) {
+ my $body = overload::Method($self->name, $op);
+ next unless defined $body;
+ $map{$op} = $body;
+ }
+
+ return \%map;
+}
+
+sub get_overload_list {
+ my $self = shift;
+ my $map = $self->_overload_map;
+ return map { $self->_wrap_overload($_, $map->{$_}) } keys $map;
+}
+
+sub get_overloaded_ops {
+ my $self = shift;
+ return keys $self->_overload_map;
+}
+
+sub has_overloaded_op {
+ my $self = shift;
+ my ($op) = @_;
+ return defined overload::Method($op);
+}
+
+sub get_overloaded_op {
+ my $self = shift;
+ my ($op) = @_;
+ my $body = overload::Method($op);
+ return unless defined $body;
+ return $self->_wrap_overload($op, $body);
+}
+
+sub add_overload {
+ my $self = shift;
+ my ($op, $body) = @_;
+ overload->import($op => $body);
+}
+
+sub _wrap_overload {
+ my $self = shift;
+ my ($op, $body) = @_;
+ return Class::MOP::Method::Overload->wrap(
+ op => $op,
+ package_name => $self->name,
+ associated_metaclass => $self,
+ body => $body,
+ );
+}
+
1;
# ABSTRACT: Methods for metaclasses which have methods
DECLARE_KEY(wrapped_method_metaclass),
DECLARE_KEY(writer),
DECLARE_KEY_WITH_VALUE(package_cache_flag, "_package_cache_flag"),
- DECLARE_KEY_WITH_VALUE(_version, "-version")
+ DECLARE_KEY_WITH_VALUE(_version, "-version"),
+ DECLARE_KEY(op)
};
SV *
KEY_writer,
KEY_package_cache_flag,
KEY__version,
+ KEY_op,
key_last,
} mop_prehashed_key_t;
use_ok('Class::MOP::Method::Accessor');
use_ok('Class::MOP::Method::Constructor');
use_ok('Class::MOP::Method::Meta');
+ use_ok('Class::MOP::Method::Overload');
use_ok('Class::MOP::Instance');
use_ok('Class::MOP::Object');
}
'Class::MOP::Method::Accessor' => Class::MOP::Method::Accessor->meta,
'Class::MOP::Method::Constructor' => Class::MOP::Method::Constructor->meta,
'Class::MOP::Method::Meta' => Class::MOP::Method::Meta->meta,
+ 'Class::MOP::Method::Overload' => Class::MOP::Method::Overload->meta,
'Class::MOP::Mixin' => Class::MOP::Mixin->meta,
'Class::MOP::Mixin::AttributeCore' => Class::MOP::Mixin::AttributeCore->meta,
'Class::MOP::Mixin::HasAttributes' => Class::MOP::Mixin::HasAttributes->meta,
Class::MOP::Method::Generated->meta,
Class::MOP::Method::Inlined->meta,
Class::MOP::Method::Meta->meta,
+ Class::MOP::Method::Overload->meta,
Class::MOP::Method::Wrapped->meta,
Class::MOP::Mixin->meta,
Class::MOP::Mixin::AttributeCore->meta,
Class::MOP::Method::Inlined
Class::MOP::Method::Wrapped
Class::MOP::Method::Meta
+ Class::MOP::Method::Overload
Class::MOP::Module
Class::MOP::Object
Class::MOP::Package
--- /dev/null
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use Test::More;
+
+{
+ package Foo;
+ use Moose;
+}
+
+{
+ is_deeply([Foo->meta->get_overload_list], []);
+ is_deeply([Foo->meta->get_overloaded_ops], []);
+}
+
+my $plus;
+my $plus_impl;
+BEGIN { $plus_impl = sub { $plus = 1; $_[0] + $_[1] } }
+{
+ package Foo::Overloaded;
+ use Moose;
+ use overload '+' => $plus_impl;
+}
+
+{
+ is_deeply([Foo::Overloaded->meta->get_overloaded_ops], ['+']);
+ my @overloads = Foo::Overloaded->meta->get_overload_list;
+ is(scalar(@overloads), 1);
+ my $plus_meth = $overloads[0];
+ isa_ok($plus_meth, 'Class::MOP::Method::Overload');
+ is($plus_meth->op, '+');
+ is($plus_meth->name, '(+');
+ is($plus_meth->body, $plus_impl);
+ is($plus_meth->package_name, 'Foo::Overloaded');
+ is($plus_meth->associated_metaclass, Foo::Overloaded->meta);
+}
+
+done_testing;
XS_EXTERNAL(boot_Class__MOP__Method);
XS_EXTERNAL(boot_Class__MOP__Method__Inlined);
XS_EXTERNAL(boot_Class__MOP__Method__Generated);
+XS_EXTERNAL(boot_Class__MOP__Method__Overload);
XS_EXTERNAL(boot_Class__MOP__Class);
XS_EXTERNAL(boot_Class__MOP__Attribute);
XS_EXTERNAL(boot_Class__MOP__Instance);
MOP_CALL_BOOT (boot_Class__MOP__Method);
MOP_CALL_BOOT (boot_Class__MOP__Method__Inlined);
MOP_CALL_BOOT (boot_Class__MOP__Method__Generated);
+ MOP_CALL_BOOT (boot_Class__MOP__Method__Overload);
MOP_CALL_BOOT (boot_Class__MOP__Class);
MOP_CALL_BOOT (boot_Class__MOP__Attribute);
MOP_CALL_BOOT (boot_Class__MOP__Instance);
--- /dev/null
+#include "mop.h"
+
+MODULE = Class::MOP::Method::Overload PACKAGE = Class::MOP::Method::Overload
+
+PROTOTYPES: DISABLE
+
+BOOT:
+ INSTALL_SIMPLE_READER(Method::Overload, op);