Skip to content

Instantly share code, notes, and snippets.

@brainysmurf
Last active January 21, 2018 10:05
Show Gist options
  • Select an option

  • Save brainysmurf/d7b5cc6641e3021c871a856f5532fb59 to your computer and use it in GitHub Desktop.

Select an option

Save brainysmurf/d7b5cc6641e3021c871a856f5532fb59 to your computer and use it in GitHub Desktop.
FormatLogger is an alternative logging module for google app scripting. This gist is for the package manager.
(function () {
return {
self: {"formatLogger": "d7b5cc6641e3021c871a856f5532fb59"},
packages: [
{"utgs": "07eaf09769b450f1e0e7b6ae043c2ba5"},
]
};
})();
(function (global, Factory) {
global.pkg = global.pkg || {};
pkg.formatLogger = function () { return Factory.apply(Factory, [global].concat(Array.prototype.slice.call(arguments))); }
pkg.formatLogger(); // can be overwritten with another call if transformers are desired
})(this,
function Package (global, options) {
options = options || {};
if (options.useLogger)
options.loggerObject = Logger;
else
options.loggerObject = console;
options.transformers = options.transformers || {};
options.defaultTransformString = options.defaultTransformString || "{0}";
options.pprintNewlines = options.pprintNewlines || true;
options.pprintWhitespace = options.pprintWhitespace || 4;
// ValueError :: String -> Error
var ValueError = function(message) {
var err = new Error(message);
err.name = 'ValueError';
return err;
};
// defaultTo :: a,a? -> a
var defaultTo = function(x, y) {
return y == null ? x : y;
};
// create :: Object -> String,*... -> String
var create = function() {
return function(template) {
var args = Array.prototype.slice.call(arguments, 1);
var idx = 0;
var state = 'UNDEFINED';
return template.replace(
/([{}])\1|[{](.*?)(?:!(.+?))?[}]/g,
function(match, literal, key, xf) {
if (literal != null) {
return literal;
}
if (key.length > 0) {
if (state === 'IMPLICIT') {
throw ValueError('cannot switch from ' +
'implicit to explicit numbering');
}
state = 'EXPLICIT';
} else {
if (state === 'EXPLICIT') {
throw ValueError('cannot switch from ' +
'explicit to implicit numbering');
}
state = 'IMPLICIT';
key = String(idx);
idx += 1;
}
var value = defaultTo('', lookup(args, key.split('.')));
if (xf == null) {
return value;
} else if (Object.prototype.hasOwnProperty.call(options.transformers, xf)) {
return options.transformers[xf](value);
} else {
throw ValueError('no transformer named "' + xf + '"');
}
}
);
};
};
var lookup = function(obj, path) {
if (!/^\d+$/.test(path[0])) {
path = ['0'].concat(path);
}
for (var idx = 0; idx < path.length; idx += 1) {
var key = path[idx];
if (typeof obj[key] === 'function')
obj = obj[key]();
else
obj = obj[key];
}
return obj;
};
Object.defineProperty(Object.prototype, 'stringify', {
get: function () {
return function (pretty) {
pretty = pretty || false;
if (pretty)
return (options.pprintNewlines ? "\n" : "") +
options.defaultTransformString.format(JSON.stringify(this, null, options.pprintWhitespace), this);
else
return options.defaultTransformString.format(JSON.stringify(this), this);
}
},
configurable: true,
enumerable: false,
});
Object.defineProperty(Object.prototype, 'typeof_', {
get: function () {
var result = typeof this;
switch (result) {
case 'string':
break;
case 'boolean':
break;
case 'number':
break;
case 'object':
case 'function':
switch (this.constructor) {
case new String().constructor:
result = 'String';
break;
case new Boolean().constructor:
result = 'Boolean';
break;
case new Number().constructor:
result = 'Number';
break;
case new Array().constructor:
result = 'Array';
break;
case new RegExp().constructor:
result = 'RegExp';
break;
case new Date().constructor:
result = 'Date';
break;
case Function:
result = 'Function';
break;
default:
result = this.constructor.toString();
var m = this.constructor.toString().match(/function\s*([^( ]+)\(/);
if (m)
result = m[1];
else
result = 'Function';
break;
}
break;
}
return result.substr(0, 1).toUpperCase() + result.substr(1);
},
configurable: true,
enumerable: false,
});
Object.defineProperty(Object.prototype, 'print', {
get: function () {
return this.stringify(false);
},
configurable: true,
enumerable: false,
});
Object.defineProperty(Object.prototype, '__print__', {
get: function () {
options.loggerObject.log.call(options.loggerObject, this.stringify(false) );
},
configurable: true,
enumerable: false,
});
Object.defineProperty(Object.prototype, 'pprint', {
get: function () {
return this.stringify(true);
},
configurable: true,
enumerable: false,
});
Object.defineProperty(Object.prototype, '__pprint__', {
get: function () {
options.loggerObject.log.call(options.loggerObject, this.stringify(true) );
},
configurable: true,
enumerable: false,
});
Object.defineProperty(String.prototype, '__log__', {
get: function () {
return function() {
options.loggerObject.log.call(options.loggerObject, this.format.apply(this, Array.prototype.slice.call(arguments)) );
}.bind(this);
},
configurable: true,
enumerable: false,
});
Object.defineProperty(String.prototype, '__error__', {
get: function () {
return function() {
options.loggerObject.error.call(options.loggerObject, this.format.apply(this, Array.prototype.slice.call(arguments)) );
}.bind(this);
},
configurable: true,
enumerable: false,
});
Object.defineProperty(String.prototype, '__info__', {
get: function () {
return function() {
options.loggerObject.info.call(options.loggerObject, this.format.apply(this, Array.prototype.slice.call(arguments)) );
}.bind(this);
},
configurable: true,
enumerable: false,
});
Object.defineProperty(String.prototype, '__warn__', {
get: function () {
return function() {
options.loggerObject.warn.call(options.loggerObject, this.format.apply(this, Array.prototype.slice.call(arguments)) );
}.bind(this);
},
configurable: true,
enumerable: false,
});
Object.defineProperty(String.prototype, 'format', {
get: function () {
var $format = create(options.transformers);
return function () {
var args = Array.prototype.slice.call(arguments);
args.unshift(this);
return $format.apply(global, args);
}
},
configurable: true,
enumerable: false,
});
}
);
(function () {
return {
version: 0,
packages: [
{"": ""},
]
};
})();
function testing___log() {
function getLog_() {
var log, index;
log = Logger.getLog();
index = log.indexOf('INFO: ');
if (index == -1)
throw Error("Wonky log: " + log);
log = log.slice(index + 'INFO: '.length, log.length-1);
return log;
}
/*
These tests can only be run if the Logger output is clear
*/
if (Logger.getLog() != "")
return;
/*
Sequence of these init is important
formatLogger needs to be inited after utgs
*/
pkg.utgs.init();
pkg.formatLogger({
useLogger: true,
defaultTransformString: "<{0}> ({1.typeof_})",
pprintNewLines: false,
});
describe("format, __print__, __pprint__, __log__", function () {
Logger.clear();
it("__print__ echoes to log all properties of an object", function () {
var obj = {hello: "Hello", world: "World!"};
obj.__print__;
assert.objectEquals({
expected: '<{"hello":"Hello","world":"World!"}> (Object)',
actual: getLog_(),
});
});
Logger.clear()
it("__print__ converts integer keys into strings (because json)", function () {
var obj = {0: "Hello", 1: "World!"};
obj.__print__;
assert.objectEquals({
comment: "Note the number literals have become strings",
expected: '<{"0":"Hello","1":"World!"}> (Object)',
actual: getLog_(),
});
});
Logger.clear();
it("__print__ echoes to log all elements of an array", function () {
var arr = [1, 2, "3", {info: 'info'}];
arr.__print__;
assert.objectEquals({
expected: '<[1,2,"3",{"info":"info"}]> (Array)',
actual: getLog_(),
});
});
Logger.clear();
it("__print__ echoes to log the string", function () {
var str = "This is a testing string";
str.__print__;
assert.objectEquals({
expected: '<"This is a testing string"> (String)',
actual: getLog_(),
});
});
Logger.clear();
it("__print__ echoes to log the number", function () {
var num = 2342342.34223;
num.__print__;
assert.objectEquals({
comment: "Notice that literal numbers turn into strings",
expected: "<2342342.34223> (Number)",
actual: getLog_(),
});
});
Logger.clear();
it("__pprint__ echoes to log pretty print of all properties of an object", function () {
var obj = {hello: "Hello", world: "World!", 0: "zero"};
obj.__pprint__;
assert.objectEquals({
expected: '\n<{\n "hello": "Hello",\n "world": "World!",\n "0": "zero"\n}> (Object)',
actual: getLog_(),
});
});
Logger.clear();
it("__pprint__ echoes to log pretty print of all elements of an array", function () {
var arr = [1, 2, "3", {info: 'info'}];
arr.__pprint__;
assert.objectEquals({
expected: '\n<[\n 1,\n 2,\n "3",\n {\n "info": "info"\n }\n]> (Array)',
actual: getLog_(),
});
});
Logger.clear();
it("__pprint__ echoes to log pretty print of the string", function () {
var str = "This is a testing string";
str.__pprint__;
assert.objectEquals({
expected: '\n<"This is a testing string"> (String)',
actual: getLog_(),
});
});
Logger.clear();
it("__pprint__ echoes to log pretty print of the number", function () {
var num = 2342342.34223;
num.__pprint__;
assert.objectEquals({
expected: '\n<2342342.34223> (Number)',
actual: getLog_(),
});
});
Logger.clear();
it("__log__ echoes same as __print__ to log templated strings", function () {
var obj = {that:"this", will: [1, 23, {hi:'hi'}], 0: "zero"};
"{0.print}".__log__(obj);
assert.objectEquals({
comment: "Notice the zero literal became a string",
expected: '<{"that":"this","will":[1,23,{"hi":"hi"}],"0":"zero"}> (Object)',
actual: getLog_(),
});
});
Logger.clear();
it("__log__ echoes with explicit keys and dot properties", function () {
var obj = {that:"this", will: [1, 23, {hi:'hi'}], 0: "zero"};
var arr = [1, 2, 3, 4];
"{0.print}\n{1.length}: {1.pprint}".__log__(obj, arr);
assert.objectEquals({
comment: "Notice the zero literal became a string",
expected: '<{"that":"this","will":[1,23,{"hi":"hi"}],"0":"zero"}> (Object)\n' + '4: \n<[\n 1,\n 2,\n 3,\n 4\n]> (Array)',
actual: getLog_(),
});
});
it("array?", function () {
var str = "{0.0} {0.1}".format(["hi", "hello"]);
assert.objectEquals({
comment: "Notation for this is a bit strange",
expected: 'hi hello',
actual: str
});
});
Logger.clear();
it("array with __log__", function () {
"{0.0} {0.1}".__log__(["hi", "hello"]);
assert.objectEquals({
comment: "",
expected: "hi hello",
actual: getLog_(),
});
});
Logger.clear();
it("array2 with __print__", function () {
["hi", "hello"].__print__;
assert.objectEquals({
comment: "",
expected: '<["hi","hello"]> (Array)',
actual: getLog_(),
});
});
Logger.clear();
it("object", function () {
var str = "{0.hi} => {0.zup}".format({hi:"hi", zup:'zup'});
assert.objectEquals({
expected: 'hi => zup',
actual: str,
});
});
it("format", function () {
var str = "{0}".format("hi");
assert.objectEquals({
expected: "hi",
actual: str
});
var str = "{0.hi} {0.zup}".format({hi:"hi", zup:'zup'});
assert.objectEquals({
expected: 'hi zup',
actual: str,
});
});
it("transformers", function () {
pkg.formatLogger({
transformers: {
upper: function (s) { return s.toUpperCase(); }
},
});
var str = "{0.0!upper}".format(["this should be in upper case"]);
assert.objectEquals({
expected: 'THIS SHOULD BE IN UPPER CASE',
actual: str,
});
});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment