scientist
Version:
Carefully refactor critical paths in production
140 lines (121 loc) • 3.8 kB
JavaScript
var Measurement, Observation, Promise, _, inspect,
slice = [].slice;
_ = require('underscore');
Promise = require('bluebird');
inspect = require('util').inspect;
Measurement = require('./measurement');
Observation = (function() {
Observation.withMeasurement = function() {
var args, measure, mixin, observation;
measure = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
mixin = _.create(this.prototype, {
measure: measure
});
observation = _.create(mixin);
this.apply(observation, args);
return observation;
};
function Observation(name, block, options) {
var ref;
if (options == null) {
options = {};
}
this.name = name;
this._options = options;
this.startTime = (ref = options.startTime) != null ? ref : new Date();
this._time = this.measure((function(_this) {
return function() {
var error, error1;
try {
return _this.value = block();
} catch (error1) {
error = error1;
return _this.error = error;
}
};
})(this));
this.duration = this._time.elapsed;
Object.freeze(this);
}
Observation.prototype.measure = Measurement.benchmark;
Observation.prototype.evaluation = function() {
if (this.didReturn()) {
return this.value;
} else {
throw this.error;
}
};
Observation.prototype.settle = function() {
return Promise["try"](this.evaluation.bind(this)).reflect().then((function(_this) {
return function(inspection) {
if (inspection.isFulfilled()) {
return function() {
return inspection.value();
};
} else {
return function() {
throw inspection.reason();
};
}
};
})(this)).then((function(_this) {
return function(block) {
return Observation.withMeasurement(_this._time.remeasure.bind(_this._time), _this.name, block, _.defaults({
startTime: _this.startTime
}, _this._options));
};
})(this));
};
Observation.prototype.map = function(f) {
var block;
if (this.didReturn()) {
block = _.constant(f(this.value));
return Observation.withMeasurement(this._time.preserve.bind(this._time), this.name, block, _.defaults({
startTime: this.startTime
}, this._options));
} else {
return this;
}
};
Observation.prototype.didReturn = function() {
return this.error == null;
};
Observation.prototype.ignores = function(other) {
if (!(other instanceof Observation)) {
return false;
}
if (_.isEmpty(this._options.ignorers)) {
return false;
}
return _.any(this._options.ignorers, (function(_this) {
return function(predicate) {
return predicate(_this, other);
};
})(this));
};
Observation.prototype.matches = function(other) {
if (!(other instanceof Observation)) {
return false;
}
if (this.didReturn() && other.didReturn()) {
return Boolean(this._options.comparator(this.value, other.value));
}
if (!this.didReturn() && !other.didReturn()) {
return this._compareErrors(this.error, other.error);
}
return false;
};
Observation.prototype._compareErrors = function(a, b) {
return (a.constructor === b.constructor) && _.isEqual(a.message, b.message);
};
Observation.prototype.inspect = function(depth, options) {
var ref;
if (this.didReturn()) {
return "value: " + (inspect(this._options.cleaner(this.value), options));
} else {
return "error: [" + ((ref = this.error.constructor) != null ? ref.name : void 0) + "] " + (inspect(this.error.message, options));
}
};
return Observation;
})();
module.exports = Observation;