1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2024-11-22 08:20:11 +00:00

Improve duration calcs, intro base resume class.

This commit is contained in:
hacksalot 2016-01-30 16:40:22 -05:00
parent 8ec6b5ed6a
commit 8e806dc04f
8 changed files with 191 additions and 117 deletions

71
dist/core/abstract-resume.js vendored Normal file
View File

@ -0,0 +1,71 @@
/**
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 = 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);
};
return AbstractResume;
})();
module.exports = AbstractResume;
}).call(this);

View File

@ -10,6 +10,8 @@ The HackMyResume date representation.
moment = require('moment'); moment = require('moment');
require('../utils/string');
/** /**
Create a FluentDate from a string or Moment date object. There are a few date Create a FluentDate from a string or Moment date object. There are a few date
@ -33,6 +35,10 @@ The HackMyResume date representation.
this.rep = this.fmt(dt); this.rep = this.fmt(dt);
} }
FluentDate.isCurrent = function(dt) {
return !dt || (String.is(dt) && /^(present|now|current)$/.test(dt));
};
return FluentDate; return FluentDate;
})(); })();

View File

@ -6,7 +6,9 @@ Definition of the FRESHResume class.
*/ */
(function() { (function() {
var CONVERTER, FS, FreshResume, JRSResume, MD, PATH, XML, _, __, _parseDates, extend, moment, validator; 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;
FS = require('fs'); FS = require('fs');
@ -30,6 +32,10 @@ Definition of the FRESHResume class.
JRSResume = require('./jrs-resume'); JRSResume = require('./jrs-resume');
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
@ -37,8 +43,12 @@ Definition of the FRESHResume class.
@constructor @constructor
*/ */
FreshResume = (function() { FreshResume = (function(superClass) {
function FreshResume() {} extend1(FreshResume, superClass);
function FreshResume() {
return FreshResume.__super__.constructor.apply(this, arguments);
}
/** Initialize the FreshResume from file. */ /** Initialize the FreshResume from file. */
@ -376,36 +386,8 @@ Definition of the FRESHResume class.
return ret; return ret;
}; };
/**
Calculate the total duration of the sheet. Assumes this.work has been sorted
by start date descending, perhaps via a call to Sheet.sort().
@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.
*/
FreshResume.prototype.duration = function(unit) { FreshResume.prototype.duration = function(unit) {
var careerLast, careerStart, empHist, firstJob; return FreshResume.__super__.duration.call(this, 'employment.history', 'start', 'end', unit);
unit = unit || 'years';
empHist = __.get(this, 'employment.history');
if (empHist && empHist.length) {
firstJob = _.last(empHist);
careerStart = firstJob.start ? firstJob.safe.start : '';
if ((typeof careerStart === 'string' || careerStart instanceof String) && !careerStart.trim()) {
return 0;
}
careerLast = _.max(empHist, function(w) {
if (w.safe && w.safe.end) {
return w.safe.end.unix();
} else {
return moment().unix();
}
});
return careerLast.safe.end.diff(careerStart, unit);
}
return 0;
}; };
@ -420,7 +402,11 @@ Definition of the FRESHResume class.
if (a.safe.start.isBefore(b.safe.start)) { if (a.safe.start.isBefore(b.safe.start)) {
return 1; return 1;
} else { } else {
return (a.safe.start.isAfter(b.safe.start) && -1) || 0; if (a.safe.start.isAfter(b.safe.start)) {
return -1;
} else {
return 0;
}
} }
}; };
sortSection = function(key) { sortSection = function(key) {
@ -448,7 +434,7 @@ Definition of the FRESHResume class.
return FreshResume; return FreshResume;
})(); })(AbstractResume);
/** /**
@ -499,7 +485,7 @@ Definition of the FRESHResume class.
return; return;
} }
if (Object.prototype.toString.call(obj) === '[object Array]') { if (Object.prototype.toString.call(obj) === '[object Array]') {
return obj.forEach(function(elem) { obj.forEach(function(elem) {
return replaceDatesInObject(elem); return replaceDatesInObject(elem);
}); });
} else if (typeof obj === 'object') { } else if (typeof obj === 'object') {
@ -509,19 +495,19 @@ Definition of the FRESHResume class.
Object.keys(obj).forEach(function(key) { Object.keys(obj).forEach(function(key) {
return replaceDatesInObject(obj[key]); return replaceDatesInObject(obj[key]);
}); });
return ['start', 'end', 'date'].forEach(function(val) { ['start', 'end', 'date'].forEach(function(val) {
if ((obj[val] !== void 0) && (!obj.safe || !obj.safe[val])) { if ((obj[val] !== void 0) && (!obj.safe || !obj.safe[val])) {
obj.safe = obj.safe || {}; obj.safe = obj.safe || {};
obj.safe[val] = _fmt(obj[val]); obj.safe[val] = _fmt(obj[val]);
if (obj[val] && (val === 'start') && !obj.end) { if (obj[val] && (val === 'start') && !obj.end) {
return obj.safe.end = _fmt('current'); obj.safe.end = _fmt('current');
} }
} }
}); });
} }
}; };
return Object.keys(this).forEach(function(member) { Object.keys(this).forEach(function(member) {
return replaceDatesInObject(that[member]); replaceDatesInObject(that[member]);
}); });
}; };

View File

@ -6,7 +6,9 @@ Definition of the JRSResume class.
*/ */
(function() { (function() {
var CONVERTER, FS, JRSResume, MD, PATH, _, _parseDates, extend, moment, validator; 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;
FS = require('fs'); FS = require('fs');
@ -24,6 +26,8 @@ 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
@ -31,10 +35,14 @@ Definition of the JRSResume class.
@class JRSResume @class JRSResume
*/ */
JRSResume = (function() { JRSResume = (function(superClass) {
var clear, format; var clear, format;
function JRSResume() {} extend1(JRSResume, superClass);
function JRSResume() {
return JRSResume.__super__.constructor.apply(this, arguments);
}
/** Initialize the JSResume from file. */ /** Initialize the JSResume from file. */
@ -249,30 +257,8 @@ Definition of the JRSResume class.
return ret; return ret;
}; };
/**
Calculate the total duration of the sheet. Assumes this.work has been sorted
by start date descending, perhaps via a call to Sheet.sort().
@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.
*/
JRSResume.prototype.duration = function(unit) { JRSResume.prototype.duration = function(unit) {
var careerLast, careerStart; return JRSResume.__super__.duration.call(this, 'work', 'startDate', 'endDate', unit);
unit = unit || 'years';
if (this.work && this.work.length) {
careerStart = this.work[this.work.length - 1].safeStartDate;
if ((typeof careerStart === 'string' || careerStart instanceof String) && !careerStart.trim()) {
return 0;
}
careerLast = _.max(this.work, function(w) {
return w.safeEndDate.unix();
}).safeEndDate;
return careerLast.diff(careerStart, unit);
}
return 0;
}; };
@ -372,7 +358,7 @@ Definition of the JRSResume class.
return JRSResume; return JRSResume;
})(); })(AbstractResume);
/** Get the default (empty) sheet. */ /** Get the default (empty) sheet. */

View File

@ -0,0 +1,56 @@
###*
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 = hist || __.get(this, 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] )
return 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
module.exports = AbstractResume

View File

@ -7,6 +7,7 @@ The HackMyResume date representation.
moment = require 'moment' moment = require 'moment'
require('../utils/string')
###* ###*
Create a FluentDate from a string or Moment date object. There are a few date Create a FluentDate from a string or Moment date object. There are a few date
@ -30,6 +31,8 @@ class FluentDate
constructor: (dt) -> constructor: (dt) ->
@rep = this.fmt dt @rep = this.fmt dt
@isCurrent: (dt) ->
!dt || (String.is(dt) and /^(present|now|current)$/.test(dt))
months = {} months = {}
abbr = {} abbr = {}

View File

@ -17,6 +17,8 @@ XML = require 'xml-escape'
MD = require 'marked' 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'
AbstractResume = require './abstract-resume'
@ -25,7 +27,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 class FreshResume extends AbstractResume
###* Initialize the FreshResume from file. ### ###* Initialize the FreshResume from file. ###
open: ( file, opts ) -> open: ( file, opts ) ->
@ -306,28 +308,8 @@ class FreshResume
ret ret
###*
Calculate the total duration of the sheet. Assumes this.work has been sorted
by start date descending, perhaps via a call to Sheet.sort().
@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: (unit) -> duration: (unit) ->
unit = unit || 'years' super('employment.history', 'start', 'end', unit)
empHist = __.get(this, 'employment.history')
if empHist && empHist.length
firstJob = _.last( empHist )
careerStart = if firstJob.start then firstJob.safe.start else ''
if ((typeof careerStart == 'string' || careerStart instanceof String) && !careerStart.trim())
return 0
careerLast = _.max empHist, ( w ) ->
return if w.safe && w.safe.end then w.safe.end.unix() else moment().unix()
return careerLast.safe.end.diff careerStart, unit
0
###* ###*
@ -337,9 +319,9 @@ class FreshResume
sort: () -> sort: () ->
byDateDesc = (a,b) -> byDateDesc = (a,b) ->
if ( a.safe.start.isBefore(b.safe.start) ) if a.safe.start.isBefore(b.safe.start)
then 1 then 1
else ( a.safe.start.isAfter(b.safe.start) && -1 ) || 0 else ( if a.safe.start.isAfter(b.safe.start) then -1 else 0 )
sortSection = ( key ) -> sortSection = ( key ) ->
ar = __.get this, key ar = __.get this, key
@ -352,10 +334,6 @@ class FreshResume
sortSection 'service.history' sortSection 'service.history'
sortSection 'projects' sortSection 'projects'
# this.awards && this.awards.sort( function(a, b) {
# return( a.safeDate.isBefore(b.safeDate) ) ? 1
# : ( a.safeDate.isAfter(b.safeDate) && -1 ) || 0;
# });
@writing && @writing.sort (a, b) -> @writing && @writing.sort (a, b) ->
if a.safe.date.isBefore b.safe.date if a.safe.date.isBefore b.safe.date
then 1 then 1
@ -400,6 +378,7 @@ _parseDates = () ->
return if !obj return if !obj
if Object.prototype.toString.call( obj ) == '[object Array]' if Object.prototype.toString.call( obj ) == '[object Array]'
obj.forEach (elem) -> replaceDatesInObject( elem ) obj.forEach (elem) -> replaceDatesInObject( elem )
return
else if typeof obj == 'object' else if typeof obj == 'object'
if obj._isAMomentObject || obj.safe if obj._isAMomentObject || obj.safe
return return
@ -410,8 +389,12 @@ _parseDates = () ->
obj.safe[ val ] = _fmt obj[val] obj.safe[ val ] = _fmt obj[val]
if obj[val] && (val == 'start') && !obj.end if obj[val] && (val == 'start') && !obj.end
obj.safe.end = _fmt 'current' obj.safe.end = _fmt 'current'
return
Object.keys( this ).forEach (member) -> replaceDatesInObject(that[member]) return
Object.keys( this ).forEach (member) ->
replaceDatesInObject(that[member])
return
return

View File

@ -14,7 +14,7 @@ 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 +22,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 class JRSResume extends AbstractResume
@ -203,25 +203,8 @@ class JRSResume
ret ret
duration: (unit) ->
###* super('work', 'startDate', 'endDate', unit)
Calculate the total duration of the sheet. Assumes this.work has been sorted
by start date descending, perhaps via a call to Sheet.sort().
@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: ( unit ) ->
unit = unit || 'years';
if this.work && this.work.length
careerStart = this.work[ this.work.length - 1].safeStartDate
if (typeof careerStart == 'string' || careerStart instanceof String) && !careerStart.trim()
return 0
careerLast = _.max( this.work, ( w ) -> w.safeEndDate.unix() ).safeEndDate;
return careerLast.diff careerStart, unit
0
###* ###*