From 4c5ccc001afbc5d9253740850ebe23789730c6da Mon Sep 17 00:00:00 2001 From: hacksalot Date: Fri, 15 Jan 2016 13:08:01 -0500 Subject: [PATCH] Introduce PEEK command. Peek at arbitrary resumes and resume objects paths with "hackmyresume peek [objectPath]". For ex: hackmyresume PEEK resume.json hackmyresume PEEK resume.json info hackmyresume PEEK resume.json employment[2].keywords hackmyresume PEEK r1.json r2.json r3.json info.brief --- src/cli/error.js | 3 +- src/cli/main.js | 13 ++++++-- src/cli/out.js | 14 ++++++++ src/core/event-codes.js | 4 ++- src/hackmyapi.js | 3 +- src/utils/safe-json-loader.js | 35 ++++++++++++++++--- src/verbs/peek.js | 63 +++++++++++++++++++++++++++++++++++ 7 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 src/verbs/peek.js diff --git a/src/cli/error.js b/src/cli/error.js index 34dd9c7..4f00a86 100644 --- a/src/cli/error.js +++ b/src/cli/error.js @@ -16,6 +16,7 @@ Error-handling routines for HackMyResume. , FCMD = require('../hackmyapi') , PATH = require('path') , WRAP = require('word-wrap') + , M2C = require('../utils/md2chalk.js') , chalk = require('chalk') , SyntaxErrorEx = require('../utils/syntax-error-ex'); require('string.prototype.startswith'); @@ -182,7 +183,7 @@ Error-handling routines for HackMyResume. ' column ' + se.col + '.'; } else { - msg = formatError( ex.inner.toString() ); + msg = ex; } warn = false; break; diff --git a/src/cli/main.js b/src/cli/main.js index 3c199cf..2a71b00 100644 --- a/src/cli/main.js +++ b/src/cli/main.js @@ -22,7 +22,6 @@ Definition of the `main` function. , StringUtils = require('../utils/string.js') , _ = require('underscore') , OUTPUT = require('./out') - , SAFELOADJSON = require('../utils/safe-json-loader') , PAD = require('string-padding') , Command = require('commander').Command; @@ -93,6 +92,15 @@ Definition of the `main` function. execute.call( this, sources, [], this.opts(), logMsg); }); + // Create the PEEK command + program + .command('peek') + .arguments('') + .description('Peek at a resume field or section') + .action(function( sources, sectionOrField ) { + execute.call( this, sources, [ sources.pop() ], this.opts(), logMsg); + }); + // Create the BUILD command program .command('build') @@ -189,7 +197,8 @@ Definition of the `main` function. if( optStr[0] === '{') oJSON = eval('(' + optStr + ')'); // jshint ignore:line else { - oJSON = SAFELOADJSON( optStr ); + oJSON = safeLoadJSON( optStr ); + // TODO: Error handling } } } diff --git a/src/cli/out.js b/src/cli/out.js index 06d604b..0279230 100644 --- a/src/cli/out.js +++ b/src/cli/out.js @@ -189,6 +189,20 @@ Output routines for HackMyResume. break; + case HME.beforePeek: + if( evt.target ) + L(M2C('Peeking at **%s** in **%s**...', 'cyan'), evt.target, evt.file); + else + L(M2C('Peeking at **%s**...', 'cyan'), evt.file); + break; + + case HME.afterPeek: + if( evt.target ) + console.dir( evt.target, { depth: null, colors: true } ); + else + L(M2C('The specified key **%s** was not found in **%s**.', 'yellow'), evt.requested, evt.file); + break; + } } diff --git a/src/core/event-codes.js b/src/core/event-codes.js index 0486c6b..a85047a 100644 --- a/src/core/event-codes.js +++ b/src/core/event-codes.js @@ -32,7 +32,9 @@ Event code definitions. afterConvert: 16, verifyOutputs: 17, beforeParse: 18, - afterParse: 19 + afterParse: 19, + beforePeek: 20, + afterPeek: 21 }; diff --git a/src/hackmyapi.js b/src/hackmyapi.js index 000c023..3cb778f 100644 --- a/src/hackmyapi.js +++ b/src/hackmyapi.js @@ -19,7 +19,8 @@ External API surface for HackMyResume. analyze: require('./verbs/analyze'), validate: require('./verbs/validate'), convert: require('./verbs/convert'), - new: require('./verbs/create') + new: require('./verbs/create'), + peek: require('./verbs/peek') }, alias: { generate: require('./verbs/build'), diff --git a/src/utils/safe-json-loader.js b/src/utils/safe-json-loader.js index 0744b3c..e393186 100644 --- a/src/utils/safe-json-loader.js +++ b/src/utils/safe-json-loader.js @@ -8,16 +8,41 @@ Definition of the SafeJsonLoader class. (function() { - var FS = require('fs'); + + + var FS = require('fs') + , HMSTATUS = require('../core/status-codes') + , SyntaxErrorEx = require('./syntax-error-ex'); + + module.exports = function loadSafeJson( file ) { + + var ret = { }; try { - return JSON.parse( FS.readFileSync( file ) ); + + ret.raw = FS.readFileSync( file, 'utf8' ); + ret.json = JSON.parse( ret.raw ); + } - catch(ex) { - loadSafeJson.error = ex; + catch( ex ) { + + // If we get here, either FS.readFileSync or JSON.parse failed. + // We'll return HMSTATUS.readError or HMSTATUS.parseError. + ret.ex = ( ret.raw && ret.raw.trim() ) ? + { // JSON.parse failed, likely because of a SyntaxError + fluenterror: HMSTATUS.parseError, + inner: SyntaxErrorEx.is( ex ) ? new SyntaxErrorEx( ex ) : ex + } : + { // FS.readFileSync failed, likely because of ENOENT or EACCES + fluenterror: HMSTATUS.readError, + inner: ex + }; + } - return null; + + return ret; + }; diff --git a/src/verbs/peek.js b/src/verbs/peek.js new file mode 100644 index 0000000..f195bbd --- /dev/null +++ b/src/verbs/peek.js @@ -0,0 +1,63 @@ +/** +Implementation of the 'peek' verb for HackMyResume. +@module peek.js +@license MIT. See LICENSE.md for details. +*/ + + + +(function(){ + + + + var Verb = require('../verbs/verb') + , _ = require('underscore') + , __ = require('lodash') + , safeLoadJSON = require('../utils/safe-json-loader') + , HMSTATUS = require('../core/status-codes') + , HMEVENT = require('../core/event-codes'); + + + + var PeekVerb = module.exports = Verb.extend({ + + init: function() { + this._super('peek'); + }, + + invoke: function() { + peek.apply( this, arguments ); + } + + }); + + + + /** + Peek at a resume, resume section, or resume field. + */ + function peek( src, dst, opts ) { + + if(!src || !src.length) throw {fluenterror: HMSTATUS.resumeNotFound}; + this.stat( HMEVENT.begin ); + + var objPath = (dst && dst[0]) || ''; + + _.each( src, function( t ) { + this.stat( HMEVENT.beforePeek, { file: t, target: objPath } ); + + var obj = safeLoadJSON( t ); + if( obj.ex ) { + this.err( obj.ex.fluenterror, obj.ex ); + } + var targ = objPath ? __.get( obj.json, objPath ) : obj; + + this.stat( HMEVENT.afterPeek, { file: t, requested: objPath, target: targ } ); + }, this); + + this.stat( HMEVENT.end ); + } + + + +}());