Class-Method-Delegate

 view release on metacpan or  search on metacpan

lib/Class/Method/Delegate.pm  view on Meta::CPAN

package Class::Method::Delegate;

use 5.010000;
use strict;
use warnings;
use Carp;
use Scalar::Util qw(blessed);

our $VERSION = '1.03';

sub import {
  my $class = shift;
  no strict 'refs';

  my $caller = caller;
  # Wants delegate
  *{"${caller}::delegate"} = sub { delegate($caller, @_) };

  strict->import;
}

sub delegate {
  my $class = shift;
  my $options = @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {};
  my ($methods, $object, $handlers);

  if (exists $options->{'methods'}) {
    $methods = $options->{'methods'};
    croak 'methods undefined' unless $methods;
    croak 'methods not arrayref' unless ref($methods) eq 'ARRAY';
    croak 'methods empty' if 0 == @$methods;
  } else {
    croak "Can't delegate without methods";
  }
  if (exists $options->{'to'}) {
      $object = $options->{'to'};
      croak 'to undefined' unless $object;
      croak 'to not coderef' unless ref($object) eq 'CODE';
  } else {
      croak "Can't delegate without an object";
  }
  if (exists $options->{'class'}) {
    $class = $options->{'class'};
    croak 'class undefined or empty' unless $class;
  }
  if (exists $options->{'handlers'}) {
      $handlers = $options->{'handlers'};
      croak 'handlers undefined' unless $handlers;
      croak 'handlers not arrayref' unless ref($handlers) eq 'ARRAY';
      croak 'too few handlers' if @$handlers < @$methods;
      croak 'too many handlers' if @$handlers > @$methods;
  } else {
      $handlers = $methods;
  }

  no strict 'refs';
  #Inject a method 
  my $i = 0;
  for my $method (@$methods) {
    my $handler = $handlers->[$i++];
    *{"${class}::$method"} = sub {
      my $self = shift;
      my $delegation_object = &$object($self);
      croak "You are trying to delegate to something that is not an object" unless blessed( $delegation_object );
      if($delegation_object->can('delegated_by')) {
        $delegation_object->delegated_by($self);
      }
      $delegation_object->$handler(@_);
    }
  }
  strict->import;
}

1;
__END__

=head1 NAME

Class::Method::Delegate - Perl extension to help you add delegation to your classes

=head1 SYNOPSIS

  use Class::Method::Delegate;
  use Package::To::Delegate::To;
  delegate methods => [ 'hello', 'goodbye' ], to => sub { Package::To::Delegate::To->new() };
  delegate methods => [ 'wave' ], to => sub { shift->{gestures} };
  delegate methods => [ 'walk', 'run' ], to => sub { self->{movements} ||= Package::To::Delegate::To->new() };

  delegate methods => [ 'walk', 'run' ], to => \&some_subroutine, handlers => [ 'slow', 'fast' ];

=head1 DESCRIPTION

Creates methods on the current class which delegate to an object.

delegate takes a hash or hashref with the following keys.

methods

Takes an array ref of strings that represent the name of the method to be delegated.

to

a sub block that returns an object, which the method calls will be sent to.

=head2 Accessing the parent from inside the delegated class.

If the object you are delegating to has a method called delegated_by, then this will be called when delegating.
The $self of the package doing the delegating will be passed in, so you can then store it.

=head2 EXPORT

delegate

=head1 SEE ALSO

Check out Class:Delegator and Class::Delegation for alternatives.

=head1 AUTHOR

Jonathan Taylor, E<lt>jon@stackhaus.comE<gt>

Version 1.03 contributed by James Buster

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2012 by Jonathan Taylor

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.14.2 or,
at your option, any later version of Perl 5 you may have available.



( run in 2.404 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )