1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2024-12-23 05:37:23 +00:00

Improve conversions and tests.

This commit is contained in:
devlinjd 2015-12-12 10:48:26 -05:00
parent fe2247329e
commit b38a7c1da2
8 changed files with 300 additions and 33 deletions

View File

@ -55,10 +55,8 @@ FRESH to JSON Resume conversion routiens.
writing: writing( src.publications, true),
recognition: recognition( src.awards, true, foreign ),
social: social( src.basics.profiles, true ),
interests: src.interests,
references: src.references,
testimonials: references( src.references, true ),
languages: src.languages,
disposition: src.disposition // <--> round-trip
};
@ -101,7 +99,7 @@ FRESH to JSON Resume conversion routiens.
awards: recognition( src.recognition, false, foreign ),
publications: writing( src.writing, false ),
interests: src.interests,
references: src.references,
references: references( src.testimonials, false ),
samples: foreign ? src.samples : undefined,
disposition: foreign ? src.disposition : undefined,
languages: src.languages
@ -275,6 +273,27 @@ FRESH to JSON Resume conversion routiens.
}
}
function references( obj, direction ) {
if( direction ) {
return obj && obj.length && obj.map(function(ref){
return {
name: ref.name,
flavor: 'professional',
quote: ref.reference,
private: false
};
});
}
else {
return obj && obj.length && obj.map(function(ref){
return {
name: ref.name,
reference: ref.quote
};
});
}
}
function writing( obj, direction ) {
if( direction ) {
return obj.map(function( pub ) {
@ -292,7 +311,7 @@ FRESH to JSON Resume conversion routiens.
return obj && obj.length ? obj.map(function(pub){
return {
name: pub.title,
publisher: pub.publisher,
publisher: pub.publisher && pub.publisher.name ? pub.publisher.name : pub.publisher,
releaseDate: pub.date,
website: pub.url,
summary: pub.summary

View File

@ -66,7 +66,10 @@ FluentDate/*.prototype*/.fmt = function( dt ) {
}
}
else {
if( dt.isValid && dt.isValid() )
if( !dt ) {
return moment();
}
else if( dt.isValid && dt.isValid() )
return dt;
throw 'Unknown date object encountered.';
}

View File

@ -12,7 +12,8 @@ Definition of the FRESHResume class.
, PATH = require('path')
, moment = require('moment')
, MD = require('marked')
, CONVERTER = require('./convert');
, CONVERTER = require('./convert')
, JRSResume = require('./jrs-resume');
/**
A FRESH-style resume in JSON or YAML.
@ -46,13 +47,14 @@ Definition of the FRESHResume class.
Save the sheet to disk in a specific format, either FRESH or JSON Resume.
*/
FreshResume.prototype.saveAs = function( filename, format ) {
this.imp.fileName = filename || this.imp.fileName;
if( format !== 'JRS' ) {
this.imp.fileName = filename || this.imp.fileName;
FS.writeFileSync( this.imp.fileName, this.stringify(), 'utf8' );
}
else {
var newRep = CONVERTER.toJRS( this );
FS.writeFileSync( this.imp.fileName, FreshResume.stringify( newRep ), 'utf8' );
FS.writeFileSync( filename, JRSResume.stringify( newRep ), 'utf8' );
}
return this;
};

View File

@ -30,17 +30,22 @@ Definition of the JRSResume class.
consistent format. Then sort each section by startDate descending.
*/
JRSResume.prototype.open = function( file, title ) {
this.imp = { fileName: file };
this.imp.raw = FS.readFileSync( file, 'utf8' );
return this.parse( this.imp.raw, title );
//this.imp = { fileName: file }; <-- schema violation, tuck it into .basics instead
this.basics = {
imp: {
fileName: file,
raw: FS.readFileSync( file, 'utf8' )
}
};
return this.parse( this.basics.imp.raw, title );
};
/**
Save the sheet to disk (for environments that have disk access).
*/
JRSResume.prototype.save = function( filename ) {
this.imp.fileName = filename || this.imp.fileName;
FS.writeFileSync( this.imp.fileName, this.stringify(), 'utf8' );
this.basics.imp.fileName = filename || this.basics.imp.fileName;
FS.writeFileSync( this.basics.imp.fileName, this.stringify( this ), 'utf8' );
return this;
};
@ -48,7 +53,7 @@ Definition of the JRSResume class.
Convert this object to a JSON string, sanitizing meta-properties along the
way. Don't override .toString().
*/
JRSResume.prototype.stringify = function() {
JRSResume.stringify = function( obj ) {
function replacer( key,value ) { // Exclude these keys from stringification
return _.some(['imp', 'warnings', 'computed', 'filt', 'ctrl', 'index',
'safeStartDate', 'safeEndDate', 'safeDate', 'safeReleaseDate', 'result',
@ -56,7 +61,11 @@ Definition of the JRSResume class.
function( val ) { return key.trim() === val; }
) ? undefined : value;
}
return JSON.stringify( this, replacer, 2 );
return JSON.stringify( obj, replacer, 2 );
};
JRSResume.prototype.stringify = function() {
return JRSResume.stringify( this );
};
/**
@ -67,16 +76,17 @@ Definition of the JRSResume class.
JRSResume.prototype.parse = function( stringData, opts ) {
opts = opts || { };
var rep = JSON.parse( stringData );
extend( true, this, rep );
// Set up metadata
if( opts.imp === undefined || opts.imp ) {
this.imp = this.imp || { };
this.imp.title = (opts.title || this.imp.title) || this.basics.name;
this.basics.imp = this.basics.imp || { };
this.basics.imp.title = (opts.title || this.basics.imp.title) || this.basics.name;
}
// Parse dates, sort dates, and calculate computed values
(opts.date === undefined || opts.date) && _parseDates.call( this );
(opts.sort === undefined || opts.sort) && this.sort();
(opts.compute === undefined || opts.compute) && (this.computed = {
(opts.compute === undefined || opts.compute) && (this.basics.computed = {
numYears: this.duration(),
keywords: this.keywords()
});
@ -111,7 +121,7 @@ Definition of the JRSResume class.
JRSResume.prototype.clear = function( clearMeta ) {
clearMeta = ((clearMeta === undefined) && true) || clearMeta;
clearMeta && (delete this.imp);
delete this.computed; // Don't use Object.keys() here
delete this.basics.computed; // Don't use Object.keys() here
delete this.work;
delete this.volunteer;
delete this.education;
@ -169,8 +179,15 @@ Definition of the JRSResume class.
var schema = FS.readFileSync( PATH.join( __dirname, 'resume.json' ), 'utf8' );
var schemaObj = JSON.parse( schema );
var validator = require('is-my-json-valid');
var validate = validator( schemaObj );
return validate( this );
var validate = validator( schemaObj, { // Note [1]
formats: { date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ }
});
var ret = validate( this );
if( !ret ) {
this.basics.imp = this.basics.imp || { };
this.basics.imp.validationErrors = validate.errors;
}
return ret;
};
/**

View File

@ -0,0 +1,224 @@
{
"basics": {
"name": "Jane Doe",
"label": "Senior Developer / Code Ninja",
"summary": "**Full-stack software developer with 6+ years industry experience** specializing in scalable cloud architectures for this, that, and the other. A native of southern CA, Jane enjoys hiking, mystery novels, and the company of Rufus, her two-year-old beagle.",
"website": "http://jane-doe.me",
"phone": "1-650-999-7777",
"email": "jdoe@onecoolstartup.io",
"picture": "jane_doe.png",
"location": {
"address": "Jane Doe\n123 Somewhere Rd.\nMountain View, CA 94035",
"postalCode": "94035",
"city": "Mountain View",
"countryCode": "US",
"region": "CA"
},
"profiles": [
{
"network": "GitHub",
"username": "jane-doe-was-here",
"url": "https://github.com/jane-doe-was-here"
},
{
"network": "Twitter",
"username": "jane-doe-was-here",
"url": "https://twitter.com/jane-doe-was-here"
}
]
},
"work": [
{
"company": "One Cool Startup",
"website": "https://onecool.io/does-not-exist",
"position": "Head Code Ninja",
"startDate": "2013-09",
"summary": "Development team manager for OneCoolApp and OneCoolWebsite, a free social network tiddlywink generator and lifestyle portal with over 200,000 users.",
"highlights": [
"Managed a 5-person development team",
"Accomplishment 2",
"Etc."
]
},
{
"company": "Veridian Dynamics",
"website": "https://en.wikipedia.org/wiki/Better_Off_Ted#Plot",
"position": "Principal Developer",
"startDate": "2011-07",
"endDate": "2013-08",
"summary": "Developer on numerous projects culminating in technical lead role for the [Jabberwocky project](http://betteroffted.wikia.com/wiki/Jabberwocky) and promotion to principal developer.",
"highlights": [
"Managed a 5-person development team",
"Accomplishment 2",
"Etc."
]
},
{
"company": "Stark Industries",
"position": "IT Administrator",
"startDate": "2008-10",
"endDate": "2011-06",
"summary": "Junior programmer with heavy code responsibilities. Promoted to intermediate role after 6 months.",
"highlights": [
"Promoted to intermediate developer after 6 months",
"Accomplishment 2",
"Etc."
]
},
{
"company": "Dunder Mifflin",
"position": "Intern",
"startDate": "2008-06",
"endDate": "2008-09",
"summary": "Performed IT administration and deployments for Dunder Mifflin.",
"highlights": [
"Supervised roll-out of Dunder Mifflin Infinity website.",
"Performed mission-critical system backups and ",
"Etc."
]
}
],
"education": [
{
"institution": "Cornell University",
"gpa": "3.5",
"courses": [
"Course 1",
"Course 2",
"Course 2"
],
"startDate": "2005-09",
"endDate": "2008-05"
},
{
"institution": "Medfield College",
"gpa": "3.2",
"courses": [
"Course 1",
"Course 2",
"Course 2"
],
"startDate": "2003-09",
"endDate": "2005-06"
}
],
"skills": [
{
"name": "Programming",
"keywords": [
"C++",
"Ruby",
"Xcode"
]
},
{
"name": "Project Management",
"keywords": [
"Agile"
]
}
],
"volunteer": [
{
"organization": "Technology for Tots",
"position": "Technical Consultant",
"startDate": "2003-11",
"endDate": "2005-06",
"website": "http://technology-for-tots.org",
"summary": "Summary of this volunteer stint.",
"highlights": [
"Accomplishment 1",
"Accomplishment 2",
"etc"
]
},
{
"organization": "US Army Reserves",
"position": "NCO",
"startDate": "1999-11",
"endDate": "2003-06",
"website": "http://www.usar.army.mil/",
"summary": "Summary of this military stint.",
"highlights": [
"Accomplishment 1",
"Accomplishment 2",
"etc"
]
}
],
"awards": [
{
"title": "Honorable Mention",
"date": "2012",
"awarder": "Google"
},
{
"title": "Summa cum laude",
"date": "2012",
"awarder": "Cornell University"
}
],
"publications": [
{
"name": "Building User Interfaces with Electron and Atom",
"publisher": "Code Project",
"releaseDate": "2011",
"website": "http://codeproject.com/build-ui-electron-atom.aspx"
},
{
"name": "Jane Doe Unplugged",
"publisher": "self",
"releaseDate": "2011",
"website": "http://jane-doe.me"
},
{
"name": "Teach Yourself GORFF in 21 Days",
"publisher": "Amazon",
"releaseDate": "2008",
"website": "http://url.to.publication.com/blah",
"summary": "A primer on the programming language of GORFF, whose for loops are coterminous with all of time and space."
}
],
"interests": [
{
"name": "reading",
"summary": "Jane is a fan of mystery novels and courtroom dramas including Agatha Christie and John Grisham.",
"keywords": [
"mystery",
"Agatha Christie",
"John Grisham"
]
},
{
"name": "hiking",
"summary": "Jane enjoys hiking, light mountain climbing, and has four summits under her belt!"
},
{
"name": "yoga"
}
],
"references": [
{
"name": "John Davidson",
"reference": "Jane is awesome! I'd hire her again in a heartbeat."
},
{
"name": "Elias Fullstacker",
"reference": "I worked with Jane on Jabberwocky and can vouch for her awesome technical capabilities and attention to detail. Insta-hire."
},
{
"name": "Dana Nevins",
"reference": "I've known Jane personally and professionally for almost ten years. She is one in a million."
}
],
"languages": [
{
"language": "English",
"level": "Native"
},
{
"language": "Spanish",
"level": "Moderate"
}
]
}

View File

@ -17,7 +17,7 @@ describe('FRESH/JRS converter', function () {
it('should round-trip from JRS to FRESH to JRS without modifying or losing data', function () {
var fileA = path.join( __dirname, 'jrs-exemplar/richard-hendriks.json' );
var fileA = path.join( __dirname, 'resumes/jrs/richard-hendriks.json' );
var fileB = path.join( __dirname, 'sandbox/richard-hendriks.json' );
_sheet = new FRESHResume().open( fileA );

View File

@ -9,13 +9,14 @@ var chai = require('chai')
chai.config.includeStack = false;
describe('fullstack.json (JRS)', function () {
describe('jane-doe.json (JRS)', function () {
var _sheet;
it('should open without throwing an exception', function () {
function tryOpen() {
_sheet = new JRSResume().open( 'node_modules/resample/fullstack/in/resume.json' );
_sheet = new JRSResume().open(
path.join( __dirname, 'resumes/jrs/jane-doe.json' ) );
}
tryOpen.should.not.Throw();
});
@ -32,28 +33,29 @@ describe('fullstack.json (JRS)', function () {
).to.equal( true );
});
it('should have a work duration of 11 years', function() {
_sheet.computed.numYears.should.equal( 11 );
it('should have a work duration of 7 years', function() {
_sheet.basics.computed.numYears.should.equal( 7 );
});
it('should save without throwing an exception', function(){
function trySave() {
_sheet.save( 'tests/sandbox/fullstack.json' );
_sheet.save( 'tests/sandbox/jane-doe.json' );
}
trySave.should.not.Throw();
});
it('should not be modified after saving', function() {
var savedSheet = new JRSResume().open( 'tests/sandbox/fullstack.json' );
var savedSheet = new JRSResume().open( 'tests/sandbox/jane-doe.json' );
_sheet.stringify().should.equal( savedSheet.stringify() )
});
it('should validate against the JSON Resume schema', function() {
var schemaJson = require('../src/core/resume.json');
var validate = validator( schemaJson, { verbose: true } );
var result = validate( JSON.parse( _sheet.imp.raw ) );
var result = _sheet.isValid();
// var schemaJson = require('../src/core/resume.json');
// var validate = validator( schemaJson, { verbose: true } );
// var result = validate( JSON.parse( _sheet.imp.raw ) );
result || console.log("\n\nOops, resume didn't validate. " +
"Validation errors:\n\n", validate.errors, "\n\n");
"Validation errors:\n\n", _sheet.basics.imp.validationErrors, "\n\n");
result.should.equal( true );
});