/*jslint maxlen:80, browser:true, devel:true */
/*
* Properties used by toChunks.
*/
/*property
MAX_SAFE_INTEGER, abs, ceil, configurable, defineProperty, enumerable,
floor, length, max, min, pow, prototype, slice, toChunks, value,
writable
*/
/*
* Properties used in the testing of toChunks implimentation.
*/
/*property
appendChild, createTextNode, floor, fromCharCode, getElementById, length,
log, pow, push, random, toChunks
*/
(function () {
'use strict';
var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1;
/**
* Defines a new property directly on an object, or modifies an existing
* property on an object, and returns the object.
*
* @private
* @function
* @param {Object} object
* @param {string} property
* @param {Object} descriptor
* @return {Object}
* @see https://goo.gl/CZnEqg
*/
function $defineProperty(object, property, descriptor) {
if (Object.defineProperty) {
Object.defineProperty(object, property, descriptor);
} else {
object[property] = descriptor.value;
}
return object;
}
/**
* Returns true if the operands are strictly equal with no type conversion.
*
* @private
* @function
* @param {*} a
* @param {*} b
* @return {boolean}
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.4
*/
function $strictEqual(a, b) {
return a === b;
}
/**
* Returns true if the operand inputArg is undefined.
*
* @private
* @function
* @param {*} inputArg
* @return {boolean}
*/
function $isUndefined(inputArg) {
return $strictEqual(typeof inputArg, 'undefined');
}
/**
* The abstract operation throws an error if its argument is a value that
* cannot be converted to an Object, otherwise returns the argument.
*
* @private
* @function
* @param {*} inputArg The object to be tested.
* @throws {TypeError} If inputArg is null or undefined.
* @return {*} The inputArg if coercible.
* @see https://goo.gl/5GcmVq
*/
function $requireObjectCoercible(inputArg) {
var errStr;
if (inputArg === null || $isUndefined(inputArg)) {
errStr = 'Cannot convert argument to object: ' + inputArg;
throw new TypeError(errStr);
}
return inputArg;
}
/**
* The abstract operation converts its argument to a value of type string
*
* @private
* @function
* @param {*} inputArg
* @return {string}
* @see https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tostring
*/
function $toString(inputArg) {
var type,
val;
if (inputArg === null) {
val = 'null';
} else {
type = typeof inputArg;
if (type === 'string') {
val = inputArg;
} else if (type === 'undefined') {
val = type;
} else {
if (type === 'symbol') {
throw new TypeError('Cannot convert symbol to string');
}
val = String(inputArg);
}
}
return val;
}
/**
* Returns a string only if the arguments is coercible otherwise throws an
* error.
*
* @private
* @function
* @param {*} inputArg
* @throws {TypeError} If inputArg is null or undefined.
* @return {string}
*/
function $onlyCoercibleToString(inputArg) {
return $toString($requireObjectCoercible(inputArg));
}
/**
* The function evaluates the passed value and converts it to an integer.
*
* @private
* @function
* @param {*} inputArg The object to be converted to an integer.
* @return {number} If the target value is NaN, null or undefined, 0 is
* returned. If the target value is false, 0 is returned
* and if true, 1 is returned.
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-9.4
*/
function $toInteger(inputArg) {
var number = +inputArg,
val = 0;
if ($strictEqual(number, number)) {
if (!number || number === Infinity || number === -Infinity) {
val = number;
} else {
val = (number > 0 || -1) * Math.floor(Math.abs(number));
}
}
return val;
}
/**
* The abstract operation ToLength converts its argument to an integer
* suitable for use as the length of an array-like object.
*
* @private
* @function
* @param {*} inputArg The object to be converted to a length.
* @return {number} If len <= +0 then +0 else if len is +INFINITY then
* 2^53-1 else min(len, 2^53-1).
* @see https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
*/
function $toLength(inputArg) {
return Math.min(Math.max($toInteger(inputArg), 0), MAX_SAFE_INTEGER);
}
if (!String.prototype.toChunks) {
/**
* This method chunks a string into an array of strings of a specified
* chunk size.
*
* @function
* @this {string} The string to be chunked.
* @param {Number} chunkSize The size of the chunks that the string will
* be chunked into.
* @returns {Array} Returns an array of the chunked string.
*/
$defineProperty(String.prototype, 'toChunks', {
enumerable: false,
configurable: true,
writable: true,
value: function (chunkSize) {
var str = $onlyCoercibleToString(this),
chunkLength = $toInteger(chunkSize),
chunked = [],
numChunks,
length,
index,
start,
end;
if (chunkLength < 1) {
return chunked;
}
length = $toLength(str.length);
numChunks = Math.ceil(length / chunkLength);
index = 0;
start = 0;
end = chunkLength;
chunked.length = numChunks;
while (index < numChunks) {
chunked[index] = str.slice(start, end);
start = end;
end += chunkLength;
index += 1;
}
return chunked;
}
});
}
}());
/*
* Some tests
*/
(function () {
'use strict';
var pre = document.getElementById('out'),
chunkSizes = [],
maxChunkSize = 512,
testString = '',
maxTestString = 100000,
chunkSize = 0,
index = 1;
while (chunkSize < maxChunkSize) {
chunkSize = Math.pow(2, index);
chunkSizes.push(chunkSize);
index += 1;
}
index = 0;
while (index < maxTestString) {
testString += String.fromCharCode(Math.floor(Math.random() * 95) + 32);
index += 1;
}
function log(result) {
pre.appendChild(document.createTextNode(result + '\n'));
}
function test() {
var strLength = testString.length,
czLength = chunkSizes.length,
czIndex = 0,
czValue,
result,
numChunks,
pass;
while (czIndex < czLength) {
czValue = chunkSizes[czIndex];
numChunks = Math.ceil(strLength / czValue);
result = testString.toChunks(czValue);
czIndex += 1;
log('chunksize: ' + czValue);
log(' Number of chunks:');
log(' Calculated: ' + numChunks);
log(' Actual:' + result.length);
pass = result.length === numChunks;
log(' First chunk size: ' + result[0].length);
pass = pass && result[0].length === czValue;
log(' Passed: ' + pass);
log('');
}
}
test();
log('');
log('Simple test result');
log('abcdefghijklmnopqrstuvwxyz'.toChunks(3));
}());
<pre id="out"></pre>