mirror of
https://github.com/JuanCanham/HackMyResume.git
synced 2024-11-22 00:10:15 +00:00
refactor: remove AbstractResume base class
(1) AbstractResume adds complexity without contributing utility. There's not really a clean "class" abstraction in JavaScript to begin with; CoffeeScript classes, as nice as they are syntactically, occlude the issue even further. (2) AbstractResume currently functions as a container for exactly two functions which arguably should live outside the resume class anyway.
This commit is contained in:
parent
2767b16b47
commit
8dca5b76e7
113
dist/core/abstract-resume.js
vendored
113
dist/core/abstract-resume.js
vendored
@ -1,113 +0,0 @@
|
|||||||
|
|
||||||
/**
|
|
||||||
Definition of the AbstractResume class.
|
|
||||||
@license MIT. See LICENSE.md for details.
|
|
||||||
@module core/abstract-resume
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var AbstractResume, FluentDate, _, __;
|
|
||||||
|
|
||||||
_ = require('underscore');
|
|
||||||
|
|
||||||
__ = require('lodash');
|
|
||||||
|
|
||||||
FluentDate = require('./fluent-date');
|
|
||||||
|
|
||||||
AbstractResume = (function() {
|
|
||||||
function AbstractResume() {}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Compute the total duration of the work history.
|
|
||||||
@returns The total duration of the sheet's work history, that is, the number
|
|
||||||
of years between the start date of the earliest job on the resume and the
|
|
||||||
*latest end date of all jobs in the work history*. This last condition is for
|
|
||||||
sheets that have overlapping jobs.
|
|
||||||
*/
|
|
||||||
|
|
||||||
AbstractResume.prototype.duration = function(collKey, startKey, endKey, unit) {
|
|
||||||
var firstDate, hist, lastDate, new_e;
|
|
||||||
unit = unit || 'years';
|
|
||||||
hist = __.get(this, collKey);
|
|
||||||
if (!hist || !hist.length) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
new_e = hist.map(function(job) {
|
|
||||||
var obj;
|
|
||||||
obj = _.pick(job, [startKey, endKey]);
|
|
||||||
if (!_.has(obj, endKey)) {
|
|
||||||
obj[endKey] = 'current';
|
|
||||||
}
|
|
||||||
if (obj && (obj[startKey] || obj[endKey])) {
|
|
||||||
obj = _.pairs(obj);
|
|
||||||
obj[0][1] = FluentDate.fmt(obj[0][1]);
|
|
||||||
if (obj.length > 1) {
|
|
||||||
obj[1][1] = FluentDate.fmt(obj[1][1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
});
|
|
||||||
new_e = _.filter(_.flatten(new_e, true), function(v) {
|
|
||||||
return v && v.length && v[0] && v[0].length;
|
|
||||||
});
|
|
||||||
if (!new_e || !new_e.length) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
new_e = _.sortBy(new_e, function(elem) {
|
|
||||||
return elem[1].unix();
|
|
||||||
});
|
|
||||||
firstDate = _.first(new_e)[1];
|
|
||||||
lastDate = _.last(new_e)[1];
|
|
||||||
return lastDate.diff(firstDate, unit);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Removes ignored or private fields from a resume object
|
|
||||||
@returns an object with the following structure:
|
|
||||||
{
|
|
||||||
scrubbed: the processed resume object
|
|
||||||
ignoreList: an array of ignored nodes that were removed
|
|
||||||
privateList: an array of private nodes that were removed
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
AbstractResume.prototype.scrubResume = function(rep, opts) {
|
|
||||||
var ignoreList, includePrivates, privateList, scrubbed, traverse;
|
|
||||||
traverse = require('traverse');
|
|
||||||
ignoreList = [];
|
|
||||||
privateList = [];
|
|
||||||
includePrivates = opts && opts["private"];
|
|
||||||
scrubbed = traverse(rep).map(function() {
|
|
||||||
if (!this.isLeaf) {
|
|
||||||
if (this.node.ignore === true || this.node.ignore === 'true') {
|
|
||||||
ignoreList.push(this.node);
|
|
||||||
this["delete"]();
|
|
||||||
} else if ((this.node["private"] === true || this.node["private"] === 'true') && !includePrivates) {
|
|
||||||
privateList.push(this.node);
|
|
||||||
this["delete"]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_.isArray(this.node)) {
|
|
||||||
this.after(function() {
|
|
||||||
this.update(_.compact(this.node));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
scrubbed: scrubbed,
|
|
||||||
ingoreList: ignoreList,
|
|
||||||
privateList: privateList
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return AbstractResume;
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
module.exports = AbstractResume;
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
|
|
||||||
//# sourceMappingURL=abstract-resume.js.map
|
|
25
dist/core/fresh-resume.js
vendored
25
dist/core/fresh-resume.js
vendored
@ -6,9 +6,7 @@ Definition of the FRESHResume class.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var AbstractResume, CONVERTER, FS, FluentDate, FreshResume, JRSResume, MD, PATH, XML, _, __, _parseDates, extend, moment, validator,
|
var CONVERTER, FS, FluentDate, FreshResume, JRSResume, MD, PATH, XML, _, __, _parseDates, extend, moment, validator;
|
||||||
extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
||||||
hasProp = {}.hasOwnProperty;
|
|
||||||
|
|
||||||
FS = require('fs');
|
FS = require('fs');
|
||||||
|
|
||||||
@ -34,8 +32,6 @@ Definition of the FRESHResume class.
|
|||||||
|
|
||||||
FluentDate = require('./fluent-date');
|
FluentDate = require('./fluent-date');
|
||||||
|
|
||||||
AbstractResume = require('./abstract-resume');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A FRESH resume or CV. FRESH resumes are backed by JSON, and each FreshResume
|
A FRESH resume or CV. FRESH resumes are backed by JSON, and each FreshResume
|
||||||
@ -43,12 +39,8 @@ Definition of the FRESHResume class.
|
|||||||
@constructor
|
@constructor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FreshResume = (function(superClass) {
|
FreshResume = (function() {
|
||||||
extend1(FreshResume, superClass);
|
function FreshResume() {}
|
||||||
|
|
||||||
function FreshResume() {
|
|
||||||
return FreshResume.__super__.constructor.apply(this, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Initialize the the FreshResume from JSON string data. */
|
/** Initialize the the FreshResume from JSON string data. */
|
||||||
@ -77,9 +69,10 @@ Definition of the FRESHResume class.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
FreshResume.prototype.parseJSON = function(rep, opts) {
|
FreshResume.prototype.parseJSON = function(rep, opts) {
|
||||||
var ignoreList, privateList, ref, ref1, scrubbed;
|
var ignoreList, privateList, ref, ref1, scrubbed, scrubber;
|
||||||
if (opts && opts.privatize) {
|
if (opts && opts.privatize) {
|
||||||
ref = this.scrubResume(rep, opts), scrubbed = ref.scrubbed, ignoreList = ref.ignoreList, privateList = ref.privateList;
|
scrubber = require('../utils/resume-scrubber');
|
||||||
|
ref = scrubber.scrubResume(rep, opts), scrubbed = ref.scrubbed, ignoreList = ref.ignoreList, privateList = ref.privateList;
|
||||||
}
|
}
|
||||||
extend(true, this, opts && opts.privatize ? scrubbed : rep);
|
extend(true, this, opts && opts.privatize ? scrubbed : rep);
|
||||||
if (!((ref1 = this.imp) != null ? ref1.processed : void 0)) {
|
if (!((ref1 = this.imp) != null ? ref1.processed : void 0)) {
|
||||||
@ -368,7 +361,9 @@ Definition of the FRESHResume class.
|
|||||||
};
|
};
|
||||||
|
|
||||||
FreshResume.prototype.duration = function(unit) {
|
FreshResume.prototype.duration = function(unit) {
|
||||||
return FreshResume.__super__.duration.call(this, 'employment.history', 'start', 'end', unit);
|
var inspector;
|
||||||
|
inspector = require('../inspectors/duration-inspector');
|
||||||
|
return inspector.run(this, 'employment.history', 'start', 'end', unit);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -415,7 +410,7 @@ Definition of the FRESHResume class.
|
|||||||
|
|
||||||
return FreshResume;
|
return FreshResume;
|
||||||
|
|
||||||
})(AbstractResume);
|
})();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
25
dist/core/jrs-resume.js
vendored
25
dist/core/jrs-resume.js
vendored
@ -6,9 +6,7 @@ Definition of the JRSResume class.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var AbstractResume, CONVERTER, FS, JRSResume, MD, PATH, _, _parseDates, extend, moment, validator,
|
var CONVERTER, FS, JRSResume, MD, PATH, _, _parseDates, extend, moment, validator;
|
||||||
extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
||||||
hasProp = {}.hasOwnProperty;
|
|
||||||
|
|
||||||
FS = require('fs');
|
FS = require('fs');
|
||||||
|
|
||||||
@ -26,8 +24,6 @@ Definition of the JRSResume class.
|
|||||||
|
|
||||||
moment = require('moment');
|
moment = require('moment');
|
||||||
|
|
||||||
AbstractResume = require('./abstract-resume');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A JRS resume or CV. JRS resumes are backed by JSON, and each JRSResume object
|
A JRS resume or CV. JRS resumes are backed by JSON, and each JRSResume object
|
||||||
@ -35,14 +31,10 @@ Definition of the JRSResume class.
|
|||||||
@class JRSResume
|
@class JRSResume
|
||||||
*/
|
*/
|
||||||
|
|
||||||
JRSResume = (function(superClass) {
|
JRSResume = (function() {
|
||||||
var clear;
|
var clear;
|
||||||
|
|
||||||
extend1(JRSResume, superClass);
|
function JRSResume() {}
|
||||||
|
|
||||||
function JRSResume() {
|
|
||||||
return JRSResume.__super__.constructor.apply(this, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Initialize the the JSResume from string. */
|
/** Initialize the the JSResume from string. */
|
||||||
@ -71,10 +63,11 @@ Definition of the JRSResume class.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
JRSResume.prototype.parseJSON = function(rep, opts) {
|
JRSResume.prototype.parseJSON = function(rep, opts) {
|
||||||
var ignoreList, privateList, ref, ref1, scrubbed;
|
var ignoreList, privateList, ref, ref1, scrubbed, scrubber;
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
if (opts.privatize) {
|
if (opts.privatize) {
|
||||||
ref = this.scrubResume(rep, opts), scrubbed = ref.scrubbed, ignoreList = ref.ignoreList, privateList = ref.privateList;
|
scrubber = require('../utils/resume-scrubber');
|
||||||
|
ref = scrubber.scrubResume(rep, opts), scrubbed = ref.scrubbed, ignoreList = ref.ignoreList, privateList = ref.privateList;
|
||||||
}
|
}
|
||||||
extend(true, this, opts.privatize ? scrubbed : rep);
|
extend(true, this, opts.privatize ? scrubbed : rep);
|
||||||
if (!((ref1 = this.imp) != null ? ref1.processed : void 0)) {
|
if (!((ref1 = this.imp) != null ? ref1.processed : void 0)) {
|
||||||
@ -239,7 +232,9 @@ Definition of the JRSResume class.
|
|||||||
};
|
};
|
||||||
|
|
||||||
JRSResume.prototype.duration = function(unit) {
|
JRSResume.prototype.duration = function(unit) {
|
||||||
return JRSResume.__super__.duration.call(this, 'work', 'startDate', 'endDate', unit);
|
var inspector;
|
||||||
|
inspector = require('../inspectors/duration-inspector');
|
||||||
|
return inspector.run(this, 'work', 'startDate', 'endDate', unit);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -339,7 +334,7 @@ Definition of the JRSResume class.
|
|||||||
|
|
||||||
return JRSResume;
|
return JRSResume;
|
||||||
|
|
||||||
})(AbstractResume);
|
})();
|
||||||
|
|
||||||
|
|
||||||
/** Get the default (empty) sheet. */
|
/** Get the default (empty) sheet. */
|
||||||
|
56
dist/inspectors/duration-inspector.js
vendored
Normal file
56
dist/inspectors/duration-inspector.js
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
(function() {
|
||||||
|
var FluentDate, _;
|
||||||
|
|
||||||
|
FluentDate = require('../core/fluent-date');
|
||||||
|
|
||||||
|
_ = require('underscore');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Compute the total duration of the work history.
|
||||||
|
@returns The total duration of the sheet's work history, that is, the number
|
||||||
|
of years between the start date of the earliest job on the resume and the
|
||||||
|
*latest end date of all jobs in the work history*. This last condition is for
|
||||||
|
sheets that have overlapping jobs.
|
||||||
|
*/
|
||||||
|
run: function(rez, collKey, startKey, endKey, unit) {
|
||||||
|
var firstDate, hist, lastDate, new_e;
|
||||||
|
unit = unit || 'years';
|
||||||
|
hist = __.get(rez, collKey);
|
||||||
|
if (!hist || !hist.length) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
new_e = hist.map(function(job) {
|
||||||
|
var obj;
|
||||||
|
obj = _.pick(job, [startKey, endKey]);
|
||||||
|
if (!_.has(obj, endKey)) {
|
||||||
|
obj[endKey] = 'current';
|
||||||
|
}
|
||||||
|
if (obj && (obj[startKey] || obj[endKey])) {
|
||||||
|
obj = _.pairs(obj);
|
||||||
|
obj[0][1] = FluentDate.fmt(obj[0][1]);
|
||||||
|
if (obj.length > 1) {
|
||||||
|
obj[1][1] = FluentDate.fmt(obj[1][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
new_e = _.filter(_.flatten(new_e, true), function(v) {
|
||||||
|
return v && v.length && v[0] && v[0].length;
|
||||||
|
});
|
||||||
|
if (!new_e || !new_e.length) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
new_e = _.sortBy(new_e, function(elem) {
|
||||||
|
return elem[1].unix();
|
||||||
|
});
|
||||||
|
firstDate = _.first(new_e)[1];
|
||||||
|
lastDate = _.last(new_e)[1];
|
||||||
|
return lastDate.diff(firstDate, unit);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}).call(this);
|
||||||
|
|
||||||
|
//# sourceMappingURL=duration-inspector.js.map
|
45
dist/utils/resume-scrubber.js
vendored
Normal file
45
dist/utils/resume-scrubber.js
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
(function() {
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Removes ignored or private fields from a resume object
|
||||||
|
@returns an object with the following structure:
|
||||||
|
{
|
||||||
|
scrubbed: the processed resume object
|
||||||
|
ignoreList: an array of ignored nodes that were removed
|
||||||
|
privateList: an array of private nodes that were removed
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
scrubResume: function(rep, opts) {
|
||||||
|
var ignoreList, includePrivates, privateList, scrubbed, traverse;
|
||||||
|
traverse = require('traverse');
|
||||||
|
ignoreList = [];
|
||||||
|
privateList = [];
|
||||||
|
includePrivates = opts && opts["private"];
|
||||||
|
scrubbed = traverse(rep).map(function() {
|
||||||
|
if (!this.isLeaf) {
|
||||||
|
if (this.node.ignore === true || this.node.ignore === 'true') {
|
||||||
|
ignoreList.push(this.node);
|
||||||
|
this["delete"]();
|
||||||
|
} else if ((this.node["private"] === true || this.node["private"] === 'true') && !includePrivates) {
|
||||||
|
privateList.push(this.node);
|
||||||
|
this["delete"]();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_.isArray(this.node)) {
|
||||||
|
this.after(function() {
|
||||||
|
this.update(_.compact(this.node));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
scrubbed: scrubbed,
|
||||||
|
ingoreList: ignoreList,
|
||||||
|
privateList: privateList
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}).call(this);
|
||||||
|
|
||||||
|
//# sourceMappingURL=resume-scrubber.js.map
|
@ -1,98 +0,0 @@
|
|||||||
###*
|
|
||||||
Definition of the AbstractResume class.
|
|
||||||
@license MIT. See LICENSE.md for details.
|
|
||||||
@module core/abstract-resume
|
|
||||||
###
|
|
||||||
|
|
||||||
_ = require 'underscore'
|
|
||||||
__ = require 'lodash'
|
|
||||||
FluentDate = require('./fluent-date')
|
|
||||||
|
|
||||||
class AbstractResume
|
|
||||||
|
|
||||||
###*
|
|
||||||
Compute the total duration of the work history.
|
|
||||||
@returns The total duration of the sheet's work history, that is, the number
|
|
||||||
of years between the start date of the earliest job on the resume and the
|
|
||||||
*latest end date of all jobs in the work history*. This last condition is for
|
|
||||||
sheets that have overlapping jobs.
|
|
||||||
###
|
|
||||||
duration: (collKey, startKey, endKey, unit) ->
|
|
||||||
unit = unit || 'years'
|
|
||||||
hist = __.get @, collKey
|
|
||||||
return 0 if !hist or !hist.length
|
|
||||||
|
|
||||||
# BEGIN CODE DUPLICATION --> src/inspectors/gap-inspector.coffee (TODO)
|
|
||||||
|
|
||||||
# Convert the candidate's employment history to an array of dates,
|
|
||||||
# where each element in the array is a start date or an end date of a
|
|
||||||
# job -- it doesn't matter which.
|
|
||||||
new_e = hist.map ( job ) ->
|
|
||||||
obj = _.pick( job, [startKey, endKey] )
|
|
||||||
# Synthesize an end date if this is a "current" gig
|
|
||||||
obj[endKey] = 'current' if !_.has obj, endKey
|
|
||||||
if obj && (obj[startKey] || obj[endKey])
|
|
||||||
obj = _.pairs obj
|
|
||||||
obj[0][1] = FluentDate.fmt( obj[0][1] )
|
|
||||||
if obj.length > 1
|
|
||||||
obj[1][1] = FluentDate.fmt( obj[1][1] )
|
|
||||||
obj
|
|
||||||
|
|
||||||
# Flatten the array, remove empties, and sort
|
|
||||||
new_e = _.filter _.flatten( new_e, true ), (v) ->
|
|
||||||
return v && v.length && v[0] && v[0].length
|
|
||||||
return 0 if !new_e or !new_e.length
|
|
||||||
new_e = _.sortBy new_e, ( elem ) -> return elem[1].unix()
|
|
||||||
|
|
||||||
# END CODE DUPLICATION
|
|
||||||
|
|
||||||
firstDate = _.first( new_e )[1];
|
|
||||||
lastDate = _.last( new_e )[1];
|
|
||||||
lastDate.diff firstDate, unit
|
|
||||||
|
|
||||||
###*
|
|
||||||
Removes ignored or private fields from a resume object
|
|
||||||
@returns an object with the following structure:
|
|
||||||
{
|
|
||||||
scrubbed: the processed resume object
|
|
||||||
ignoreList: an array of ignored nodes that were removed
|
|
||||||
privateList: an array of private nodes that were removed
|
|
||||||
}
|
|
||||||
###
|
|
||||||
scrubResume: (rep, opts) ->
|
|
||||||
traverse = require 'traverse'
|
|
||||||
ignoreList = []
|
|
||||||
privateList = []
|
|
||||||
includePrivates = opts && opts.private
|
|
||||||
|
|
||||||
scrubbed = traverse( rep ).map () -> # [^1]
|
|
||||||
if !@isLeaf
|
|
||||||
if @node.ignore == true || @node.ignore == 'true'
|
|
||||||
ignoreList.push @node
|
|
||||||
@delete()
|
|
||||||
else if (@node.private == true || @node.private == 'true') && !includePrivates
|
|
||||||
privateList.push @node
|
|
||||||
@delete()
|
|
||||||
if _.isArray(@node) # [^2]
|
|
||||||
@after () ->
|
|
||||||
@update _.compact this.node
|
|
||||||
return
|
|
||||||
return
|
|
||||||
|
|
||||||
scrubbed: scrubbed
|
|
||||||
ingoreList: ignoreList
|
|
||||||
privateList: privateList
|
|
||||||
|
|
||||||
module.exports = AbstractResume
|
|
||||||
|
|
||||||
|
|
||||||
# [^1]: As of v0.6.6, the NPM traverse library has a quirk when attempting
|
|
||||||
# to remove array elements directly using traverse's `this.remove`. See:
|
|
||||||
#
|
|
||||||
# https://github.com/substack/js-traverse/issues/48
|
|
||||||
#
|
|
||||||
# [^2]: The workaround is to use traverse's 'this.delete' to nullify the value
|
|
||||||
# first, followed by removal with something like _.compact.
|
|
||||||
#
|
|
||||||
# https://github.com/substack/js-traverse/issues/48#issuecomment-142607200
|
|
||||||
#
|
|
@ -18,7 +18,6 @@ MD = require 'marked'
|
|||||||
CONVERTER = require 'fresh-jrs-converter'
|
CONVERTER = require 'fresh-jrs-converter'
|
||||||
JRSResume = require './jrs-resume'
|
JRSResume = require './jrs-resume'
|
||||||
FluentDate = require './fluent-date'
|
FluentDate = require './fluent-date'
|
||||||
AbstractResume = require './abstract-resume'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -27,7 +26,7 @@ A FRESH resume or CV. FRESH resumes are backed by JSON, and each FreshResume
|
|||||||
object is an instantiation of that JSON decorated with utility methods.
|
object is an instantiation of that JSON decorated with utility methods.
|
||||||
@constructor
|
@constructor
|
||||||
###
|
###
|
||||||
class FreshResume extends AbstractResume
|
class FreshResume# extends AbstractResume
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -55,7 +54,8 @@ class FreshResume extends AbstractResume
|
|||||||
|
|
||||||
if opts and opts.privatize
|
if opts and opts.privatize
|
||||||
# Ignore any element with the 'ignore: true' or 'private: true' designator.
|
# Ignore any element with the 'ignore: true' or 'private: true' designator.
|
||||||
{ scrubbed, ignoreList, privateList } = @scrubResume rep, opts
|
scrubber = require '../utils/resume-scrubber'
|
||||||
|
{ scrubbed, ignoreList, privateList } = scrubber.scrubResume rep, opts
|
||||||
|
|
||||||
# Now apply the resume representation onto this object
|
# Now apply the resume representation onto this object
|
||||||
extend true, @, if opts and opts.privatize then scrubbed else rep
|
extend true, @, if opts and opts.privatize then scrubbed else rep
|
||||||
@ -299,7 +299,9 @@ class FreshResume extends AbstractResume
|
|||||||
|
|
||||||
|
|
||||||
duration: (unit) ->
|
duration: (unit) ->
|
||||||
super('employment.history', 'start', 'end', unit)
|
inspector = require '../inspectors/duration-inspector'
|
||||||
|
inspector.run @, 'employment.history', 'start', 'end', unit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ PATH = require('path')
|
|||||||
MD = require('marked')
|
MD = require('marked')
|
||||||
CONVERTER = require('fresh-jrs-converter')
|
CONVERTER = require('fresh-jrs-converter')
|
||||||
moment = require('moment')
|
moment = require('moment')
|
||||||
AbstractResume = require('./abstract-resume')
|
|
||||||
|
|
||||||
|
|
||||||
###*
|
###*
|
||||||
@ -22,7 +21,7 @@ A JRS resume or CV. JRS resumes are backed by JSON, and each JRSResume object
|
|||||||
is an instantiation of that JSON decorated with utility methods.
|
is an instantiation of that JSON decorated with utility methods.
|
||||||
@class JRSResume
|
@class JRSResume
|
||||||
###
|
###
|
||||||
class JRSResume extends AbstractResume
|
class JRSResume# extends AbstractResume
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -49,8 +48,9 @@ class JRSResume extends AbstractResume
|
|||||||
parseJSON: ( rep, opts ) ->
|
parseJSON: ( rep, opts ) ->
|
||||||
opts = opts || { };
|
opts = opts || { };
|
||||||
if opts.privatize
|
if opts.privatize
|
||||||
|
scrubber = require '../utils/resume-scrubber'
|
||||||
# Ignore any element with the 'ignore: true' or 'private: true' designator.
|
# Ignore any element with the 'ignore: true' or 'private: true' designator.
|
||||||
{ scrubbed, ignoreList, privateList } = @scrubResume rep, opts
|
{ scrubbed, ignoreList, privateList } = scrubber.scrubResume rep, opts
|
||||||
|
|
||||||
# Extend resume properties onto ourself.
|
# Extend resume properties onto ourself.
|
||||||
extend true, this, if opts.privatize then scrubbed else rep
|
extend true, this, if opts.privatize then scrubbed else rep
|
||||||
@ -188,7 +188,8 @@ class JRSResume extends AbstractResume
|
|||||||
|
|
||||||
|
|
||||||
duration: (unit) ->
|
duration: (unit) ->
|
||||||
super('work', 'startDate', 'endDate', unit)
|
inspector = require '../inspectors/duration-inspector';
|
||||||
|
inspector.run @, 'work', 'startDate', 'endDate', unit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
44
src/inspectors/duration-inspector.coffee
Normal file
44
src/inspectors/duration-inspector.coffee
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
FluentDate = require '../core/fluent-date'
|
||||||
|
_ = require 'underscore'
|
||||||
|
|
||||||
|
module.exports =
|
||||||
|
|
||||||
|
###*
|
||||||
|
Compute the total duration of the work history.
|
||||||
|
@returns The total duration of the sheet's work history, that is, the number
|
||||||
|
of years between the start date of the earliest job on the resume and the
|
||||||
|
*latest end date of all jobs in the work history*. This last condition is for
|
||||||
|
sheets that have overlapping jobs.
|
||||||
|
###
|
||||||
|
run: (rez, collKey, startKey, endKey, unit) ->
|
||||||
|
unit = unit || 'years'
|
||||||
|
hist = __.get rez, collKey
|
||||||
|
return 0 if !hist or !hist.length
|
||||||
|
|
||||||
|
# BEGIN CODE DUPLICATION --> src/inspectors/gap-inspector.coffee (TODO)
|
||||||
|
|
||||||
|
# Convert the candidate's employment history to an array of dates,
|
||||||
|
# where each element in the array is a start date or an end date of a
|
||||||
|
# job -- it doesn't matter which.
|
||||||
|
new_e = hist.map ( job ) ->
|
||||||
|
obj = _.pick( job, [startKey, endKey] )
|
||||||
|
# Synthesize an end date if this is a "current" gig
|
||||||
|
obj[endKey] = 'current' if !_.has obj, endKey
|
||||||
|
if obj && (obj[startKey] || obj[endKey])
|
||||||
|
obj = _.pairs obj
|
||||||
|
obj[0][1] = FluentDate.fmt( obj[0][1] )
|
||||||
|
if obj.length > 1
|
||||||
|
obj[1][1] = FluentDate.fmt( obj[1][1] )
|
||||||
|
obj
|
||||||
|
|
||||||
|
# Flatten the array, remove empties, and sort
|
||||||
|
new_e = _.filter _.flatten( new_e, true ), (v) ->
|
||||||
|
return v && v.length && v[0] && v[0].length
|
||||||
|
return 0 if !new_e or !new_e.length
|
||||||
|
new_e = _.sortBy new_e, ( elem ) -> return elem[1].unix()
|
||||||
|
|
||||||
|
# END CODE DUPLICATION
|
||||||
|
|
||||||
|
firstDate = _.first( new_e )[1];
|
||||||
|
lastDate = _.last( new_e )[1];
|
||||||
|
lastDate.diff firstDate, unit
|
47
src/utils/resume-scrubber.coffee
Normal file
47
src/utils/resume-scrubber.coffee
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
module.exports =
|
||||||
|
|
||||||
|
###*
|
||||||
|
Removes ignored or private fields from a resume object
|
||||||
|
@returns an object with the following structure:
|
||||||
|
{
|
||||||
|
scrubbed: the processed resume object
|
||||||
|
ignoreList: an array of ignored nodes that were removed
|
||||||
|
privateList: an array of private nodes that were removed
|
||||||
|
}
|
||||||
|
###
|
||||||
|
scrubResume: (rep, opts) ->
|
||||||
|
traverse = require 'traverse'
|
||||||
|
ignoreList = []
|
||||||
|
privateList = []
|
||||||
|
includePrivates = opts && opts.private
|
||||||
|
|
||||||
|
scrubbed = traverse( rep ).map () -> # [^1]
|
||||||
|
if !@isLeaf
|
||||||
|
if @node.ignore == true || @node.ignore == 'true'
|
||||||
|
ignoreList.push @node
|
||||||
|
@delete()
|
||||||
|
else if (@node.private == true || @node.private == 'true') && !includePrivates
|
||||||
|
privateList.push @node
|
||||||
|
@delete()
|
||||||
|
if _.isArray(@node) # [^2]
|
||||||
|
@after () ->
|
||||||
|
@update _.compact this.node
|
||||||
|
return
|
||||||
|
return
|
||||||
|
|
||||||
|
scrubbed: scrubbed
|
||||||
|
ingoreList: ignoreList
|
||||||
|
privateList: privateList
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [^1]: As of v0.6.6, the NPM traverse library has a quirk when attempting
|
||||||
|
# to remove array elements directly using traverse's `this.remove`. See:
|
||||||
|
#
|
||||||
|
# https://github.com/substack/js-traverse/issues/48
|
||||||
|
#
|
||||||
|
# [^2]: The workaround is to use traverse's 'this.delete' to nullify the value
|
||||||
|
# first, followed by removal with something like _.compact.
|
||||||
|
#
|
||||||
|
# https://github.com/substack/js-traverse/issues/48#issuecomment-142607200
|
||||||
|
#
|
Loading…
Reference in New Issue
Block a user