Skip to content

Latest commit

 

History

History
168 lines (123 loc) · 5.07 KB

README.md

File metadata and controls

168 lines (123 loc) · 5.07 KB

Gimple

Gimple is a small Dependency Injection Container for Groovy, Java and more generally for JVM. Consists of just one class ( ... maybe two ) and it's inspired (and in many points carbon-copied) from the PHP Pimple project

Homepage: http://fbn.github.io/gimple/

Features

  • Simple: one (... maybe two) class.
  • Modern: strong use of closures.
  • Thread safety & efficiency: powered by Guava Stripe. Tested with thread-safe.org.
  • Nice API: the container is an LinkedHashMap extension. In groovy you can use it like a Map, [:].
  • Prototype / Singleton: define singleton or prototype scoped services or parameters.

Why!?

Java, and more generally JVM, already got many dependency injection containers (spring framework, google guice, picocontainer) but all of them are heavy libraries composed of dozens of classes.

It's just a single class!

Usage

Gimple is published via Maven:

If you use gradle simply add the following lines to build.gradle file:

repositories {
    maven {
        url 'https://github.com/FbN/mvn/raw/master/'
    }
} 

dependencies {
    compile 'com.github.gimple:Gimple:0.1.2'
}

API

Instantiate

def container = new gimple.Container()

Defining Services

A service is an object that does something as part of a larger system. Examples of services are:

  • a database connection
  • a templating engine
  • a mailer

Almost any global object can be a service. Services are defined by a closure that returns an instance of an object:

container['sessionStorage'] = { c ->
    new SessionStorage('SESSION_ID')
}

container['session'] = { c ->
    new Session(c['sessionStorage'])
}

Notice that closure has access to the current container instance, allowing references to other services or parameters.

As objects are only created when you get them, the order of the definitions does not matter.

Using the defined services is also very easy:

def session = container['session']

Defining Factory Services

By default, each time you get a service, Gimple returns the same instance of it. If you want a different instance to be returned for all calls, wrap your closure with the factory() method

container['session'] = container.factory( { c ->
    new Session(c['sessionStorage'])
})

Now, each call to container['session'] returns a new instance of the session.

Defining Parameters

Defining a parameter allows to ease the configuration of your container from the outside and to store global values:

container['cookieName'] = 'SESSION_ID'
container['sessionStorageClass'] = 'SessionStorage'

If not a closure it is a parameter.

If you change the sessionStorage service definition like below:

container['sessionStorage'] = { c ->
    new "${c['sessionStorageClass']}"(c['cookieName'])
}

Protecting Parameters

Because Gimple sees closures as a service definitions, you need to wrap closure with the protect() method to store them as parameters:

container['randomFunc'] = container.protect({ new Random().nextInt() })

Modifying Services after Definition

You can replace a service simple reassigning a new value to id (the service must not be already used). In some cases you may want to modify a service definition after it has been defined without replacing it. You can see it as a filter applied after the original service. You can use the extend() method to define additional code to be run on your service just after it is created:

container['sessionStorage'] = { c ->
    new "${c['sessionStorageClass']}"(c['cookieName'])
};

container.extend('sessionStorage', {storage, c ->
    ...
    do anything with storage and c
    ...

    storage
})

The first argument is the name of the service to extend, the second a function that gets access to the object instance and the container.

Extending a Container

If you use the same libraries over and over, you might want to reuse some services from one project in another one. Package your services into a provider by implementing gimple.ServiceProviderInterface:

class FooProvider implements gimple.ServiceProviderInterface {
    def register(Container gimple) {
        // register some services and parameters
        // on gimple
    }
}

Then, register the provider on a Container:

gimple.register(new FooProvider())

Fetching the Service Creation Function

When you access an object, Gimple automatically calls the closure that you defined, which creates the service object for you. If you want to get raw access to the closure, you can use the raw() method:

container['session'] = { c ->
    new Session(c['sessionStorage'])
};

def sessionFunction = container.raw('session')

Authors and Contributors

Fabiano Taioli / ftaioli@gmail.com

Maciek Opała