IOC::Service - An IOC Service object


IOC documentation Contained in the IOC distribution.

Index


Code Index:

NAME

Top

IOC::Service - An IOC Service object

SYNOPSIS

Top

  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 { 
      my $c = shift; 
      return FileLogger->new($c->get('log_file'));
  }));
  $container->register(IOC::Service->new('application' => sub {
      my $c = shift; 
      my $app = Application->new();
      $app->logger($c->get('logger'));
      return $app;
  }));

  $container->get('application')->run();   

DESCRIPTION

Top

In this IOC framework, the IOC::Service object holds instances of components to be managed.

   +--------------+                 +-------------------------+
   | IOC::Service |---(instance)--->| <Your Component/Object> |
   +--------------+                 +-------------------------+ 
          |
  (parent_container)
          |
          V
 +------------------+                  
 |  IOC::Container  |
 +------------------+

METHODS

Top

new ($name, $block)

Creates a service with a $name, and uses the $block argument to initialize the service on demand.

name

Returns the name of the service instance.

setContainer ($container)

Given a $container, which is an instance of IOC::Container or a subclass of it, this method will associate the service instance with that container object.

removeContainer

This will break the connection between a service and a container. This method is usually only called by the unregister method in IOC::Container.

instance

This method returns the component held by the service object, the is basically the value returned by the $block constructor argument.

deferred

This method returns an IOC::Service::Deferred wrapper which will lazy load the service. This is used for handling circular dependencies, and rarely used directly.

TO DO

Top

Work on the documentation

BUGS

Top

None that I am aware of. Of course, if you find a bug, let me know, and I will be sure to fix it.

CODE COVERAGE

Top

I use Devel::Cover to test the code coverage of my tests, see the CODE COVERAGE section of IOC for more information.

SEE ALSO

Top

AUTHOR

Top

stevan little, <stevan@iinteractive.com>

COPYRIGHT AND LICENSE

Top


IOC documentation Contained in the IOC distribution.

package IOC::Service;

use strict;
use warnings;

our $VERSION = '0.08';

use Scalar::Util qw(blessed);

use IOC::Exceptions;

sub new {
    my ($_class, $name, $block) = @_;
    my $class = ref($_class) || $_class;
    my $service = {};
    bless($service, $class);
    $service->_init($name, $block);
    return $service;
}

sub _init {
    my ($self, $name, $block) = @_;
    (defined($name)) || throw IOC::InsufficientArguments "Service object cannot be created without a name";
    (defined($block) && ref($block) eq 'CODE')
        || throw IOC::InsufficientArguments "Service object cannot be created without CODE block";
    # set the defaults
    $self->{_instance} = undef;
    # assign constructor args    
    $self->{name} = $name;
    $self->{block} = $block;
    # container is optional
    $self->{container} = undef;    
}

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__