Skip to content

Instantly share code, notes, and snippets.

@guybrush
Created September 19, 2010 18:46
Show Gist options
  • Save guybrush/587002 to your computer and use it in GitHub Desktop.
Save guybrush/587002 to your computer and use it in GitHub Desktop.
/*!
* Table.js
* Copyright(c) 2010 TJ Holowaychuk <[email protected]>
* MIT Licensed
*/
/**
* http://github.com/Marak/table.js/blob/master/lib/table.js
*/
/**
* Module dependencies.
*/
var sys = require('sys');
/**
* Initialize a Table.
*
* @api public
*/
var Table = exports = module.exports = function Table(){
this.align = {};
this.chars = '+-|';
};
sys.inherits(Table, Array);
/**
* Add a `row` of cells.
*
* @param {Array} row
* @return {Row}
* @api public
*/
Table.prototype.addRow = function(row){
this.push(row = new Row(row));
return row;
};
/**
* Add a head `row` of cells.
*
* @param {Array} row
* @return {Head}
* @api public
*/
Table.prototype.addHead = function(row){
this.push(row = new Head(row));
return row;
};
/**
* Align `col` to `align`.
*
* @param {Number} col
* @param {Number|String} align
* @api public
*/
Table.prototype.alignColumn = function(col, align){
this.align[col] = alignmentString(align);
};
/**
* Convert table to a string.
*
* @return {String}
* @api public
*/
Table.prototype.toString = function(){
var sep = this.separator();
return sep + '\n'
+ this.map(function(row){
return this.chars[2]
+ row.toString(this)
+ ' '
+ this.chars[2]
+ (row instanceof Head ? '\n' + sep : '');
}, this).join('\n') + '\n'
+ sep;
};
/**
* Return table seperator.
*
* @return {String}
* @api private
*/
Table.prototype.separator = function(){
return this.chars[0]
+ Array(this.rowWidth()).join(this.chars[1])
+ this.chars[0];
};
/**
* Return largest row width.
*
* @return {number}
* @api private
*/
Table.prototype.rowWidth = function(){
var self = this;
return this.reduce(function(width, row){
var n = row.width(self);
return n > width ? n : width;
}, 0) + 2;
};
/**
* Return largest cell width in the given `col`.
*
* @param {Number} col
* @return {Number}
* @api private
*/
Table.prototype.largestCellWidth = function(col){
return this.reduce(function(width, row){
var n = row[col].str.length;
return n > width ? n : width;
}, 0);
};
// Row
/**
* Initialize a new row with the given `cells`.
*
* @param {Array} cells
* @api public
*/
var Row = exports.Row = function Row(cells){
if (cells) {
for (var i = 0, len = cells.length; i < len; ++i) {
this.addCell(cells[i]);
}
}
};
sys.inherits(Row, Array);
/**
* Add the given `cell` with optional `align`ment.
*
* @param {Cell|String} cell
* @param {Number|Object} align
* @return {Cell}
* @api public
*/
Row.prototype.addCell = function(cell, align){
if (cell instanceof Cell) {
this.push(cell);
} else {
align = typeof align === 'object'
? align.align
: align;
this.push(cell = new Cell(cell, align));
}
return cell;
};
/**
* Return row width.
*
* @param {Table} table
* @return {Number}
* @api private
*/
Row.prototype.width = function(table){
return this.reduce(function(sum, cell, i){
return sum + table.largestCellWidth(i) + 2;
}, this.length - 1);
};
/**
* Convert row to a string.
*
* @param {Table} table
* @return {String}
* @api private
*/
Row.prototype.toString = function(table){
return this.map(function(cell, i){
var align = table.align[i] === undefined
? -1
: table.align[i];
return cell.toString(table.largestCellWidth(i), align);
}).join(table.chars[2]);
};
// Head
/**
* Initialize a new head with the given `cells`.
*
* @param {Array} cells
* @api public
*/
var Head = exports.Head = function Head(cells){
Row.call(this, cells);
};
sys.inherits(Head, Row);
// Cell
/**
* Initialize new cell with the given `str` and `align`ment.
*
* @param {String} str
* @param {Number|String} align
* @api public
*/
var Cell = exports.Cell = function Cell(str, align){
this.str = str;
this.align = align === undefined
? align
: alignmentString(align);
};
/**
* Convert cell to a string with the given `width`, and `align`ment.
*
* @param {Number} width
* @param {Number} align
* @return {String}
* @api private
*/
Cell.prototype.toString = function(width, align){
var len = this.str.length,
align = typeof this.align === 'number'
? this.align
: align;
if (len < width) {
var pad = width - len;
switch (align) {
case 0:
pad = pad / 2;
while (pad--) {
this.str = ' ' + this.str + ' ';
}
break;
case 1:
while (pad--) {
this.str = ' ' + this.str;
}
break;
default:
while (pad--) {
this.str += ' ';
}
}
}
return ' ' + this.str + ' ';
};
// Utilities
/**
* Accept an `align`ment string such as 'left', 'right'
* or 'center'. When a `Number` is passed it is returned.
*
* @param {String|Number} align
* @return {Number}
* @api private
*/
function alignmentString(align) {
switch (align) {
case 'right':
return 1;
case 'left':
return -1;
case 'center':
return 0;
default:
return align;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment