Skip to content
This repository has been archived by the owner on May 1, 2020. It is now read-only.

yahoo/preceptor-core

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 - A base object that every preceptor object should inherit from. See below for more information.
  • utils - Frequently used utility functions
  • log - Centralized log and logger management

###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:

  • constructFn {function} - The function to be used as constructor. This parameter is optional. When no function is given, then a generic function is used.
  • prototypeProperties {object} - Properties that should be assigned the the prototype property of the constructor. This parameter is required.
  • staticProperties {object} - Properties that should be assigned to the constructor. This parameter is optional.

#####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:

  • obj {object} - Destination object to merge values into
  • objects {object[]} - Array of objects that should be copied into the obj.
  • fn {function} - Function that returns a value that should be used in place of the original value. Every property in the objects of the objects parameter will call this function. This parameter is optional. Should no function be supplied, then the values will be used as-is.

Apply-Function Parameters:

  • srcValue {*} - The original value of a property that should be copied to the obj.
  • dstValue {*} - Current value on the obj object.
  • options {object} - Additional options
  • options.key {string} - Name of the property that should be copied.
  • options.currentObject {object} _ The object currently processed from the objects list.
  • options.objectIndex {int} - The index of currentObject in the objects list.
  • options.valueIndex {int} - The index of the current property in currentObject.

####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:

  • obj {object} - Destination object to merge values into
  • objects {object[]} - Array of objects that should be copied into the obj.
  • options {object} - Additional options.
  • options.replace {boolean} - If set, then array entries in destination will be replaced instead of values appended to the destination list.

####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:

  • glue {string} - Glue string
  • str, ... {string} - Strings that should be glued.

####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:

  • currentItem {*} - Value that should be used
  • previousItem {*} - Previous item value

####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:

  • module {string} - Module name or path
  • defaultValue {*} - Default value if the module cannot be found

####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:

  • log - The singleton managing multiple loggers
  • logger - Instance for a specific logger

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:

  • logger.trace - Trace log entries that could give much more detail on steps through the code
  • logger.debug - Debug values that might be helpful for debugging problems without being too overwhelming like logger.trace
  • logger.info - Info messages that is probably helpful for a user to understand what decisions were made
  • logger.warn - Warning message for missing configuration or other behavior that might be unexpected to the user
  • logger.error - Errors during execution

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 - All log-types are used which is an alias for TRACE.
  • TRACE - Trace messages and all messages with the log-type below will be used.
  • DEBUG - Trace messages will be filtered
  • INFO - Trace and Debug messages will be filtered
  • WARN - Info and above messages will be filtered
  • ERROR - Only error messages will be used

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.

About

Shared library for the preceptor test runner and aggregator

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published