From 8dca5b76e7fe6df1b36d0d37f10465f7d7b521b5 Mon Sep 17 00:00:00 2001 From: hacksalot Date: Sun, 4 Feb 2018 22:49:58 -0500 Subject: [PATCH] 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. --- dist/core/abstract-resume.js | 113 ----------------------- dist/core/fresh-resume.js | 25 ++--- dist/core/jrs-resume.js | 25 ++--- dist/inspectors/duration-inspector.js | 56 +++++++++++ dist/utils/resume-scrubber.js | 45 +++++++++ src/core/abstract-resume.coffee | 98 -------------------- src/core/fresh-resume.coffee | 10 +- src/core/jrs-resume.coffee | 9 +- src/inspectors/duration-inspector.coffee | 44 +++++++++ src/utils/resume-scrubber.coffee | 47 ++++++++++ 10 files changed, 223 insertions(+), 249 deletions(-) delete mode 100644 dist/core/abstract-resume.js create mode 100644 dist/inspectors/duration-inspector.js create mode 100644 dist/utils/resume-scrubber.js delete mode 100644 src/core/abstract-resume.coffee create mode 100644 src/inspectors/duration-inspector.coffee create mode 100644 src/utils/resume-scrubber.coffee diff --git a/dist/core/abstract-resume.js b/dist/core/abstract-resume.js deleted file mode 100644 index ce0e81e..0000000 --- a/dist/core/abstract-resume.js +++ /dev/null @@ -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 diff --git a/dist/core/fresh-resume.js b/dist/core/fresh-resume.js index c256e63..344c421 100644 --- a/dist/core/fresh-resume.js +++ b/dist/core/fresh-resume.js @@ -6,9 +6,7 @@ Definition of the FRESHResume class. */ (function() { - var AbstractResume, 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; + var CONVERTER, FS, FluentDate, FreshResume, JRSResume, MD, PATH, XML, _, __, _parseDates, extend, moment, validator; FS = require('fs'); @@ -34,8 +32,6 @@ Definition of the FRESHResume class. FluentDate = require('./fluent-date'); - AbstractResume = require('./abstract-resume'); - /** A FRESH resume or CV. FRESH resumes are backed by JSON, and each FreshResume @@ -43,12 +39,8 @@ Definition of the FRESHResume class. @constructor */ - FreshResume = (function(superClass) { - extend1(FreshResume, superClass); - - function FreshResume() { - return FreshResume.__super__.constructor.apply(this, arguments); - } + FreshResume = (function() { + function FreshResume() {} /** Initialize the the FreshResume from JSON string data. */ @@ -77,9 +69,10 @@ Definition of the FRESHResume class. */ FreshResume.prototype.parseJSON = function(rep, opts) { - var ignoreList, privateList, ref, ref1, scrubbed; + var ignoreList, privateList, ref, ref1, scrubbed, scrubber; 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); if (!((ref1 = this.imp) != null ? ref1.processed : void 0)) { @@ -368,7 +361,9 @@ Definition of the FRESHResume class. }; 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; - })(AbstractResume); + })(); /** diff --git a/dist/core/jrs-resume.js b/dist/core/jrs-resume.js index be078ad..69f7396 100644 --- a/dist/core/jrs-resume.js +++ b/dist/core/jrs-resume.js @@ -6,9 +6,7 @@ Definition of the JRSResume class. */ (function() { - var AbstractResume, 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; + var CONVERTER, FS, JRSResume, MD, PATH, _, _parseDates, extend, moment, validator; FS = require('fs'); @@ -26,8 +24,6 @@ Definition of the JRSResume class. moment = require('moment'); - AbstractResume = require('./abstract-resume'); - /** 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 */ - JRSResume = (function(superClass) { + JRSResume = (function() { var clear; - extend1(JRSResume, superClass); - - function JRSResume() { - return JRSResume.__super__.constructor.apply(this, arguments); - } + function JRSResume() {} /** Initialize the the JSResume from string. */ @@ -71,10 +63,11 @@ Definition of the JRSResume class. */ JRSResume.prototype.parseJSON = function(rep, opts) { - var ignoreList, privateList, ref, ref1, scrubbed; + var ignoreList, privateList, ref, ref1, scrubbed, scrubber; opts = opts || {}; 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); if (!((ref1 = this.imp) != null ? ref1.processed : void 0)) { @@ -239,7 +232,9 @@ Definition of the JRSResume class. }; 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; - })(AbstractResume); + })(); /** Get the default (empty) sheet. */ diff --git a/dist/inspectors/duration-inspector.js b/dist/inspectors/duration-inspector.js new file mode 100644 index 0000000..5b048a2 --- /dev/null +++ b/dist/inspectors/duration-inspector.js @@ -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 diff --git a/dist/utils/resume-scrubber.js b/dist/utils/resume-scrubber.js new file mode 100644 index 0000000..93bc636 --- /dev/null +++ b/dist/utils/resume-scrubber.js @@ -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 diff --git a/src/core/abstract-resume.coffee b/src/core/abstract-resume.coffee deleted file mode 100644 index 13ce00c..0000000 --- a/src/core/abstract-resume.coffee +++ /dev/null @@ -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 -# diff --git a/src/core/fresh-resume.coffee b/src/core/fresh-resume.coffee index 8a7e825..f24a073 100644 --- a/src/core/fresh-resume.coffee +++ b/src/core/fresh-resume.coffee @@ -18,7 +18,6 @@ MD = require 'marked' CONVERTER = require 'fresh-jrs-converter' JRSResume = require './jrs-resume' 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. @constructor ### -class FreshResume extends AbstractResume +class FreshResume# extends AbstractResume @@ -55,7 +54,8 @@ class FreshResume extends AbstractResume if opts and opts.privatize # 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 extend true, @, if opts and opts.privatize then scrubbed else rep @@ -299,7 +299,9 @@ class FreshResume extends AbstractResume duration: (unit) -> - super('employment.history', 'start', 'end', unit) + inspector = require '../inspectors/duration-inspector' + inspector.run @, 'employment.history', 'start', 'end', unit + diff --git a/src/core/jrs-resume.coffee b/src/core/jrs-resume.coffee index e7b2835..2834625 100644 --- a/src/core/jrs-resume.coffee +++ b/src/core/jrs-resume.coffee @@ -14,7 +14,6 @@ PATH = require('path') MD = require('marked') CONVERTER = require('fresh-jrs-converter') 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. @class JRSResume ### -class JRSResume extends AbstractResume +class JRSResume# extends AbstractResume @@ -49,8 +48,9 @@ class JRSResume extends AbstractResume parseJSON: ( rep, opts ) -> opts = opts || { }; if opts.privatize + scrubber = require '../utils/resume-scrubber' # 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 true, this, if opts.privatize then scrubbed else rep @@ -188,7 +188,8 @@ class JRSResume extends AbstractResume duration: (unit) -> - super('work', 'startDate', 'endDate', unit) + inspector = require '../inspectors/duration-inspector'; + inspector.run @, 'work', 'startDate', 'endDate', unit diff --git a/src/inspectors/duration-inspector.coffee b/src/inspectors/duration-inspector.coffee new file mode 100644 index 0000000..a93e78b --- /dev/null +++ b/src/inspectors/duration-inspector.coffee @@ -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 diff --git a/src/utils/resume-scrubber.coffee b/src/utils/resume-scrubber.coffee new file mode 100644 index 0000000..ff54411 --- /dev/null +++ b/src/utils/resume-scrubber.coffee @@ -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 +#