mirror of
				https://github.com/JuanCanham/HackMyResume.git
				synced 2025-10-29 20:36:03 +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:
		
							
								
								
									
										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' ) |     , path = require( 'path' ) | ||||||
|     , extend = require( './extend' ) |     , extend = require( './extend' ) | ||||||
|     , _ = require('underscore') |     , _ = 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) { |   String.prototype.endsWith = function(suffix) { | ||||||
|     return this.indexOf(suffix, this.length - suffix.length) !== -1; |     return this.indexOf(suffix, this.length - suffix.length) !== -1; | ||||||
| @@ -281,7 +285,12 @@ module.exports = function () { | |||||||
|     generate: hmr, |     generate: hmr, | ||||||
|     transform: single, |     transform: single, | ||||||
|     options: _opts, |     options: _opts, | ||||||
|     formats: _fmts |     formats: _fmts, | ||||||
|  |     Sheet: Sheet, | ||||||
|  |     HtmlGenerator: HtmlGenerator, | ||||||
|  |     TextGenerator: TextGenerator, | ||||||
|  |     HtmlPdfGenerator: HtmlPdfGenerator, | ||||||
|  |     WordGenerator: WordGenerator | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
| }(); | }(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user