Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Support for totals (Closes #1)

  • Loading branch information...
commit b1a972930e463c1a7f34f5b334423480e7cb3970 1 parent 20f2a69
@eldargab authored
View
2  .npmignore
@@ -0,0 +1,2 @@
+test/
+example.js
View
3  example.js
@@ -18,5 +18,8 @@ data.forEach(function (product) {
})
t.sort(['Price, USD'])
+t.total('Price, USD', Table.aggr.avg, function (val, width) {
+ return Table.padLeft('Avg: ' + val.toFixed(2), width)
+})
console.log(t.toString())
View
71 lib/print.js
@@ -1,71 +0,0 @@
-var util = require('./util')
-
-module.exports = function print (rows, columns, shift) {
- var widths = {}
-
- function setWidth (col, width) {
- var isFixed = columns[col].width != null
- if (isFixed) {
- widths[col] = columns[col].width
- } else {
- if (widths[col] > width) return
- widths[col] = width
- }
- }
-
- function cellPrinter (row, col) {
- return row.__printers[col] || columns[col].printer
- }
-
- function calcWidths () {
- for (var key in columns) {
- setWidth(key, key.length)
- }
-
- rows.forEach(function (row) {
- for (var key in columns) {
- setWidth(key, cellPrinter(row, key).call(row, row[key]).length)
- }
- })
- }
-
- function printRow (cb) {
- var s = ''
- var firstColumn = true
- for (var key in columns) {
- if (!firstColumn) s += shift
- firstColumn = false
- var width = widths[key]
- s += printCell(cb(key, width), width)
- }
- s += '\n'
- return s
- }
-
- function printCell (s, width) {
- if (s.length <= width) return util.padSpaces(s, width)
- s = s.slice(0, width)
- if (width > 3) s = s.slice(0, -3).concat('...')
- return s
- }
-
- var ret = ''
-
- calcWidths()
-
- ret += printRow(function (key) {
- return key
- })
-
- ret += printRow(function (key, width) {
- return util.padWithDashs('', width)
- })
-
- rows.forEach(function (row) {
- ret += printRow(function (key, width) {
- return cellPrinter(row, key).call(row, row[key], width)
- })
- })
-
- return ret
-}
View
113 lib/table.js
@@ -1,16 +1,13 @@
var util = require('./util')
-var print = require('./print')
module.exports = Table
-Table.string = function (obj) {
- if (obj === undefined) return ''
- return String(obj)
-}
-
+Table.string = util.string
+Table.number = util.number
Table.padLeft = util.padLeft
Table.RightPadder = util.RightPadder
Table.LeftPadder = util.LeftPadder
+Table.aggr = util.aggr
function Table () {
@@ -37,10 +34,8 @@ function Row () {
Table.prototype.cell = function (col, val, printer, width) {
this.row.__cell(col, val, printer)
- var c = this.columns[col] || (this.columns[col] = {
- printer: printer || Table.string
- })
- c.width = width > c.width || c.width == null ? width : c.width
+ var c = this.columns[col] || (this.columns[col] = {})
+ if (width != null) c.width = width
return this
}
@@ -52,8 +47,104 @@ Table.prototype.newRow = Table.prototype.newLine = function () {
Table.prototype.sort = require('./sort')
+Table.prototype.total = function (col, fn, printer) {
+ fn = fn || util.aggr.sum
+ printer = printer || fn.printer
+
+ this._totals = this._totals || new Row
+
+ var val
+ var rows = this.rows
+
+ this._totals.__cell(col, null, function (_, width) {
+ if (width != null) return printer(val, width)
+ val = rows.reduce(function (val, row, index) {
+ return fn(val, row[col], index, rows.length)
+ }, null)
+ return printer(val)
+ })
+ return this
+}
+
Table.prototype.shift = ' '
Table.prototype.toString = function () {
- return print(this.rows, this.columns, this.shift)
+ var delimeter = this._row(function () {
+ return ['', util.padWithDashs]
+ })
+ var head = this._row(function (key) {
+ return [key, Table.string]
+ })
+ var rows = [head, delimeter].concat(this.rows)
+ if (this._totals) {
+ rows = rows.concat([delimeter, this._totals])
+ }
+ return print(rows, this.columns, this.shift)
+}
+
+Table.prototype._row = function (cb) {
+ var row = new Row
+ for (var key in this.columns) {
+ var args = cb(key)
+ row.__cell(key, args[0], args[1])
+ }
+ return row
+}
+
+function print (rows, columns, shift) {
+ var widths = {}
+
+ function setWidth (col, width) {
+ var isFixed = columns[col].width != null
+ if (isFixed) {
+ widths[col] = columns[col].width
+ } else {
+ if (widths[col] > width) return
+ widths[col] = width
+ }
+ }
+
+ function cellPrinter (row, col) {
+ return row.__printers[col] || util.string
+ }
+
+ function calcWidths () {
+ for (var key in columns) {
+ setWidth(key, key.length)
+ }
+
+ rows.forEach(function (row) {
+ for (var key in columns) {
+ setWidth(key, cellPrinter(row, key).call(row, row[key]).length)
+ }
+ })
+ }
+
+ function printRow (cb) {
+ var s = ''
+ var firstColumn = true
+ for (var key in columns) {
+ if (!firstColumn) s += shift
+ firstColumn = false
+ var width = widths[key]
+ s += printCell(cb(key, width), width)
+ }
+ s += '\n'
+ return s
+ }
+
+ function printCell (s, width) {
+ if (s.length <= width) return util.padSpaces(s, width)
+ s = s.slice(0, width)
+ if (width > 3) s = s.slice(0, -3).concat('...')
+ return s
+ }
+
+ calcWidths()
+
+ return rows.map(function (row) {
+ return printRow(function (key, width) {
+ return cellPrinter(row, key).call(row, row[key], width)
+ })
+ }).join('')
}
View
41 lib/util.js
@@ -1,4 +1,3 @@
-
exports.RightPadder = function (char) {
char = char || ' '
return function (obj, length) {
@@ -28,4 +27,42 @@ exports.padLeft = exports.LeftPadder()
exports.padWithDashs = exports.RightPadder('-')
-exports.padSpaces = exports.RightPadder()
+exports.padSpaces = exports.RightPadder()
+
+exports.string = function (val) {
+ if (val === undefined) return ''
+ return String(val)
+}
+
+exports.number = function (val, width) {
+ return exports.padLeft(exports.string(val), width)
+}
+
+
+var aggr = exports.aggr = {}
+
+aggr.Printer = function (name, format) {
+ return function (val, width) {
+ var s = name + ' ' + format(val)
+ return width == null
+ ? s
+ : exports.padLeft(s, width)
+ }
+}
+
+aggr.sum = function (sum, val) {
+ sum = sum || 0
+ return sum += val
+}
+
+aggr.sum.printer = aggr.Printer('\u2211', String)
+
+aggr.avg = function (sum, val, index, length) {
+ sum = sum || 0
+ sum += val
+ return index + 1 == length
+ ? sum / length
+ : sum
+}
+
+aggr.avg.printer = aggr.Printer('Avg:', String)
View
41 test/table.js
@@ -13,7 +13,7 @@ describe('Easy table', function () {
return t.toString().split('\n')[line].should
}
- it('test', function () {
+ it('Formating', function () {
t.cell('First column', '11')
t.cell('Second column', '12')
t.newRow()
@@ -65,7 +65,7 @@ describe('Easy table', function () {
expectLine(3).be.equal(' 10 ')
})
- it('It should be called with `this` set to line', function () {
+ it('It should be called with `this` set to row', function () {
function print (obj) {
this.should.have.property('bar')
this.should.have.property('baz')
@@ -75,23 +75,23 @@ describe('Easy table', function () {
})
})
- describe('Should accept column length as 4-th parameter to .cell() method. In such case:', function () {
- it('Column length should be fixed', function () {
+ describe('Should accept column width as 4-th parameter to .cell() method. In such case:', function () {
+ it('Width is fixed', function () {
t.cell('col', 'value', null, 10).newRow()
expectLine(3).be.equal('value ')
})
- it('If cell value doesn`t fit it should be trancated', function () {
+ it('If cell`s value doesn`t fit it should be truncated', function () {
t.cell('col', 'A very long value', null, 14).newRow()
expectLine(3).be.equal('A very long...')
})
})
- it('test Table.padLeft()', function () {
+ it('Table.padLeft()', function () {
Table.padLeft('a', 2).should.equal(' a')
})
- it('test .sort()', function () {
+ it('Sorting', function () {
t.cell('a', 1).newRow()
t.cell('a', 2).newRow()
t.cell('a', null).newRow()
@@ -110,5 +110,32 @@ describe('Easy table', function () {
expectLine(3).be.equal('1 ')
expectLine(4).be.equal('2 ')
})
+
+ describe('Totals', function () {
+ it('Default totaling', function () {
+ t.cell('a', 1).newRow()
+ t.cell('a', 2).newRow()
+ t.total('a')
+ expectLine(6).be.equal('\u2211 3')
+ })
+
+ it('Passing aggregator with printer', function () {
+ t.cell('a', 1).newRow()
+ t.cell('a', 3).newRow()
+ t.total('a', Table.aggr.avg)
+ expectLine(6).be.equal('Avg: 2')
+ })
+
+ it('Custom format', function () {
+ t.cell('a', 1).newRow()
+ t.cell('a', 3).newRow()
+
+ t.total('a', Table.aggr.avg, function format (val, width) {
+ val.should.equal(2)
+ return 'Hey!'
+ })
+ expectLine(6).be.equal('Hey!')
+ })
+ })
})
Please sign in to comment.
Something went wrong with that request. Please try again.