IOC

 view release on metacpan or  search on metacpan

lib/IOC/Service.pm  view on Meta::CPAN

sub name {
    my ($self) = @_;
    return $self->{name};
}

sub setContainer {
    my ($self, $container) = @_;
    (blessed($container) && $container->isa('IOC::Container'))
        || throw IOC::InsufficientArguments "container argument is incorrect";
    $self->{container} = $container;
    $self;
}

sub removeContainer {
    my ($self) = @_;
    $self->{container} = undef;
    $self;
}

sub instance {
    my ($self) = @_;
    unless (defined $self->{_instance}) {
        (defined($self->{container}))
            || throw IOC::IllegalOperation "Cannot create a service instance without setting container";    
        my $instance = $self->{block}->($self->{container});
        $self->{_instance} = $instance unless defined $self->{_instance};
        (defined($self->{_instance})) 
            || throw IOC::InitializationError "Service creation block returned undefined value";
    }
    return $self->{_instance};
}

sub deferred {
    my ($self) = @_;
    return IOC::Service::Deferred->new($self);
}

sub DESTROY {
    my ($self) = @_;
    # remove the connnection to the instance
    # but do not attempt to DESTROY it, that
    # should be left up to the instance itself
    $self->{_instance} = undef if defined $self->{_instance};
    # remove the container instance as well
    # no need to DESTROY this either since 
    # not only could it still have other services
    # in it, but it it highly likely that the
    # call to DESTROY this object came from
    # its container anyway
    $self->{container} = undef if defined $self->{container};
}

package IOC::Service::Deferred;

use strict;
use warnings;

our $VERSION = '0.02';

use overload '%{}' => sub { 
                    return $_[0] if (caller)[0] eq 'IOC::Service::Deferred';
                    $_[0] = $_[0]->{service}->instance(); 
                    $_[0] 
              },
             '@{}' => sub { $_[0] = $_[0]->{service}->instance(); $_[0] },
             '${}' => sub { $_[0] = $_[0]->{service}->instance(); $_[0] },             
             '&{}' => sub { $_[0] = $_[0]->{service}->instance(); $_[0] },
              nomethod => sub {
                    $_[0] = $_[0]->{service}->instance();
                    return overload::StrVal($_[0]) if ($_[3] eq '""' && !overload::Method($_[0], $_[3]));
                    if (my $func = overload::Method($_[0], $_[3])) {
                        return $_[0]->$func($_[1], $_[2]);
                    }
                    throw IOC::MethodNotFound "Could not find a method for overloaded '$_[3]' operator";
              };             

use Scalar::Util qw(blessed);

sub new {
    my ($class, $service) = @_;
    (blessed($service) && $service->isa('IOC::Service')) 
        || throw IOC::InsufficientArguments "You can only defer an IOC::Service object";
    return bless { service => $service }, $class;
}

sub can { 
    $_[0] = $_[0]->{service}->instance();
    (shift)->can(shift);
}

sub isa { 
    $_[0] = $_[0]->{service}->instance();
    (shift)->isa(shift);
}

sub DESTROY { (shift)->{service} = undef }

sub AUTOLOAD {
    my ($subname) = our $AUTOLOAD =~ /([^:]+)$/;
    $_[0] = $_[0]->{service}->instance();
    my $func = $_[0]->can($subname);
    (ref($func) eq 'CODE') 
        || throw IOC::MethodNotFound "You cannot call '$subname'";
    goto &$func;
}

1;

__END__

=head1 NAME

IOC::Service - An IOC Service object

=head1 SYNOPSIS

  use IOC::Service;
  
  my $container = IOC::Container->new();
  $container->register(IOC::Service::Literal->new('log_file' => "logfile.log"));
  $container->register(IOC::Service->new('logger' => sub { 



( run in 2.367 seconds using v1.01-cache-2.11-cpan-302cb4679cc )