Coder Social home page Coder Social logo

rewire's Introduction

NAME

Rewire - Dependency Injection

ABSTRACT

Dependency Injection Container for Perl 5

SYNOPSIS

use Rewire;

my $services = {
  filetemp => {
    package => 'File/Temp'
  },
  tempfile => {
    package => 'Mojo/File',
    argument => { '$service' => 'filetemp' }
  }
};

my $rewire = Rewire->new(services => $services);

$rewire->resolve('tempfile');

DESCRIPTION

This package provides methods for using dependency injection, and building objects and values.

INTEGRATES

This package integrates behaviors from:

Data::Object::Role::Buildable

Data::Object::Role::Proxyable

LIBRARIES

This package uses type constraints from:

Types::Standard

SCENARIOS

This package supports the following scenarios:

$callback

use Rewire;

my $services = {
  io => {
    package => 'IO/Handle'
  },
  log => {
    package => 'Mojo/Log',
    argument => {
      format => { '$callback' => 'io' }
    }
  },
};

my $rewire = Rewire->new(
  services => $services
);

This package supports resolving services as callbacks to be passed around and/or resolved by other services. The $callback directive is used to specify the name of a service to be resolved and passed as an argument.

$envvar

use Rewire;

my $services = {
  file => {
    package => 'Mojo/File',
    argument => { '$envvar' => 'home' }
  }
};

my $rewire = Rewire->new(
  services => $services
);

This package supports inlining environment variables as arguments to services. The $envvar directive is used to specify the name of an environment variable, and can also be used in metadata for reusability.

$function

use Rewire;

my $services = {
  temp => {
    package => 'File/Temp'
  },
  file => {
    package => 'Mojo/File',
    argument => { '$function' => 'temp#tempfile' }
  }
};

my $rewire = Rewire->new(
  services => $services
);

This package supports inlining the result of a service resolution and function call as arguments to services. The # delimited $function directive is used to specify the name of an existing service on the right-hand side, and an arbitrary function to be call on the result on the left-hand side.

$metadata

use Rewire;

my $metadata = {
  home => '/home/ubuntu'
};

my $services = {
  file => {
    package => 'Mojo/File',
    argument => { '$metadata' => 'home' }
  }
};

my $rewire = Rewire->new(
  metadata => $metadata,
  services => $services
);

This package supports inlining configuration data as arguments to services. The $metadata directive is used to specify the name of a stashed configuration value or data structure.

$method

use Rewire;

my $services = {
  temp => {
    package => 'File/Temp'
  },
  file => {
    package => 'Mojo/File',
    argument => { '$method' => 'temp#filename' }
  }
};

my $rewire = Rewire->new(
  services => $services
);

This package supports inlining the result of a service resolution and method call as arguments to services. The # delimited $method directive is used to specify the name of an existing service on the right-hand side, and an arbitrary method to be call on the result on the left-hand side.

$routine

use Rewire;

my $services = {
  temp => {
    package => 'File/Temp'
  },
  file => {
    package => 'Mojo/File',
    argument => { '$routine' => 'temp#tempfile' }
  }
};

my $rewire = Rewire->new(
  services => $services
);

This package supports inlining the result of a service resolution and routine call as arguments to services. The # delimited $routine directive is used to specify the name of an existing service on the right-hand side, and an arbitrary routine to be call on the result on the left-hand side.

$service

use Rewire;

my $services = {
  io => {
    package => 'IO/Handle'
  },
  log => {
    package => 'Mojo/Log',
    argument => {
      handle => { '$service' => 'io' }
    }
  },
};

my $rewire = Rewire->new(
  services => $services
);

This package supports inlining resolved services as arguments to other services. The $service directive is used to specify the name of a service to be resolved and passed as an argument.

arguments

use Rewire;

my $metadata = {
  applog => '/var/log/rewire.log'
};

my $services = {
  mojo_log => {
    package => 'Mojo/Log',
    argument => {
      path => { '$metadata' => 'applog' },
      level => 'warn'
    },
    argument_as => 'list'
  }
};

my $rewire = Rewire->new(
  services => $services,
  metadata => $metadata
);

This package supports providing static and/or dynamic arguments during object construction from metadata or other services.

builder

use Rewire;

my $services = {
  mojo_date => {
    package => 'Mojo/Date',
    builder => [
      {
        method => 'new',
        return => 'self'
      },
      {
        method => 'to_datetime',
        return => 'result'
      }
    ]
  }
};

my $rewire = Rewire->new(
  services => $services,
);

This package supports specifying multiple build steps as function, method, and routine calls and chaining them together.

config

use Rewire;

my $metadata = {
  home => '/home/ubuntu'
};

my $services = {
  tempfile => {
    package => 'Mojo/File',
    argument => { '$metadata' => 'home' }
  }
};

my $rewire = Rewire->new(
  services => $services,
  metadata => $metadata
);

This package supports configuring services and metadata in the service of building objects and values.

constructor

use Rewire;

my $services = {
  mojo_date => {
    package => 'Mojo/Date',
    constructor => 'new'
  }
};

my $rewire = Rewire->new(
  services => $services
);

This package supports specifying constructors other than the traditional new routine. A constructor is always called with the package name as the invocant.

extends

use Rewire;

my $services = {
  io => {
    package => 'IO/Handle'
  },
  log => {
    package => 'Mojo/Log',
    argument => {
      handle => { '$service' => 'io' }
    }
  },
  development_log => {
    package => 'Mojo/Log',
    extends => 'log',
    builder => [
      {
        method => 'new',
        return => 'self'
      },
      {
        method => 'path',
        argument => '/tmp/development.log',
        return => 'none'
      },
      {
        method => 'level',
        argument => 'debug',
        return => 'none'
      }
    ]
  },
  production_log => {
    package => 'Mojo/Log',
    extends => 'log',
    builder => [
      {
        method => 'new',
        return => 'self'
      },
      {
        method => 'path',
        argument => '/tmp/production.log',
        return => 'none'
      },
      {
        method => 'level',
        argument => 'warn',
        return => 'none'
      }
    ]
  },
  staging_log => {
    package => 'Mojo/Log',
    extends => 'development_log',
  },
  testing_log => {
    package => 'Mojo/Log',
    extends => 'log',
  },
};

my $rewire = Rewire->new(
  services => $services
);

This package supports extending services in the definition of other services, recursively compiling service configurations and eventually executing the requested compiled service.

function

use Rewire;

my $services = {
  foo_sum => {
    package => 'Mojo/Util',
    function => 'md5_sum',
    argument => 'foo',
  }
};

my $rewire = Rewire->new(
  services => $services,
);

This package supports specifying construction as a function call, which when called does not provide an invocant.

lifecycle

use Rewire;

my $metadata = {
  home => '/home/ubuntu'
};

my $services = {
  tempfile => {
    package => 'Mojo/File',
    argument => { '$metadata' => 'home' },
    lifecycle => 'singleton'
  }
};

my $rewire = Rewire->new(
  services => $services,
  metadata => $metadata
);

This package supports different lifecycle options which determine when services are built and whether they're persisted.

metadata

use Rewire;

my $metadata = {
  homedir => '/home',
  tempdir => '/tmp'
};

my $services = {
  home => {
    package => 'Mojo/Path',
    argument => { '$metadata' => 'homedir' },
  },
  temp => {
    package => 'Mojo/Path',
    argument => { '$metadata' => 'tempdir' },
  }
};

my $rewire = Rewire->new(
  services => $services,
  metadata => $metadata
);

This package supports specifying data and structures which can be used in the construction of multiple services.

method

use Rewire;

my $services = {
  mojo_url => {
    package => 'Mojo/URL',
    argument => 'https://perl.org',
    method => 'new'
  }
};

my $rewire = Rewire->new(
  services => $services,
);

This package supports specifying construction as a method call, which when called provides the package or object instance as the invocant.

proxyable

use Rewire;

my $services = {
  home => {
    package => 'Mojo/Path',
    argument => '/home',
  },
  temp => {
    package => 'Mojo/Path',
    argument => '/tmp',
  }
};

my $rewire = Rewire->new(
  services => $services
);

# resolve services via method calls
[
  $rewire->home, # i.e. $rewire->process('home')
  $rewire->temp  # i.e. $rewire->process('temp')
]

This package supports the resolution of services using a single method call. This is enabled by intercepting method calls and proxying them to the "process" method.

routine

use Rewire;

my $services = {
  mojo_url => {
    package => 'Mojo/URL',
    argument => 'https://perl.org',
    routine => 'new'
  }
};

my $rewire = Rewire->new(
  services => $services,
);

This package supports specifying construction as a function call, which when called provides the package as the invocant.

service

my $metadata = {
  home => '/home/ubuntu'
};

my $services = {
  tempfile => {
    package => 'Mojo/File',
    argument => { '$metadata' => 'home' },
    lifecycle => 'eager'
  }
};

my $rewire = Rewire->new(
  services => $services,
  metadata => $metadata
);

This package supports defining services to be constructed on-demand or automatically on instantiation.

ATTRIBUTES

This package has the following attributes:

context

context(CodeRef)

This attribute is read-only, accepts (CodeRef) values, and is optional.

engine

engine(InstanceOf["Data::Object::Space"])

This attribute is read-only, accepts (InstanceOf["Data::Object::Space"]) values, and is optional.

metadata

metadata(HashRef)

This attribute is read-only, accepts (HashRef) values, and is optional.

services

services(HashRef)

This attribute is read-only, accepts (HashRef) values, and is optional.

METHODS

This package implements the following methods:

config

config() : HashRef

The config method returns the configuration based on the services and metadata attributes.

  • config example #1

      # given: synopsis
    
      $rewire->config;
    

process

process(Str $name, Any $argument, Maybe[Str] $argument_as) : Any

The process method processes and returns an object or value based on the service named but where the arguments are provided ad-hoc. Note: This method is meant to be used to construct services ad-hoc and as such bypasses caching and lifecycle effects.

  • process example #1

      # given: synopsis
    
      $rewire->process('tempfile', 'rewire.tmp');
    
  • process example #2

      use Rewire;
    
      my $metadata = {
        logfile => '/var/log/rewire.log',
      };
    
      my $services = {
        mojo_log => {
          package => 'Mojo/Log',
          argument => { '$metadata' => 'logfile' },
        }
      };
    
      my $rewire = Rewire->new(
        services => $services,
        metadata => $metadata
      );
    
      $rewire->process('mojo_log', {
        level => 'fatal',
        path => { '$metadata' => 'logfile' }
      });
    
  • process example #3

      use Rewire;
    
      my $metadata = {
        logfile => '/var/log/rewire.log',
      };
    
      my $services = {
        mojo_log => {
          package => 'Mojo/Log',
          builder => [
            {
              method => 'new',
              return => 'self'
            }
          ]
        }
      };
    
      my $rewire = Rewire->new(
        services => $services,
        metadata => $metadata
      );
    
      $rewire->process('mojo_log', {
        level => 'fatal',
        path => { '$metadata' => 'logfile' }
      });
    

resolve

resolve(Str $name) : Any

The resolve method resolves and returns an object or value based on the service named. Note: This method is recommended to be used to construct services as defined by the configuration and as such doesn't not allow passing additional arguments.

  • resolve example #1

      # given: synopsis
    
      $rewire->resolve('tempfile');
    
  • resolve example #2

      use Rewire;
    
      my $services = {
        mojo_log => {
          package => 'Mojo/Log',
          argument => {
            level => 'fatal',
            path => '/var/log/rewire.log'
          },
        }
      };
    
      my $rewire = Rewire->new(
        services => $services,
      );
    
      $rewire->resolve('mojo_log');
    
  • resolve example #3

      package Dynamic;
    
      sub import;
    
      sub AUTOLOAD {
        bless {};
      }
    
      sub DESTROY {
        ; # noop
      }
    
      package main;
    
      use Rewire;
    
      my $services = {
        dynamic => {
          package => 'Dynamic',
          builder => [
            {
              method => 'new',
              return => 'self'
            },
            {
              method => 'missing_method',
              return => 'result'
            }
          ],
        }
      };
    
      my $rewire = Rewire->new(
        services => $services,
      );
    
      $rewire->resolve('dynamic');
    

validate

validate() : Object

The validate method validates the configuration and throws an exception if invalid, otherwise returns itself.

  • validate example #1

      # given: synopsis
    
      $rewire->validate;
    

AUTHOR

Al Newkirk, [email protected]

LICENSE

Copyright (C) 2011-2019, Al Newkirk, et al.

This is free software; you can redistribute it and/or modify it under the terms of the The Apache License, Version 2.0, as elucidated in the "license file".

PROJECT

Wiki

Project

Initiatives

Milestones

Contributing

Issues

rewire's People

Watchers

James Cloos avatar

rewire's Issues

Return and reference callbacks which resolve services

Context

Given a service to be passed to another as a callback:

Enhancement

Create a $callback directive that returns services as resolvable callbacks.

use Rewire;
 
my $services = {
  dbh => {
    package => 'DBI',
    method => 'connect',
    ...,
  },
  musicdb => {
    package => 'Music::DB',
    method => 'connect',
    argument => {
      dbh_maker => {
        '$callback' => 'dbh',
      },
    },
    return => 'self'
  }
};

my $rewire = Rewire->new(
  services => $services,
);

my $musicdb = $rewire->musicdb;

Ensure extended service inherits arguments

Context

Given a simple service-container using inheritance:

Issue

It seems like the argument declaration(s) aren't propagated to the subclass, e.g.:

my $services = {
  person => {
    package => 'Person',
    argument => {
      name => { '$envvar' => 'user' }
    }
  },
  student => {
    package => 'Student',
    extends => 'person',
  },
};

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.