Mixins and with

As things are just a combination of types and capabilities in there is support for combining them built in to the core library. Thing provides a method with that mixes several types and capabilities together:

class CustomThing extends Thing.with(Mixin1, Mixin2) {
        ...
}

Defining a mixin

Mixins are defined via Thing.mixin and they work the same as a normal Thing-class such as with metadata. Mixins are functions that create a JavaScript class with a specific parent:

const { Thing } = require('abstract-things');

const CustomMixin = Thing.mixin(Parent => class extends Parent {

        static get capability() {
                return 'custom:cap';
        }

        constructor(...args) {
                // Most mixins should call super with all arguments
                super(...args);

                // Set properties, initialize event listeners as normal
                this.custom = true;
        }

        customMethod() {
                return this.custom;
        }

});

Internal capabilities

In some cases when building a library things will be very straight-forward, just extend Thing with whatever is needed, implement the behavior and abstract methods and you’re done. In other cases such as when working against a IoT-bridge for things such as lights or sensors you might find that its useful to package the API used to talk to the thing as an internal capability.

Example:

const { Thing } = require('abstract-things');
const { Light, SwitchablePower } = require('abstract-things/light');

// This mixin provides access to the external API for custom capabilities
const CustomAPI = Thing.mixin(Parent => class extends Parent {

        constructor(api) {
                super();

                this.api = api;
        }

        initCallback() {
                return super.initCallback()
                        // Ask the fake API to initialize itself
                        .then(() => this.api.init());
        }

});

/*
 * Create the custom capability that provides an implementation of
 * SwitchablePower on top of CustomAPI.
 */
const CustomPower = Thing.mixin(Parent => class extends Parent
        .with(CustomAPI, SwitchablePower) {

        initCallback() {
                return super.initCallback()
                        .then(() => {
                                // During init this connects to the powerChanged event of our fake API
                                this.api.on('powerChanged', power => this.updatePower(power))

                                // Set the power as well
                                this.updatePower(this.api.hasPower());
                        });
        }

        updatePower(power) {
                return this.api.setPower(power);
        }

});

const CustomDimmable = ...;

// Define the specific combinations that can exist
const PoweredThing = Light.with(CustomPower);
const PoweredAndDimambleThing = Light.with(CustomPower, CustomDimmable);

// Create them and pass the API-instance
new PoweredThing(getApiSomehow());