The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Class::Component::Component::Autocall::InjectMethod;

use strict;
use warnings;

use Carp::Clan qw/Class::Component/;

sub register_method {
    my($self, @methods) = @_;
    my $class = ref($self) || $self;

    $self->NEXT( register_method => @methods );                                                                                                                
    while (my($method, $plugin) = splice @methods, 0, 2) {
        next unless $plugin;
        no strict 'refs';
        no warnings 'redefine';
        unless (ref $plugin eq 'HASH') {
            *{"$class\::$method"} = sub { $plugin->$method(shift, @_) };
            next;
        }

        # extend method
        my $obj         = $plugin;
        $plugin         = $obj->{plugin};
        my $real_method = $obj->{method};
        next unless $plugin && $real_method;
        if (ref $real_method eq 'CODE') {
            *{"$class\::$method"} = sub { $real_method->($plugin, shift, @_) };
        } elsif (!ref($real_method)) {
            *{"$class\::$method"} = sub { $plugin->$real_method(shift, @_) };
        }
    }
}

sub remove_method {
    my($self, @methods) = @_;
    $self->NEXT( remove_method => @methods );
    while (my($method, $plugin) = splice @methods, 0, 2) {
        no strict 'refs';
        delete ${ref($self) . "::"}{$method};
    }
}

1;