1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2024-11-05 01:56:21 +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:
hacksalot 2018-02-04 22:49:58 -05:00
parent 2767b16b47
commit 8dca5b76e7
No known key found for this signature in database
GPG Key ID: 2F343EC247CA4B06
10 changed files with 223 additions and 249 deletions

View File

@ -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

View File

@ -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); })();
/** /**

View File

@ -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
View 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
View 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

View File

@ -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
#

View File

@ -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

View File

@ -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

View 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

View 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
#