spectacular
Version:
Advanced BDD framework for CoffeeScript and JavaScript
360 lines (304 loc) • 9.54 kB
text/coffeescript
utils = spectacular.utils ||= {}
spectacular.utils.squeeze = (s) -> s.replace /\s+/g, ' '
spectacular.utils.strip = (s) -> s.replace /^\s+|\s+$/g, ''
spectacular.utils.capitalize = (s) -> s.replace /^(\w)/, (m, c) -> c.toUpperCase()
spectacular.utils.underscore = (s) ->
s.replace(/([a-z])([A-Z])/g, "$1_$2")
.split(/[-/]|\s/g)
.join("_")
.toLowerCase()
spectacular.utils.camelize = (s) ->
a = s.toLowerCase().split /[_\s-]/
s = a.shift()
s = "#{s}#{utils.capitalize w}" for w in a
s
spectacular.utils.snakify = (o) ->
for k,v of o
descriptor = Object.getOwnPropertyDescriptor o, k
if descriptor?
Object.defineProperty o, utils.underscore(k), descriptor
else
o[utils.underscore k] = v
spectacular.utils.keys = (o) -> k for k of o
spectacular.utils.isArray = (o) -> Object::toString.call(o) is '[object Array]'
spectacular.utils.literalEnumeration = (array) ->
if array.length > 1
last = array.pop()
result = array.join(', ')
result += " and #{last}"
else
result = array.toString()
result
spectacular.utils.fill = (l=4, s=' ') ->
o = ''
o = "#{o}#{s}" while o.length < l
o
spectacular.utils.uniq = (arr) ->
newArr = []
newArr.push v for v in arr when v not in newArr
newArr
spectacular.utils.escapeDiff = (s) ->
utils.escape(
s
.replace(/<del>/g, '[[del]]')
.replace(/<\/del>/g, '[[/del]]')
.replace(/<ins>/g, '[[ins]]')
.replace(/<\/ins>/g, '[[/ins]]')
)
.replace(/\[\[del\]\]/g, '<del>')
.replace(/\[\[\/del\]\]/g, '</del>')
.replace(/\[\[ins\]\]/g, '<ins>')
.replace(/\[\[\/ins\]\]/g, '</ins>')
spectacular.utils.escape = (s) ->
n = s
n = n.replace(/&/g, '&')
n = n.replace(/</g, '<')
n = n.replace(/>/g, '>')
n = n.replace(/"/g, '"')
n
spectacular.utils.unescape = (s) ->
n = s
n = n.replace(/&/g, '&')
n = n.replace(/</g, '<')
n = n.replace(/>/g, '>')
n = n.replace(/"/g, '"')
n
spectacular.utils.indent = (string, ind=4) ->
s = ''
s = "#{s} " for i in [0..ind-1]
"#{s}#{string.replace /\n/g, "\n#{s}"}"
spectacular.utils.padRight = (string, pad=4) ->
string = string.toString()
string = " #{string}" while string.length < pad
string
spectacular.utils.toggle = (value, c1, c2) -> if value then c2 else c1
spectacular.utils.TAGS = if isCommonJS
diffStart: ''
diffEnd: ''
delStart: '\x1B[31m'
delEnd: '\x1B[39m'
insStart: '\x1B[32m'
insEnd: '\x1B[39m'
space: ''
else
diffStart: '<span class="diff">'
diffEnd: '</span>'
delStart: '<del>'
delEnd: '</del>'
insStart: '<ins>'
insEnd: '</ins>'
space: ''
spectacular.utils.ins = (str) ->
utils.TAGS.insStart + str + utils.TAGS.insEnd
spectacular.utils.del = (str) ->
utils.TAGS.delStart + str + utils.TAGS.delEnd
spectacular.utils.descOfNode = (actual) ->
if actual?
if actual.length?
utils.inspect Array::map.call actual, (e) -> e.outerHTML
else
utils.inspect actual.outerHTML
else
actual
# Javascript Diff Algorithm
# By John Resig (http://ejohn.org/)
# Modified by Chu Alan "sprite"
#
# Released under the MIT license.
#
# More Info:
# http://ejohn.org/projects/javascript-diff-algorithm/
spectacular.utils.diff = (o, n) ->
ns = new Object()
os = new Object()
i = 0
while i < n.length
if not ns[n[i]]? or typeof ns[n[i]] isnt 'object'
ns[n[i]] =
rows: new Array()
o: null
ns[n[i]].rows.push i
i++
i = 0
while i < o.length
if not os[o[i]]? or typeof os[n[i]] isnt 'object'
os[o[i]] =
rows: new Array()
n: null
os[o[i]].rows.push i
i++
for i of ns
if ns[i].rows.length is 1 and typeof (os[i]) isnt "undefined" and os[i].rows.length is 1
n[ns[i].rows[0]] =
text: n[ns[i].rows[0]]
row: os[i].rows[0]
o[os[i].rows[0]] =
text: o[os[i].rows[0]]
row: ns[i].rows[0]
i = 0
while i < n.length - 1
if n[i].text? and not n[i + 1].text? and n[i].row + 1 < o.length and not o[n[i].row + 1].text? and n[i + 1] is o[n[i].row + 1]
n[i + 1] =
text: n[i + 1]
row: n[i].row + 1
o[n[i].row + 1] =
text: o[n[i].row + 1]
row: i + 1
i++
i = n.length - 1
while i > 0
if n[i].text? and not n[i - 1].text? and n[i].row > 0 and not o[n[i].row - 1].text? and n[i - 1] is o[n[i].row - 1]
n[i - 1] =
text: n[i - 1]
row: n[i].row - 1
o[n[i].row - 1] =
text: o[n[i].row - 1]
row: i - 1
i--
o: o
n: n
spectacular.utils.stringDiff = (o, n) ->
return utils.del o if not n? or n.length is 0
return utils.ins n if not o? or o.length is 0
o = String(o).replace(/\s+$/, "")
n = String(n).replace(/\s+$/, "")
out = utils.diff((if o is "" then [] else o.split(/\s+/)), (if n is "" then [] else n.split(/\s+/)))
str = ""
oSpace = o.match(/\s+/g)
unless oSpace?
oSpace = [utils.TAGS.space]
else
oSpace.push utils.TAGS.space
nSpace = n.match(/\s+/g)
unless nSpace?
nSpace = [utils.TAGS.space]
else
nSpace.push utils.TAGS.space
if out.n.length is 0
i = 0
while i < out.o.length
str += utils.del utils.escape(out.o[i]) + oSpace[i]
i++
else
unless out.n[0].text?
n = 0
while n < out.o.length and not out.o[n].text?
str += utils.del utils.escape(out.o[n]) + oSpace[n]
n++
i = 0
while i < out.n.length
unless out.n[i].text?
str += utils.ins utils.escape(out.n[i]) + nSpace[i]
else
pre = ""
n = out.n[i].row + 1
while n < out.o.length and not out.o[n].text?
pre += utils.del utils.escape(out.o[n]) + oSpace[n]
n++
str += "" + out.n[i].text + nSpace[i] + pre
i++
str
spectacular.utils.inspect = (obj, depth=1, lookup=[]) ->
switch typeof obj
when 'string' then "'#{obj}'"
when 'number', 'boolean' then "#{obj}"
when 'object'
return 'null' unless obj?
return '[circular]' if obj in lookup
lookup.push obj
ind = utils.fill depth * 2
if utils.isArray obj
return '[]' if obj.length is 0
"[\n#{
obj.map((o) -> ind + utils.inspect o, depth+1, lookup).join ',\n'
}\n#{ind[0..-3]}]"
else
return '{}' if utils.keys(obj).length is 0
"{\n#{
("#{ind}#{k}: #{utils.inspect v, depth+1, lookup}" for k,v of obj when obj.hasOwnProperty k).join ',\n'
}\n#{ind[0..-3]}}"
when 'function'
if obj.name
obj.name
else if obj._name
obj._name
else
obj.toString()
else
'undefined'
spectacular.utils.objectDiff = (left, right, depth=1) ->
typeLeft = typeof left
typeRight = typeof right
unless typeLeft is typeRight
s = ''
s += utils.del utils.inspect(left, depth) if left?
s += utils.ins utils.inspect(right, depth) if right?
return s
switch typeLeft
when 'string' then utils.inspect utils.stringDiff left, right
when 'number', 'boolean' then utils.stringDiff left.toString(), right.toString()
when 'object'
unless utils.isArray(left) is utils.isArray(right)
return utils.del(utils.inspect left, depth) +
utils.ins(utils.inspect right, depth)
ind = utils.fill (depth) * 2
prevInd = utils.fill (depth - 1) * 2
if utils.isArray left
l = Math.max left.length, right.length
s = '['
a = for i in [0..l-1]
'\n' + ind + utils.objectDiff(left[i], right[i], depth + 1)
s += a.join(',') + "\n#{prevInd}]"
else
allKeys = utils.uniq utils.keys(left).concat utils.keys(right)
s = "{"
a = for k in allKeys
key = k + ': '
p = ''
unless right[k]
p = utils.del "#{key}#{left[k]}"
else unless left[k]
p = utils.ins "#{key}#{right[k]}"
else
p = key + utils.objectDiff(left[k], right[k], depth + 1)
'\n' + ind + p
s += a.join(',') + "\n#{prevInd}}"
spectacular.utils.compare = (actual, value, diff, noMessage=false) ->
switch typeof value
when 'object'
if utils.isArray actual
unless noMessage
diff.diff = utils.TAGS.diffStart + "#{diff.diff}\n\n#{utils.objectDiff actual, value}" + utils.TAGS.diffEnd
return false if actual.length isnt value.length
for v,i in value
unless utils.compare actual[i], v, diff, true
return false
return true
else
unless noMessage
diff.diff = utils.TAGS.diffStart + "#{diff.diff}\n\n#{utils.objectDiff actual, value}" + utils.TAGS.diffEnd
return false if utils.keys(actual).length isnt utils.keys(value).length
for k,v of value
unless utils.compare actual[k], v, diff, true
return false
return true
when 'string'
unless noMessage
diff.diff = utils.TAGS.diffStart + "#{diff.diff}\n\n'#{utils.stringDiff actual, value}'" + utils.TAGS.diffEnd
actual is value
else
actual is value
spectacular.utils.findStateMethodOrProperty = (obj, state) ->
camelizedVersion = "is#{utils.capitalize state}"
snakedVersion = "is_#{state}"
if obj[state]?
state
else if obj[camelizedVersion]?
camelizedVersion
else if obj[snakedVersion]?
snakedVersion
else
null
v._name = k for k,v of utils
spectacular.utils.colorize = (str, color, colorsEnabled=false) ->
if str? and colorsEnabled and str?[color] then str[color] else str