Jimple Functions

Jimple Functions

Jimple Functions

A set of utility functions to generate resources that can be used on Jimple or abstractions created from it (like Jimpex).

Resources and Providers

These are the base entities sent to the container; in the case of Jimple, there's only provider, to configure something that gets added to the contianer, but on the case of Jimpex, you have controllers and middlewares.

These resources have a very simple structure: an object with a function property the container will call when processing it.

For example, the Jimple provider:

const myProvider = {
  register(app) {
    // ...
  }
}

Then, you send that to the container and the register function gets called with a reference to the container itself.

Jimpex's middlewares are controller are the same, but the function is called connect.

Instead of defining an object, we can use the resource function:

const { resource } = require('wootils/shared');

const myProvider = resource('provider', 'register', (app) => {
  // ...
});

But if you had to be that verbose, it wouldn't make sense to make these wrappers, so the idea is for the abstractions to create their own resources to just send the function.

Since I use Jimple everywhere, I already added the provider wrapper in here:

const { provider } = require('wootils/shared');

const myProvider = provider((app) => {
  // ...
});

Yes, Jimple already supports the provider shorthand function (I made the PR for that), but once you see the rest of the wrappers, you'll understand why I redefined it in here.

As an extra, on Jimpex, I use it define the following wrappers:

const { resource } = require('wootils/shared');

const controller = (connectFn) => resource('controller', 'connect', connectFn);
const middleware = (connectFn) => resource('middleware', 'connect', connectFn);

Resources creators and providers creators

Let's say you want you resource to be able to take custom options to change its behaviour, for example:

const { provider } = require('wootils/shared');

const myProvider = (options = {}) => provider((app) => {
  // ...
});

The problem there is that your provider is not longer a provider, but some sort of "provider generator", as you have to run the function in order to get the provider:

app.register(myProvider());

The alternative would be to define two providers:

const { provider } = require('wootils/shared');

const myProviderWithOptions = (options = {}) => provider((app) => {
  // ...
});

const myProvider = myProviderWithOptions();

But now, whoever implements it needs to be aware that there are two different providers for the same resource.

Here's where a resourceCreator comes in: this wrapper allows you to wrap a function that returns a function to interact with the resource. Let's see an example with a "provider creator":

const { resourceCreator } = require('wootils/shared');

const myProvider = resourceCreator(
  'provider',
  'register',
  (options = {}) => (app) => {
    // ...
  },
);

The magic here is that what you get in return is not a actual provider, but a Proxy. If the proxy register function gets called, it will internally call the "creator function" without parameters; at the same time, you can call the proxy as a function and it will be the same as calling the "creator function", it will return the provider for you to use:

app.register(myProvider);
// or
app.register(myProvider({ enabled: true }));

Moving back to Jimple, yes, the providerCreator comes by default:

const { providerCreator } = require('wootils/shared');

const myProvider = providerCreator((options = {}) => (app) => {
  // ...
});

Collections

Finally, what if we want to group some resources together so the container can interact with all of them at once? That's what resources collections are:

const { provider, resourcesCollection } = require('wootils/shared');

const myFirstProvider = provider((app) => { /* .. */ });
const mySecondProvider = provider((app) => { /* .. */ });

const myProviders = resourcesCollection('providers', 'register')({
  myFirstProvider,
  mySecondProvider,
});

The syntax is a little bit different from the others as it's not strictly a wrapper, it generates a function that you have to later call with a dictionary of resources.

The collection can be used to interact with all the resources at once, just by calling its function (register in the example), which will take care of calling the function on all its resources with the same arguments it received.

app.register(myProviders);

It would be the same as...

app.register(myFirstProvider);
app.register(mySecondProvider);

You can even access the resources by their keys:

app.register(myProviders.myFirstProvider);

And yes, there's a default collection for providers already in the module, providers:

const { provider, providers } = require('wootils/shared');

const myFirstProvider = provider((app) => { /* .. */ });
const mySecondProvider = provider((app) => { /* .. */ });

const myProviders = providers({
  myFirstProvider,
  mySecondProvider,
});

Proxy mode

This is a utility that allows you to create a proxy version of the container that supports adding and retrieving resources as if they were regular properties:

const { proxyContainer } = require('wootils/shared');
const Jimple = require('jimple');

// Instead of assigning the instance, we wrap it on the `proxyContainer` function.
const app = proxyContainer(new Jimple());

// Now we can use the resources as properties...

app.someService = () => new SomeService();
// This is the same as `.set('someService', () => new SomeService());`
console.log(app.someService);
// And this is the same as `.get('someService');`

When using the container this way, the register function also gets modified so the providers will also receive the proxy version:

const myProvider = provider((app) => {
  app.someService = () => new SomeService();
});

ES Modules

If you are using ESM, you can import the functions from the /esm sub path:

import {
  resource,
  resourceCreator,
  resourcesCollection,
  provider,
  providerCreator,
  providers,
} from 'wootils/esm/shared/jimpleFns';

// or

import {
  resource,
  resourceCreator,
  resourcesCollection,
  provider,
  providerCreator,
  providers,
} from 'wootils/esm/shared';

Technical documentation

If you are reading this form the markdown document, you can go to the online version; or you can generate the documentation site yourself by running the docs command:

# You can either use npm or yarn, it doesn't matter
npm run docs && open ./docs/index.html;