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:
parent
fe2247329e
commit
b38a7c1da2
@ -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
|
||||
|
@ -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.';
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
224
tests/resumes/jrs/jane-doe.json
Normal file
224
tests/resumes/jrs/jane-doe.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
@ -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 );
|
||||
|
@ -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 );
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user