gardejo/js-kancolle-logistics-visualizer

View on GitHub
lib/formatter.js

Summary

Maintainability
A
3 hrs
Test Coverage
/**
 * @fileOverview A partical object for a string formatter.
 * @author kclv@ermitejo.com (MORIYA Masaki, alias Gardejo)
 * @license The MIT license (See LICENSE file)
 */

'use strict';

// ================================================================
// String Formatter
// ================================================================

/**
 * A string formatter.
 * @public
 * @const
 * @constructor
 */
kclv.Formatter = function() {
    return;
};

/**
 * Convert the specified value into JSON by delegeted {@code JSON#stringify}.
 * @public
 * @param {Object} value The value to convert to a JSON string.
 * @param {(Function|Array)=} opt_replacer See {@code JSON#stringify}.
 * @param {(string)=} opt_space Causes the resulting string to be
 *     pretty-printed.
 * @nosideeffects
 * @see JSON#stringify
 */
kclv.Formatter.prototype.stringify = function(value, opt_replacer, opt_space) {
    return JSON.stringify(value, opt_replacer, opt_space);
};

/**
 * Quote the specified target (a string or array of string) and get it.
 * @public
 * @param {!(string|Array.<string>)} target A raw string or array of a raw
 *     string.
 * @param {Array.<number>=} opt_indices Indices of target elements of array.
 *     If {@code target} parameter is not {@code Array}, it will be ignored.
 *     If it is undefined, a concrete function operates all elements of array.
 * @returns {(string|Array.<string>)} A quoted string or array of a quoted
 *     string.
 * @nosideeffects
 * @see #format_
 * @see #unquote
 */
kclv.Formatter.prototype.quote = function(target, opt_indices) {
    return this.format_(
        function(string) { return '"' + string + '"'; },
        target,
        opt_indices
    );
};

/**
 * Unquote the specified target (a string or array of a string) and get it.
 * @public
 * @param {!(string|Array.<string>)} target A quoted string or array of a
 *     quoted string.
 * @param {Array.<number>=} opt_indices Indices of target elements of array.
 *     If {@code target} parameter is not {@code Array}, it will be ignored.
 *     If it is undefined, a concrete function operates all elements of array.
 * @returns {(string|Array.<string>)} A raw (unquoted) string or array of a raw
 *     (unquoted) string.
 * @nosideeffects
 * @see #format_
 * @see #quote
 */
kclv.Formatter.prototype.unquote = function(target, opt_indices) {
    return this.format_(
        function(string) { return string.replace(/"/g, ''); },
        target,
        opt_indices
    );
};

/**
 * Parenthesize the specified target (a string or array of a string) and get
 *     it.
 * @public
 * @param {!(string|Array.<string>)} target A raw string or array of a raw
 *     string.
 * @param {Array.<number>=} opt_indices Indices of target elements of array.
 *     If {@code target} parameter is not {@code Array}, it will be ignored.
 *     If it is undefined, a concrete function operates all elements of array.
 * @returns {(string|Array.<string>)} A parenthesized string or array of a
 *     parenthesized string.
 * @nosideeffects
 * @see #format_
 */
kclv.Formatter.prototype.parenthesize = function(target, opt_indices) {
    return this.format_(
        function(string) { return '(' + string + ')'; },
        target,
        opt_indices
    );
};

/**
 * Integerize the specified target (a string or array of a string) and get it.
 * @public
 * @param {!(string|Array.<string>)} target An integer-like string or array of
 *     an integer-like string.
 * @param {Array.<number>=} opt_indices Indices of target elements of array.
 *     If {@code target} parameter is not {@code Array}, it will be ignored.
 *     If it is undefined, a concrete function operates all elements of array.
 * @returns {(number|Array.<number>)} An integer or array of a integer.
 * @nosideeffects
 * @see #format_
 */
kclv.Formatter.prototype.integerize = function(target, opt_indices) {
    return this.format_(
        // Radix is 10 (default).
        function(string) { return parseInt(string, 10); },
        target,
        opt_indices
    );
};

/**
 * Commify the specified target (a string or array of a string) and get it.
 *     Note: A delimiter is only comma.
 *     Note: Positions of delimiters are every three characters.
 * @public
 * @param {!(number|Array.<number>)} target A number or array of a number.
 * @param {Array.<number>=} opt_indices Indices of target elements of array.
 *     If {@code target} parameter is not {@code Array}, it will be ignored.
 *     If it is undefined, a concrete function operates all elements of array.
 * @returns {(string|Array.<string>)} A commified number-like string or array
 *     of a commified number-like string.
 * @nosideeffects
 * @see #format_
 * @see Tom Christiansen, Nathan Torkington, "Perl Coolbook 2nd Ed. Vol.1",
 *     Ch.2 (Recipe 2.16).
 */
kclv.Formatter.prototype.commify = function(target, opt_indices) {
    return this.format_(
        function(number) {
            return number.toString().                       // '2411'
                split('').reverse().join('').               // '1142'
                replace(/(\d{3})(?=\d)(?!\d*\.)/g, '$1,').  // '114,2'
                split('').reverse().join('');               // '2,411'
        },
        target,
        opt_indices
    );
};

/**
 * (Template) Format the specified target (a string or array of a string) and
 *     get it.
 * @private
 * @param {Function} formatter Concrete formatter method to call.
 * @param {(string|Array.<string>)} target A string or array of a string.
 * @param {Array.<number>=} opt_indices Indices of target elements of array.
 *     If {@code target} parameter is not {@code Array}, it will be ignored.
 *     If it is undefined, a concrete function operates all elements of array.
 * @nosideeffects
 */
kclv.Formatter.prototype.format_ = function(formatter, target, opt_indices) {
    if (! Array.isArray(target) ) {
        return target === null ? target : formatter.call(this, target);
    }

    if (! opt_indices) {
        // Format all elements.
        return target.map( function(element) {
            return this.format_(formatter, element);
        }, this );
    }

    // Format specified (by indices) elements.
    return target.map( function(element, index) {
        return opt_indices.indexOf(index) < 0 ? // Processing element or not?
            element : this.format_(formatter, element);
    }, this );
};

/**
 * Enumerate the specified items as a string and get it.
 *     Note: A delimiter is only comma.
 * @public
 * @param {Array.<string>} items Enumerating items.
 * @param {boolean} isAffirmative Whether the context is an affirmative
 *     sentence.
 * @returns {string} Enumerated items as a string.
 * @nosideeffects
 * @example
 *     enumerate(["a"]);                 // becomes '"a"'
 *     enumerate(["a", "b"],      true)  // becames '"a" and "b"'
 *     enumerate(["a", "b"],      false) // becames '"a" nor "b"'
 *     enumerate(["a", "b", "c"], true ) // becames '"a", "b" and "c"'
 *     enumerate(["a", "b", "c"], false) // becames '"a", "b" nor "c"'
 */
kclv.Formatter.prototype.enumerate = function(items, isAffirmative) {
    var clonedItems = items.slice();

    if (clonedItems.length <= 1) {
        return clonedItems.shift();
    }

    return [
        clonedItems.splice(0, clonedItems.length - 1).join(', '),
        isAffirmative ? 'and' : 'nor',
        clonedItems.shift()
    ].join(' ');
};

/**
 * Convert an object (such as {@code Error}) into a human-readable string for
 *     a dialogue window (or a console). For example, an object was stringified
 *     as JSON. For a GUI performance and a convenience, it may snips a too
 *     long string.
 * @public
 * @param {!(Error|Object)} exception Throwed object, usually an instance of
 *     {@code Error}.
 * @returns {string} A string representing a throwed object.
 * @nosideeffects
 */
kclv.Formatter.prototype.dialogue = function(exception) {
    var message = 'Something wrong.',
        json,
        length,
        MAXIMUM_LENGTH = 1000; // TODO

    if ( exception instanceof Error ) {
        return exception.name + ': ' + exception.message;
    }

    if (! exception) {
        return message;
    }

    message += ' Object notation is:\n\n';
    json = this.stringify(exception, null, '    '); // TODO
    if (! json) {
        return message + 'undefined';
    }

    length = json.length;
    if (length <= MAXIMUM_LENGTH) {
        return message + json;
    }

    return message + json.substr(0, MAXIMUM_LENGTH) + ' ...\n\n' +
           '(Snipped ' + (length - MAXIMUM_LENGTH) +  ' characters.)';
};