mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-18 21:27:51 +00:00
Refactor table utilities into tableHelpers
This commit is contained in:
parent
55fa8435bb
commit
34346dd3d0
67
lib/table/table-helpers.coffee
Normal file
67
lib/table/table-helpers.coffee
Normal file
@ -0,0 +1,67 @@
|
||||
_ = require('lodash')
|
||||
_.str = require('underscore.string')
|
||||
|
||||
KEY_DISPLAY_MAP =
|
||||
app_name: 'Name'
|
||||
last_seen_time: 'Last Seen'
|
||||
ip_address: 'IP Address'
|
||||
id: 'ID'
|
||||
|
||||
startsWithLetter = (string) ->
|
||||
firstLetter = _.first(string)
|
||||
return /[a-z|A-Z]/.test(firstLetter)
|
||||
|
||||
renameObjectKey = (object, key, newKey) ->
|
||||
return if key is newKey
|
||||
object[newKey] = object[key]
|
||||
delete object[key]
|
||||
|
||||
exports.getKeyName = (key) ->
|
||||
nameFromMap = KEY_DISPLAY_MAP[key]
|
||||
return nameFromMap if nameFromMap?
|
||||
key = key.replace('_', ' ')
|
||||
return _.str.titleize(key)
|
||||
|
||||
exports.prepareObject = (object) ->
|
||||
object = _.omit object, (value, key) ->
|
||||
return not startsWithLetter(key)
|
||||
|
||||
for key, value of object
|
||||
if _.isObject(value) and not _.isArray(value)
|
||||
object[key] = exports.prepareObject(value)
|
||||
|
||||
newKeyName = exports.getKeyName(key)
|
||||
renameObjectKey(object, key, newKeyName)
|
||||
|
||||
object = _.omit object, (value, key) ->
|
||||
|
||||
# For some reason, _.isEmpty returns true for numbers
|
||||
return _.isEmpty(value) and not _.isNumber(value)
|
||||
|
||||
return object
|
||||
|
||||
exports.processTableContents = (contents, map) ->
|
||||
|
||||
# Allows us to simplify the algorithm by not
|
||||
# concerning about different input types
|
||||
if not _.isArray(contents)
|
||||
contents = [ contents ]
|
||||
|
||||
contents = _.map(contents, map or _.identity)
|
||||
contents = _.map(contents, exports.prepareObject)
|
||||
return contents
|
||||
|
||||
isRealObject = (object) ->
|
||||
return false if _.isArray(object) or _.isFunction(object)
|
||||
return _.isObject(object)
|
||||
|
||||
exports.getDefaultContentsOrdering = (contents) ->
|
||||
return if _.isEmpty(contents)
|
||||
firstContentEntry = _.first(contents)
|
||||
return if not isRealObject(firstContentEntry)
|
||||
return _.keys(firstContentEntry)
|
||||
|
||||
exports.normaliseOrdering = (ordering, contents) ->
|
||||
if not _.isEmpty(ordering)
|
||||
return _.map(ordering, _.str.titleize)
|
||||
return exports.getDefaultContentsOrdering(contents)
|
148
lib/table/table-helpers.spec.coffee
Normal file
148
lib/table/table-helpers.spec.coffee
Normal file
@ -0,0 +1,148 @@
|
||||
expect = require('chai').expect
|
||||
_ = require('lodash')
|
||||
tableHelpers = require('./table-helpers')
|
||||
|
||||
OBJECTS =
|
||||
application:
|
||||
device: null
|
||||
id: 162
|
||||
user:
|
||||
__deferred: []
|
||||
__id: 24
|
||||
app_name: 'HelloResin'
|
||||
git_repository: 'git@git.staging.resin.io:jviotti/helloresin.git'
|
||||
commit: '1234'
|
||||
device_type: 'raspberry-pi'
|
||||
__metadata:
|
||||
uri: '/ewa/application(162)'
|
||||
basic:
|
||||
Hello: 'world'
|
||||
Hey: 'there'
|
||||
__private: true
|
||||
_option: false
|
||||
$data: [ 1, 2, 3 ]
|
||||
recursive:
|
||||
hello: 'world'
|
||||
Hey:
|
||||
__private: true
|
||||
value:
|
||||
$option: false
|
||||
data: 'There'
|
||||
_option: false
|
||||
__something:
|
||||
value: 'ok'
|
||||
nested:
|
||||
$data: [ 1, 2, 3 ]
|
||||
valid:
|
||||
One: 'one'
|
||||
Two: 'two'
|
||||
Three: 'three'
|
||||
|
||||
describe 'Table Helpers:', ->
|
||||
|
||||
describe '#getKeyName()', ->
|
||||
|
||||
it 'should return titleized names', ->
|
||||
expect(tableHelpers.getKeyName('hello world')).to.equal('Hello World')
|
||||
expect(tableHelpers.getKeyName('foo Bar')).to.equal('Foo Bar')
|
||||
|
||||
it 'should return custom names from the map', ->
|
||||
expect(tableHelpers.getKeyName('last_seen_time')).to.equal('Last Seen')
|
||||
expect(tableHelpers.getKeyName('app_name')).to.equal('Name')
|
||||
|
||||
it 'should remove underscores', ->
|
||||
expect(tableHelpers.getKeyName('git_repository')).to.equal('Git Repository')
|
||||
expect(tableHelpers.getKeyName('device_type')).to.equal('Device Type')
|
||||
|
||||
describe '#prepareObject()', ->
|
||||
|
||||
it 'should get rid of keys not starting with letters', ->
|
||||
expect(tableHelpers.prepareObject(OBJECTS.basic)).to.deep.equal
|
||||
Hello: 'world'
|
||||
Hey: 'there'
|
||||
|
||||
it 'should get rid of keys not starting with letters recursively', ->
|
||||
expect(tableHelpers.prepareObject(OBJECTS.recursive)).to.deep.equal
|
||||
Hello: 'world'
|
||||
Hey:
|
||||
Value:
|
||||
Data: 'There'
|
||||
|
||||
it 'should do proper key renamings', ->
|
||||
expect(tableHelpers.prepareObject(OBJECTS.application)).to.deep.equal
|
||||
ID: 162
|
||||
Name: 'HelloResin'
|
||||
'Git Repository': 'git@git.staging.resin.io:jviotti/helloresin.git'
|
||||
Commit: '1234'
|
||||
'Device Type': 'raspberry-pi'
|
||||
|
||||
it 'should not remove not empty arrays', ->
|
||||
object = { Array: [ 1, 2, 3 ] }
|
||||
expect(tableHelpers.prepareObject(object)).to.deep.equal(object)
|
||||
|
||||
describe '#processTableContents()', ->
|
||||
|
||||
checkIfArray = (input) ->
|
||||
result = tableHelpers.processTableContents(input, _.identity)
|
||||
expect(result).to.be.an.instanceof(Array)
|
||||
|
||||
it 'should always return an array', ->
|
||||
checkIfArray(OBJECTS.basic)
|
||||
checkIfArray([ OBJECTS.basic ])
|
||||
checkIfArray([ 'contents' ])
|
||||
|
||||
it 'should be able to manipulate the contents', ->
|
||||
result = tableHelpers.processTableContents { hey: 'there' }, (item) ->
|
||||
item.hey = 'yo'
|
||||
return item
|
||||
|
||||
expect(result).to.deep.equal([ Hey: 'yo' ])
|
||||
|
||||
it 'should get rid of keys not starting with letters', ->
|
||||
result = tableHelpers.processTableContents(OBJECTS.basic, _.identity)
|
||||
expect(result).to.deep.equal [
|
||||
{
|
||||
Hello: 'world'
|
||||
Hey: 'there'
|
||||
}
|
||||
]
|
||||
|
||||
it 'should allow a null/undefined map function without corrupting the data', ->
|
||||
for map in [ null, undefined ]
|
||||
result = tableHelpers.processTableContents([ OBJECTS.valid ], map)
|
||||
expect(result).to.deep.equal([ OBJECTS.valid ])
|
||||
|
||||
describe '#getDefaultContentsOrdering()', ->
|
||||
|
||||
it 'should return undefined if no contents', ->
|
||||
expect(tableHelpers.getDefaultContentsOrdering()).to.be.undefined
|
||||
|
||||
it 'should return undefined if contents is empty', ->
|
||||
expect(tableHelpers.getDefaultContentsOrdering([])).to.be.undefined
|
||||
|
||||
it 'should return undefined if contents is not an array of objects', ->
|
||||
inputs = [
|
||||
[ 1, 2, 3 ]
|
||||
[ '1', '2', '3' ]
|
||||
[ _.identity ]
|
||||
]
|
||||
|
||||
for input in inputs
|
||||
expect(tableHelpers.getDefaultContentsOrdering(input)).to.be.undefined
|
||||
|
||||
it 'should return an array containing all the object keys', ->
|
||||
result = tableHelpers.getDefaultContentsOrdering([ OBJECTS.valid ])
|
||||
for key, value of OBJECTS.valid
|
||||
expect(result.indexOf(key)).to.not.equal(-1)
|
||||
|
||||
describe '#normaliseOrdering()', ->
|
||||
|
||||
it 'should return titleized words if ordering is not empty', ->
|
||||
ordering = [ 'one', 'two', 'three' ]
|
||||
result = tableHelpers.normaliseOrdering(ordering, {})
|
||||
expect(result).to.deep.equal([ 'One', 'Two', 'Three' ])
|
||||
|
||||
it 'should return an array containing all the object keys', ->
|
||||
result = tableHelpers.normaliseOrdering(null, [ OBJECTS.valid ])
|
||||
for key, value of OBJECTS.valid
|
||||
expect(result.indexOf(key)).to.not.equal(-1)
|
@ -1,72 +1,19 @@
|
||||
_ = require('lodash')
|
||||
cliff = require('cliff')
|
||||
|
||||
KEY_DISPLAY_MAP =
|
||||
commit: 'Commit'
|
||||
app_name: 'Name'
|
||||
git_repository: 'Git Repository'
|
||||
device_type: 'Device Type'
|
||||
id: 'ID'
|
||||
|
||||
startsWithLetter = (string) ->
|
||||
firstLetter = _.first(string)
|
||||
return /[a-z|A-Z]/.test(firstLetter)
|
||||
|
||||
renameObjectKey = (object, key, newKey) ->
|
||||
object[newKey] = object[key]
|
||||
delete object[key]
|
||||
|
||||
exports.prepareObject = (object) ->
|
||||
object = _.omit object, (value, key) ->
|
||||
return not startsWithLetter(key)
|
||||
|
||||
for key, value of object
|
||||
if _.isObject(value) and not _.isArray(value)
|
||||
object[key] = exports.prepareObject(value)
|
||||
|
||||
displayKey = KEY_DISPLAY_MAP[key]
|
||||
if displayKey?
|
||||
renameObjectKey(object, key, displayKey)
|
||||
|
||||
object = _.omit object, (value, key) ->
|
||||
|
||||
# For some reason, _.isEmpty returns true for numbers
|
||||
return _.isEmpty(value) and not _.isNumber(value)
|
||||
|
||||
return object
|
||||
|
||||
exports.processTableContents = (contents, map) ->
|
||||
|
||||
# Allows us to simplify the algorithm by not
|
||||
# concerning about different input types
|
||||
if not _.isArray(contents)
|
||||
contents = [ contents ]
|
||||
|
||||
contents = _.map(contents, map or _.identity)
|
||||
contents = _.map(contents, exports.prepareObject)
|
||||
return contents
|
||||
|
||||
isRealObject = (object) ->
|
||||
return false if _.isArray(object) or _.isFunction(object)
|
||||
return _.isObject(object)
|
||||
|
||||
exports.getDefaultContentsOrdering = (contents) ->
|
||||
return if _.isEmpty(contents)
|
||||
firstContentEntry = _.first(contents)
|
||||
return if not isRealObject(firstContentEntry)
|
||||
return _.keys(firstContentEntry)
|
||||
tableHelpers = require('./table-helpers')
|
||||
|
||||
# TODO: Maybe there is a (sane) way to test this, given
|
||||
# that the result is not automatically printed by cliff?
|
||||
exports.horizontal = (contents, map, ordering, colours) ->
|
||||
contents = exports.processTableContents(contents, map)
|
||||
ordering ?= exports.getDefaultContentsOrdering(contents)
|
||||
contents = tableHelpers.processTableContents(contents, map)
|
||||
ordering = tableHelpers.normaliseOrdering(ordering, contents)
|
||||
return cliff.stringifyObjectRows(contents, ordering, colours)
|
||||
|
||||
exports.vertical = (contents, map, ordering) ->
|
||||
contents = exports.processTableContents(contents, map)
|
||||
ordering ?= exports.getDefaultContentsOrdering(contents)
|
||||
contents = tableHelpers.processTableContents(contents, map)
|
||||
ordering = tableHelpers.normaliseOrdering(ordering, contents)
|
||||
|
||||
# TODO: Add some kind of separator to make clear
|
||||
# when we're printing another content item
|
||||
result = []
|
||||
for item in contents
|
||||
for next in ordering
|
||||
|
@ -1,136 +1,23 @@
|
||||
expect = require('chai').expect
|
||||
_ = require('lodash')
|
||||
table = require('./table')
|
||||
|
||||
OBJECTS =
|
||||
application:
|
||||
device: null
|
||||
id: 162
|
||||
user:
|
||||
__deferred: []
|
||||
__id: 24
|
||||
app_name: 'HelloResin'
|
||||
git_repository: 'git@git.staging.resin.io:jviotti/helloresin.git'
|
||||
commit: '1234'
|
||||
device_type: 'raspberry-pi'
|
||||
__metadata:
|
||||
uri: '/ewa/application(162)'
|
||||
basic:
|
||||
hello: 'world'
|
||||
Hey: 'there'
|
||||
__private: true
|
||||
_option: false
|
||||
$data: [ 1, 2, 3 ]
|
||||
recursive:
|
||||
hello: 'world'
|
||||
Hey:
|
||||
__private: true
|
||||
value:
|
||||
$option: false
|
||||
data: 'There'
|
||||
_option: false
|
||||
__something:
|
||||
value: 'ok'
|
||||
nested:
|
||||
$data: [ 1, 2, 3 ]
|
||||
valid:
|
||||
one: 'one'
|
||||
two: 'two'
|
||||
three: 'three'
|
||||
One: 'one'
|
||||
Two: 'two'
|
||||
Three: 'three'
|
||||
|
||||
describe 'Table:', ->
|
||||
|
||||
describe '#prepareObject()', ->
|
||||
|
||||
it 'should get rid of keys not starting with letters', ->
|
||||
expect(table.prepareObject(OBJECTS.basic)).to.deep.equal
|
||||
hello: 'world'
|
||||
Hey: 'there'
|
||||
|
||||
it 'should get rid of keys not starting with letters recursively', ->
|
||||
expect(table.prepareObject(OBJECTS.recursive)).to.deep.equal
|
||||
hello: 'world'
|
||||
Hey:
|
||||
value:
|
||||
data: 'There'
|
||||
|
||||
it 'should do proper key renamings', ->
|
||||
expect(table.prepareObject(OBJECTS.application)).to.deep.equal
|
||||
ID: 162
|
||||
Name: 'HelloResin'
|
||||
'Git Repository': 'git@git.staging.resin.io:jviotti/helloresin.git'
|
||||
Commit: '1234'
|
||||
'Device Type': 'raspberry-pi'
|
||||
|
||||
it 'should not remove not empty arrays', ->
|
||||
object = { array: [ 1, 2, 3 ] }
|
||||
expect(table.prepareObject(object)).to.deep.equal(object)
|
||||
|
||||
describe '#processTableContents()', ->
|
||||
|
||||
checkIfArray = (input) ->
|
||||
result = table.processTableContents(input, _.identity)
|
||||
expect(result).to.be.an.instanceof(Array)
|
||||
|
||||
it 'should always return an array', ->
|
||||
checkIfArray(OBJECTS.basic)
|
||||
checkIfArray([ OBJECTS.basic ])
|
||||
checkIfArray([ 'contents' ])
|
||||
|
||||
it 'should be able to manipulate the contents', ->
|
||||
result = table.processTableContents { hey: 'there' }, (item) ->
|
||||
item.hey = 'yo'
|
||||
return item
|
||||
|
||||
expect(result).to.deep.equal([ hey: 'yo' ])
|
||||
|
||||
it 'should get rid of keys not starting with letters', ->
|
||||
result = table.processTableContents(OBJECTS.basic, _.identity)
|
||||
expect(result).to.deep.equal [
|
||||
{
|
||||
hello: 'world'
|
||||
Hey: 'there'
|
||||
}
|
||||
]
|
||||
|
||||
it 'should allow a null/undefined map function without corrupting the data', ->
|
||||
for map in [ null, undefined ]
|
||||
result = table.processTableContents([ OBJECTS.valid ], map)
|
||||
expect(result).to.deep.equal([ OBJECTS.valid ])
|
||||
|
||||
describe '#getDefaultContentsOrdering()', ->
|
||||
|
||||
it 'should return undefined if no contents', ->
|
||||
expect(table.getDefaultContentsOrdering()).to.be.undefined
|
||||
|
||||
it 'should return undefined if contents is empty', ->
|
||||
expect(table.getDefaultContentsOrdering([])).to.be.undefined
|
||||
|
||||
it 'should return undefined if contents is not an array of objects', ->
|
||||
inputs = [
|
||||
[ 1, 2, 3 ]
|
||||
[ '1', '2', '3' ]
|
||||
[ _.identity ]
|
||||
]
|
||||
|
||||
for input in inputs
|
||||
expect(table.getDefaultContentsOrdering(input)).to.be.undefined
|
||||
|
||||
it 'should return an array containing all the object keys', ->
|
||||
result = table.getDefaultContentsOrdering([ OBJECTS.valid ])
|
||||
console.log result
|
||||
for key, value of OBJECTS.valid
|
||||
expect(result.indexOf(key)).to.not.equal(-1)
|
||||
|
||||
describe '#vertical()', ->
|
||||
|
||||
it 'should return a string respecting the ordering', ->
|
||||
ordering = [ 'one', 'two', 'three' ]
|
||||
ordering = [ 'One', 'Two', 'Three' ]
|
||||
result = table.vertical(OBJECTS.valid, null, ordering).split('\n')
|
||||
expected = [
|
||||
'one: one'
|
||||
'two: two'
|
||||
'three: three'
|
||||
'One: one'
|
||||
'Two: two'
|
||||
'Three: three'
|
||||
]
|
||||
|
||||
expect(result).to.deep.equal(expected)
|
||||
@ -138,9 +25,9 @@ describe 'Table:', ->
|
||||
it 'should be able to print everything without explicit ordering', ->
|
||||
result = table.vertical(OBJECTS.valid, null).split('\n')
|
||||
expected = [
|
||||
'one: one'
|
||||
'two: two'
|
||||
'three: three'
|
||||
'One: one'
|
||||
'Two: two'
|
||||
'Three: three'
|
||||
]
|
||||
|
||||
for line in expected
|
||||
|
@ -36,6 +36,7 @@
|
||||
"bluebird": "~2.3.11",
|
||||
"open": "0.0.5",
|
||||
"inquirer": "~0.8.0",
|
||||
"cliff": "~0.1.9"
|
||||
"cliff": "~0.1.9",
|
||||
"underscore.string": "~2.4.0"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user