mirror of
https://github.com/JuanCanham/HackMyResume.git
synced 2024-11-21 16:00:11 +00:00
Introduce formal generators.
Introduce a shallow hierarchy of simple generator classes, collecting common functionality and allowing for future snap-in generator replacement. Use John Resig's "class"-based inheritance per http://ejohn.org/blog/simple-javascript-inheritance/.
This commit is contained in:
parent
7bf25469de
commit
7363e48019
13
src/gen/base-generator.js
Normal file
13
src/gen/base-generator.js
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
Base resume generator for FluentCV.
|
||||
@license Copyright (c) 2015 by James M. Devlin. All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var Class = require( './class' );
|
||||
var BaseGenerator = module.exports = Class.extend({
|
||||
init: function( outputFormat ) {
|
||||
this.format = outputFormat;
|
||||
}
|
||||
});
|
||||
}());
|
67
src/gen/class.js
Normal file
67
src/gen/class.js
Normal file
@ -0,0 +1,67 @@
|
||||
/* Simple JavaScript Inheritance
|
||||
* By John Resig http://ejohn.org/
|
||||
* MIT Licensed.
|
||||
* http://ejohn.org/blog/simple-javascript-inheritance/
|
||||
*/
|
||||
// Inspired by base2 and Prototype
|
||||
(function(){
|
||||
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
|
||||
// The base Class implementation (does nothing)
|
||||
this.Class = function(){};
|
||||
module.exports = Class;
|
||||
|
||||
// Create a new Class that inherits from this class
|
||||
Class.extend = function(prop) {
|
||||
var _super = this.prototype;
|
||||
|
||||
// Instantiate a base class (but only create the instance,
|
||||
// don't run the init constructor)
|
||||
initializing = true;
|
||||
var prototype = new this();
|
||||
initializing = false;
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
for (var name in prop) {
|
||||
// Check if we're overwriting an existing function
|
||||
prototype[name] = typeof prop[name] == "function" &&
|
||||
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
|
||||
(function(name, fn){
|
||||
return function() {
|
||||
var tmp = this._super;
|
||||
|
||||
// Add a new ._super() method that is the same method
|
||||
// but on the super-class
|
||||
this._super = _super[name];
|
||||
|
||||
// The method only need to be bound temporarily, so we
|
||||
// remove it when we're done executing
|
||||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
|
||||
return ret;
|
||||
};
|
||||
})(name, prop[name]) :
|
||||
prop[name];
|
||||
}
|
||||
|
||||
// The dummy class constructor
|
||||
function Class() {
|
||||
// All construction is actually done in the init method
|
||||
if ( !initializing && this.init )
|
||||
this.init.apply(this, arguments);
|
||||
}
|
||||
|
||||
// Populate our constructed prototype object
|
||||
Class.prototype = prototype;
|
||||
|
||||
// Enforce the constructor to be what we expect
|
||||
Class.prototype.constructor = Class;
|
||||
|
||||
// And make this class extendable
|
||||
Class.extend = arguments.callee;
|
||||
|
||||
return Class;
|
||||
};
|
||||
|
||||
})();
|
31
src/gen/html-generator.js
Normal file
31
src/gen/html-generator.js
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
HTML resume generator for FluentCV.
|
||||
@license Copyright (c) 2015 by James M. Devlin. All rights reserved.
|
||||
*/
|
||||
|
||||
var TemplateGenerator = require('./template-generator');
|
||||
var FS = require('fs-extra');
|
||||
var HTML = require( 'html' );
|
||||
|
||||
var HtmlGenerator = TemplateGenerator.extend({
|
||||
|
||||
init: function() {
|
||||
this._super( 'html' );
|
||||
},
|
||||
|
||||
/**
|
||||
Generate an HTML resume with optional pretty printing.
|
||||
*/
|
||||
onBeforeSave: function( mk, themeFile, outputFile ) {
|
||||
var cssSrc = themeFile.replace( /.html$/g, '.css' );
|
||||
var cssDst = outputFile.replace( /.html$/g, '.css' );
|
||||
FS.copy( cssSrc, cssDst, function( e ) {
|
||||
if( e ) err( "Couldn't copy CSS file to destination: " + err);
|
||||
});
|
||||
return true ?
|
||||
HTML.prettyPrint( mk, { indent_size: 2 } ) : mk;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = HtmlGenerator;
|
31
src/gen/html-pdf-generator.js
Normal file
31
src/gen/html-pdf-generator.js
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
HTML-based PDF resume generator for FluentCV.
|
||||
@license Copyright (c) 2015 by James M. Devlin. All rights reserved.
|
||||
*/
|
||||
|
||||
var TemplateGenerator = require('./template-generator');
|
||||
var FS = require('fs-extra');
|
||||
var HTML = require( 'html' );
|
||||
|
||||
var HtmlPdfGenerator = TemplateGenerator.extend({
|
||||
|
||||
init: function() {
|
||||
this._super( 'pdf', 'html' );
|
||||
},
|
||||
|
||||
/**
|
||||
Generate an HTML resume with optional pretty printing.
|
||||
*/
|
||||
onBeforeSave: function( mk, themeFile, outputFile ) {
|
||||
var cssSrc = themeFile.replace( /.html$/g, '.css' );
|
||||
var cssDst = outputFile.replace( /.html$/g, '.css' );
|
||||
FS.copy( cssSrc, cssDst, function( e ) {
|
||||
if( e ) err( "Couldn't copy CSS file to destination: " + err);
|
||||
});
|
||||
return true ?
|
||||
HTML.prettyPrint( mk, { indent_size: 2 } ) : mk;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = HtmlPdfGenerator;
|
148
src/gen/template-generator.js
Normal file
148
src/gen/template-generator.js
Normal file
@ -0,0 +1,148 @@
|
||||
/**
|
||||
Template-based resume generator base for FluentCV.
|
||||
@license Copyright (c) 2015 by James M. Devlin. All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
var FS = require( 'fs' );
|
||||
var BaseGenerator = require( './base-generator' );
|
||||
var _ = require( 'underscore' );
|
||||
var MD = require( 'marked' );
|
||||
var XML = require( 'xml-escape' );
|
||||
var path = require('path');
|
||||
|
||||
var _opts = {
|
||||
keepBreaks: true,
|
||||
nSym: '&newl;',
|
||||
rSym: '&retn;',
|
||||
template: {
|
||||
interpolate: /\{\{(.+?)\}\}/g,
|
||||
escape: /\{\{\=(.+?)\}\}/g,
|
||||
evaluate: /\{\%(.+?)\%\}/g,
|
||||
comment: /\{\#(.+?)\#\}/g
|
||||
},
|
||||
filters: {
|
||||
out: function( txt ) { return txt; },
|
||||
raw: function( txt ) { return txt; },
|
||||
xml: function( txt ) { return XML(txt); },
|
||||
md: function( txt ) { return MD(txt); },
|
||||
mdin: function( txt ) { return MD(txt).replace(/^\s*\<p\>|\<\/p\>\s*$/gi, ''); },
|
||||
lower: function( txt ) { return txt.toLowerCase(); }
|
||||
},
|
||||
prettyPrint: true,
|
||||
prettyIndent: 2
|
||||
};
|
||||
|
||||
var TemplateGenerator = BaseGenerator.extend({
|
||||
|
||||
/** outputFormat: html, txt, pdf, doc
|
||||
templateFormat: html or txt
|
||||
**/
|
||||
init: function( outputFormat, templateFormat, cssFile ){
|
||||
this._super( outputFormat );
|
||||
this.tplFormat = templateFormat || outputFormat;
|
||||
},
|
||||
|
||||
/** Default generation method for template-based generators. */
|
||||
generate: function( rez, f, themeName ) {
|
||||
try {
|
||||
|
||||
// Get the output file type (pdf, html, txt, etc)
|
||||
var fName = path.basename( f, '.' + this.format );
|
||||
|
||||
// Load the active theme file, including CSS data if req'd
|
||||
var themeFile = path.join( __dirname, '../../../watermark/', themeName, this.format + '.' + this.tplFormat );
|
||||
var cssData = this.tplFormat === 'html' ? FS.readFileSync( path.join( __dirname, '../../../watermark/', themeName, 'html.css' ), 'utf8' ) : null;
|
||||
var mk = FS.readFileSync( themeFile, 'utf8' );
|
||||
|
||||
// Compile and invoke the template!
|
||||
mk = this.single( rez, mk, this.format, cssData, fName );
|
||||
this.onBeforeSave && (mk = this.onBeforeSave( mk, themeFile, f ));
|
||||
|
||||
// Post-process and save the file
|
||||
FS.writeFileSync( f, mk, 'utf8' );
|
||||
return mk;
|
||||
}
|
||||
catch( ex ) {
|
||||
err( ex );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Perform a single resume JSON-to-DEST resume transformation. Exists as a
|
||||
separate function in order to expose string-based transformations to clients
|
||||
who don't have access to filesystem resources (in-browser, etc.).
|
||||
*/
|
||||
single: function( json, jst, format, styles, fName ) {
|
||||
|
||||
// Freeze whitespace in the template
|
||||
_opts.keepBreaks && ( jst = freeze(jst) );
|
||||
|
||||
// Tweak underscore's default template delimeters
|
||||
_.templateSettings = _opts.template;
|
||||
|
||||
// Convert {{ someVar }} to {% print(filt.out(someVar) %}
|
||||
// Convert {{ someVar|someFilter }} to {% print(filt.someFilter(someVar) %}
|
||||
jst = jst.replace( _.templateSettings.interpolate, function replace(m, p1) {
|
||||
if( p1.indexOf('|') > -1 ) {
|
||||
var terms = p1.split('|');
|
||||
return '{% print( filt.' + terms[1] + '( ' + terms[0] + ' )) %}';
|
||||
}
|
||||
else {
|
||||
return '{% print( filt.out(' + p1 + ') ) %}';
|
||||
}
|
||||
});
|
||||
|
||||
// Strip {# comments #}
|
||||
jst = jst.replace( _.templateSettings.comment, '');
|
||||
json.display_progress_bar = true;
|
||||
|
||||
// Compile and run the template. TODO: avoid unnecessary recompiles.
|
||||
jst = _.template( jst )({ r: json, css: styles, embedCss: false, cssFile: fName, filt: _opts.filters });
|
||||
|
||||
// Unfreeze whitespace
|
||||
_opts.keepBreaks && ( jst = unfreeze(jst) );
|
||||
|
||||
return jst;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
Export the TemplateGenerator function/ctor.
|
||||
*/
|
||||
module.exports = TemplateGenerator;
|
||||
|
||||
/**
|
||||
Freeze newlines for protection against errant JST parsers.
|
||||
*/
|
||||
function freeze( markup ) {
|
||||
return markup
|
||||
.replace( _reg.regN, _opts.nSym )
|
||||
.replace( _reg.regR, _opts.rSym );
|
||||
}
|
||||
|
||||
/**
|
||||
Unfreeze newlines when the coast is clear.
|
||||
*/
|
||||
function unfreeze( markup ) {
|
||||
return markup
|
||||
.replace( _reg.regSymR, '\r' )
|
||||
.replace( _reg.regSymN, '\n' );
|
||||
}
|
||||
|
||||
/**
|
||||
Regexes for linebreak preservation.
|
||||
*/
|
||||
var _reg = {
|
||||
regN: new RegExp( '\n', 'g' ),
|
||||
regR: new RegExp( '\r', 'g' ),
|
||||
regSymN: new RegExp( _opts.nSym, 'g' ),
|
||||
regSymR: new RegExp( _opts.rSym, 'g' )
|
||||
};
|
||||
|
||||
|
||||
|
||||
}());
|
15
src/gen/text-generator.js
Normal file
15
src/gen/text-generator.js
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
Plain text resume generator for FluentCV.
|
||||
@license Copyright (c) 2015 by James M. Devlin. All rights reserved.
|
||||
*/
|
||||
|
||||
var TemplateGenerator = require('./template-generator');
|
||||
var TextGenerator = TemplateGenerator.extend({
|
||||
|
||||
init: function(){
|
||||
this._super( 'txt' );
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
module.exports = TextGenerator;
|
13
src/gen/word-generator.js
Normal file
13
src/gen/word-generator.js
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
MS Word resume generator for FluentCV.
|
||||
@license Copyright (c) 2015 by James M. Devlin. All rights reserved.
|
||||
*/
|
||||
|
||||
var TemplateGenerator = require('./template-generator');
|
||||
var WordGenerator = module.exports = TemplateGenerator.extend({
|
||||
|
||||
init: function(){
|
||||
this._super( 'doc', 'xml' );
|
||||
},
|
||||
|
||||
});
|
@ -13,7 +13,11 @@ module.exports = function () {
|
||||
, path = require( 'path' )
|
||||
, extend = require( './extend' )
|
||||
, _ = require('underscore')
|
||||
, Sheet = require('./sheet');
|
||||
, Sheet = require('./sheet')
|
||||
, HtmlGenerator = require('./gen/html-generator')
|
||||
, TextGenerator = require('./gen/text-generator')
|
||||
, HtmlPdfGenerator = require('./gen/html-pdf-generator')
|
||||
, WordGenerator = require('./gen/word-generator');
|
||||
|
||||
String.prototype.endsWith = function(suffix) {
|
||||
return this.indexOf(suffix, this.length - suffix.length) !== -1;
|
||||
@ -281,7 +285,12 @@ module.exports = function () {
|
||||
generate: hmr,
|
||||
transform: single,
|
||||
options: _opts,
|
||||
formats: _fmts
|
||||
formats: _fmts,
|
||||
Sheet: Sheet,
|
||||
HtmlGenerator: HtmlGenerator,
|
||||
TextGenerator: TextGenerator,
|
||||
HtmlPdfGenerator: HtmlPdfGenerator,
|
||||
WordGenerator: WordGenerator
|
||||
};
|
||||
|
||||
}();
|
||||
|
Loading…
Reference in New Issue
Block a user