View on GitHub

Preceptor-core

Shared library for the preceptor test-runner and aggregator

Download this project as a .zip file Download this project as a tar.gz file

Preceptor-Core

Shared library for the preceptor test runner and aggregator.

Build Status Coveralls Coverage Code Climate Grade

NPM version NPM License

NPM NPM

Coverage Report API Documentation

Gitter Support

Table of Contents

Installation

Install this module with the following command:

npm install preceptor-core

Add the module to your package.json dependencies:

npm install --save preceptor-core

Add the module to your package.json dev-dependencies:

npm install --save-dev preceptor-core

Require the module in your source-code:

var core = require('preceptor-core');

Usage

The module exposes two objects:

Base-Object

The Base object inherits all features of the EventEmitter and exposes a couple static and dynamic properties:

Static Properties - Defined on the constructor

TYPE {string}

Describes the type of the object. The default value is "Base". Overwrite this value in sub-objects to help in debugging as the will appear as descriptor of an object.

extend {function}

Extends the current object by creating a new constructor and inheriting all static and dynamic properties. Every function will be wrapped in a __super wrapper that will make the __super function available in every method call. (See below for more information!)

Parameters:

toString {function}

Describes the object. By default, the format is: [TYPE] where by TYPE is the value assigned to the constructor.

__parent {object}

This is a reference to the parent prototype.

Dynamic Properties - Defined on this or prototype

uniqueId {string}

Every instance of an object gets a unique-id assigned.

NAME {string}

Describes the instance. The default value is "unnamed". Overwrite this value in instances to help to help identifying instances during run-time.

toString {function}

Describes the instance. By default, the format is: [TYPE::NAME(uniqueId)] where by TYPE is the value assigned to the constructor, and NAME is the value assigned to the instance.

__super {function}

Accessor function to access the parent implementation of a method. Should there be no parent method, then this method is an empty function.

Example

var Base = require('preceptor-core').Base;

/**
 * @class Pet
 * @extends Base
 * @properties {string} _type Type of pet
 * @properties {string} _name Name of pet
 */
var Pet = Base.extend(

    /**
     * Constructor of Pet
     *
     * @constructor
     * @param {string} type Type of pet
     * @param {string} name Name of pet
     */
     function (type, name) {

        // Call the parent constructor
        this.__super();

        // Save property on the current object
        this._type = type;
        this._name = name;

        // Add instance descriptor
        this.NAME = type + ':' + name;

        // Define here all dynamic values, values that should not be shared between multiple instances of "Pet".
    },

    /** @lends Pet.prototype */
    { // Properties assigned to the prototype of "Pet"

        /**
         * Make sound of pet
         *
         * @param {string} sound
         * @method makeSound
         */
        makeSound: function (sound) {
            this.emit('sound', this.getName(), sound);

            console.log(this.getName() + " says: " + sound);
        },

        /**
         * Gets the name of the pet
         *
         * @return {string}
         */
        getName: function () {
            return this._name;
        }

        // ...
        // Any other functions and values assigned to the prototype.

        // These properties can be accessed after instantiation with ```petInstance.makeSound()```.

        // You can also define here all values that should be available in instances of "Pet" that should be shared
        // across all object instances.
    },

    /** @lends Pet */
    { // Properties assigned to the constructor of "Pet"

        /**
         * @type {string}
         */
        TYPE: "Pet"

        // ...
        // Any other constructor functions and values.

        // These properties can be accessed with ```Pet.TYPE```.
    }
);

/**
 * @class Cat
 * @extends Pet
 */
var Cat = Pet.extend(

    /**
     * Constructor of Cat
     *
     * @constructor
     * @param {string} name Name of pet
     */
    function (name) {
        this.__super("cat", name);
    },

    /** @lends Cat.prototype */
    { // Properties assigned to the prototype of "Cat"
        /**
         * Make sound of cat
         *
         * @method makeSound
         */
        makeSound: function () {
            this.__super("miau");
        }
    },

    /** @lends Cat */
    { // Properties assigned to the constructor of "Cat"
        /**
         * @type {string}
         */
        TYPE: "Cat"
    }
);

/**
 * @class Dog
 * @extends Pet
 */
var Dog = Pet.extend(

    /**
     * Constructor of Dog
     *
     * @constructor
     * @param {string} name Name of pet
     */
        function (name) {
        this.__super("dog", name);
    },

    /** @lends Dog.prototype */
    { // Properties assigned to the prototype of "Dog"
        /**
         * Make sound of cat
         *
         * @method makeSound
         */
        makeSound: function () {
            this.__super("barf");
        }
    },

    /** @lends Dog */
    { // Properties assigned to the constructor of "Dog"
        /**
         * @type {string}
         */
        TYPE: "Dog"
    }
);

var tomTheCat = new Cat("Tom");
var zeusTheDog = new Dog("Zeus");

// Listen to events
tomTheCat.on('sound', function (name, sound) {
    console.log("The cat said " + sound);
});
zeusTheDog.on('sound', function (name, sound) {
    console.log("The dog said " + sound);
});

// Make sounds
tomTheCat.makeSound();
zeusTheDog.makeSound();

// Print instance identifier
console.log("Cat object: " + Cat.toString());
console.log("Cat instance", tomTheCat.toString());

console.log("Dog object: " + Dog.toString());
console.log("Dog instance", zeusTheDog.toString());

Output:

The cat said miau
Tom says: miau
The dog said barf
Zeus says: barf
Cat object: [Cat]
Cat instance [Cat::cat:Tom(instance1)]
Dog object: [Dog]
Dog instance [Dog::dog:Zeus(instance2)]

utils

Utils exposes the following utility functions:

extendApply

This extend-function works like any other extend function, except it calls a function on each value and uses the result as value of a property.

Parameters:

Apply-Function Parameters:

Example - Simple extend

var utils = require('../../').utils;
var result;

var obj1 = {
    "name": "obj1",
    "entry1": 23,
    "entry2": 46
};

var obj2 = {
    "name": "obj2",
    "entry2": 78,
    "entry3": 2
};

var srcObj = {
    "entry0": 0
};


console.log("Simple extend:");
utils.extendApply(srcObj, [obj1, obj2]);
console.log(srcObj);

Output:

Simple extend:
{ entry0: 0, name: 'obj2', entry1: 23, entry2: 78, entry3: 2 }

Example - Extend with apply function

console.log("Extend with function:");
result = utils.extendApply({}, [obj1, obj2], function (value) {
    return value + 1;
});
console.log(result);

Output:

Extend with function:
{ name: 'obj21', entry1: 24, entry2: 79, entry3: 3 }

Example - Logging extend apply calls

console.log("Extend logging:");
result = utils.extendApply({}, [obj1, obj2], function (srcValue, dstValue, options) {

    console.log("The value '" + srcValue + "' with key '" + options.key + "' from object with name '" +
        options.currentObject.name +  "' was '" + dstValue + "' in the original object");

    return options.objectIndex + ':' + options.valueIndex;
});
console.log(result);

Output:

Extend logging:
The value 'obj1' with key 'name' from object with name 'obj1' was 'undefined' in the original object
The value '23' with key 'entry1' from object with name 'obj1' was 'undefined' in the original object
The value '46' with key 'entry2' from object with name 'obj1' was 'undefined' in the original object
The value 'obj2' with key 'name' from object with name 'obj2' was '0:0' in the original object
The value '78' with key 'entry2' from object with name 'obj2' was '0:2' in the original object
The value '2' with key 'entry3' from object with name 'obj2' was 'undefined' in the original object
{ name: '1:0', entry1: '0:1', entry2: '1:1', entry3: '1:2' }

deepExtend

Extends an object with properties that will be recursively copied.

Parameters:

Example: Simple usage

var utils = require('preceptor-core').utils;

var obj1 = {
    "entry1": [1, 2, 3],
    "entry2": [5, 6],
    "entry4": 23,
    "entry5": {
        "entry6": 22,
        "entry7": 24,
        "entry8": {
            "entry9": 9
        }
    }
};

var obj2 = {
    "entry2": [8, 9],
    "entry3": 2,
    "entry5": {
        "entry7": 21,
        "entry10": 11
    }
};

var srcObj = {
    "entry0": 0,
    "entry2": [7],
    "entry5": {
        "entry0": "zero"
    }
};

utils.deepExtend(srcObj, [obj1, obj2]);
console.log(srcObj);

Output:

{ entry0: 0,
  entry2: [ 7, 5, 6, 8, 9 ],
  entry5:
   { entry0: 'zero',
     entry6: 22,
     entry7: 21,
     entry8: { entry9: 9 },
     entry10: 11 },
  entry1: [ 1, 2, 3 ],
  entry4: 23,
  entry3: 2 }

Example: Use with replace

var utils = require('preceptor-core').utils;
var result;

result = utils.deepExtend({}, [obj1, obj2], { replace: true });
console.log(result);

Output:

{ entry1: [ 1, 2, 3 ],
    entry2: [ 8, 9 ],
    entry4: 23,
    entry5: { entry6: 22, entry7: 21, entry8: { entry9: 9 }, entry10: 11 },
    entry3: 2 }

combine

Combines multiple strings by applying a glue-string between them if they are not already available there. This is very similar to the path.join method, but it doesn't care what the structure of the rest or the string is.

This method is used with the extendApply function to give object methods the possibility to call the parent method with __super().

Parameters:

Example: Simple usage

var utils = require('preceptor-core').utils;

console.log(utils.combine('-', '', '', ''));
// Output: -

console.log(utils.combine('-', 'test1', 'test2'));
// Output: test1-test2

console.log(utils.combine('-', '-test1-', '-test2-'));
// Output: -test1-test2-

console.log(utils.combine('-', 'test1-', 'test2'));
// Output: test1-test2

console.log(utils.combine('-', 'test1', '-test2'));
// Output: test1-test2

superWrapper

Function that creates a new function that sets the __super property up to be called from within a function body.

Parameters:

Example: Simple usage

var utils = require('preceptor-core').utils;

var newFn = utils.superWrapper(function (value) {
    this.__super(123, value);
    console.log("Method test in object 2 and value " + value);
}, function (value1, value2) {
    console.log("Method test in object 1 and values " + value1 + " and " + value2);
});
newFn(88);

Output:

Method test in object 1 and values 123 and 88
Method test in object 2 and value 88

Example: Usage with extendApply

var utils = require('preceptor-core').utils;

var obj1 = {
    test: function (value1, value2) {
        console.log("Method test in object 1 and values " + value1 + " and " + value2);
    }
};

var obj2 = {
    test: function (value) {
        this.__super(123, value);
        console.log("Method test in object 2 and value " + value);
    }
};

var result = utils.extendApply(obj1, [obj2], utils.superWrapper);
result.test(88);

Output:

Method test in object 1 and values 123 and 88
Method test in object 2 and value 88

require

This function does the same thing as the original require function to load modules. However, this function will give you the option to use default values when the module cannot be found.

Parameters:

Example: Simple usage

var utils = require('preceptor-core').utils;

var configuration = utils.require('config', {});

log

The log object exposes a centralize logging interface including buffering for deferred logging.

This object works with two different type of objects:

A new logger can be created by calling the getLogger method on the log object:

var logger = log.getLogger(__filename);

For each logger, a filename/identifier can be supplied that will be exported with each log trigger.

When having a logger, then log entries can be triggered, including objects:

logger.debug('Debug message: ', { message: 'something something' });

There are a couple of log-types available:

These log-types may be filtered depending on the log-level set. The log-levels can be requested and set with the following values:

log.setLevel('DEBUG');

log.getLevel() // -> DEBUG

The default value is INFO.

Following log-levels are available:

All loggers are by default centralized buffered to defer log-messages until it is known what level of output the user wants. That means that the non-buffering mode needs to be activated. This can be done by calling only once:

log.flush();

API-Documentation

Generate the documentation with following command:

npm run docs

The documentation will be generated in the docs folder of the module root.

Tests

Run the tests with the following command:

npm run test

The code-coverage will be written to the coverage folder in the module root.

Third-party libraries

The following third-party libraries are used by this module:

Dependencies

Dev-Dependencies

License

The MIT License

Copyright 2014-2015 Yahoo Inc.