drews-mixins
Version:
A couple underscore.js mixins
403 lines (353 loc) • 11.6 kB
text/coffeescript
#make sure you compile iwth -cw not -cwb
#this project used to have async helpers until i found @caolan's
#nimble project
failCount = 0
passCount = 0
count = 0
failedMessages = []
class AssertionError extends Error
constructor: (options) ->
@name = 'AssertionError'
@message = options.message
@actual = options.actual
@expected = options.expected
@operator = options.operator
toString: () =>
"test"
[@name + ':', @message].join ' '
# wait for
define "drews-mixins", ->
_ = require "underscore";
exports = {}
exports.asyncEx = (len, cb) ->
_.wait len, -> cb null, len
exports.asyncFail = (len, cb) ->
_.wait len, -> cb len
exports.doneMaker = () ->
allDoneCallback = ->
results = []
allDone = (cb) ->
allDoneCallback = cb
id = _.uniqueId()
length = 0
doneLength = 0
live = true
done = () ->
myLength = length
length++
return do (myLength) -> (err, result) ->
if live is false then return
doneLength++
if err then allDoneCallback err, results
results[myLength] = result
if doneLength is length
allDoneCallback null, results
live = false
[done, allDone]
#think about old wrapper objects sometime
# some backbone.js-like events, consider using node.js like ones
# compare backbones events with nodes events
# https://github.com/joyent/node/blob/master/lib/events.js
# https://github.com/documentcloud/backbone/blob/master/backbone.js
# https://github.com/maccman/spine/blob/master/spine.js
exports.on = (obj, ev, callback) ->
calls = obj._callbacks || obj._callbacks = {}
list = calls[ev] || (calls[ev] = [])
list.push callback
obj._events = obj._callbacks
obj
exports.removeListener = (obj, ev, callback) ->
if (!ev)
obj._callbacks = {}
obj._events = obj._callbacks
else if calls = obj._callbacks
if !callback
calls[ev] = []
else
list = calls[ev]
if !list then return obj
for item, i in list
if callback == list[i]
list.splice i, 1 #spine.js
#list[i] = null #backbone.js
# then backbone clearns the nulls later
# node.js copies the array when triggering
# so the once isn't a problem
break
obj
#TODO async events? wait 0, ->
trigger = (obj, eventName, args...) ->
both = 2
id = _.uniqueId()
if !(calls = obj._callbacks) then return obj
while both--
ev = if both then eventName else "all"
list = calls[ev]
if list=calls[ev]
# then next line coppies the array
# so it doesn't get shrinked by a once
# backbone.js has maybe a more efficient way
# where unbind sets it to null, and here it slices them
# if they are null
list = list.slice() #stole this from node.js events
for item, i in list
callback = list[i]
if not callback
else
args = if both then args else args.unshift(eventName)
# maby have obj as the first param?
callback.apply obj, args
exports.trigger = trigger
exports.emit = exports.trigger
exports.addListener = exports.on
exports.unbind = exports.removeListener
exports.once = (obj, ev, callback) ->
g = (args...) ->
_.removeListener obj, ev, g
callback.apply obj, args
_.addListener obj, ev, g
exports.graceful = (errorFunc, callback) ->
if _.isArray errorFunc
extraArgs = _.s errorFunc, 1
errorFunc = errorFunc[0]
else
extraArgs = []
makeHandler = (func) ->
(err, results...) ->
if err
#return errorFunc null, err, extraArgs...
return errorFunc.apply null, null, null
func results...
if callback
makeHandler callback
else
makeHandler
#simple substring/slice functionality
# for arrays and strings
# very similar to php's subst and php's array_slice
exports.s = (val, start, end) ->
need_to_join = false
ret = []
if _.isString val
val = val.split ""
need_to_join = true
if start >= 0
else
start = val.length + start
if _.isUndefined(end)
ret = val.slice start
else
if end < 0
end = val.length + end
else
end = end + start
ret = val.slice start, end
if need_to_join
ret.join ""
else
ret
exports.startsWith = (str, with_what) ->
_.s(str, 0, with_what.length) == with_what
exports.rnd = (low, high) -> Math.floor(Math.random() * (high-low+1)) + low
exports.time = () ->
(new Date()).getTime()
exports.replaceBetween = (str, start, between, end) ->
pos = str.indexOf start
if pos is -1 then return str
endpos = str.indexOf end, pos + start.length
if endpos is -1 then return str
return _.s(str, 0, pos + start.length) + between + _.s(str, endpos)
exports.trimLeft = (obj) ->
obj.toString().replace(/^\s+/, "")
exports.trimRight = (obj) ->
obj.toString().replace(/\s+$/, "")
exports.isNumeric = (str) ->
if _.isNumber(str)
return true
if _.s(str, 0, 1) == "-"
return true
if _.s(str, 0, 1).match(/\d/)
return true
else
return false
exports.capitalize = (str) ->
str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();
# this is just a wrapper for setTimeout.
# it puts the miliseconds first to it's more
# natural to write in coffeescript
exports.wait = (miliseconds, func) ->
setTimeout func, miliseconds
times = (numb, func) ->
for i in [1..numb]
func i
exports.interval = (miliseconds, func) ->
setInterval func, miliseconds
exports.compareArrays = (left, right) ->
#not yet optimized
inLeftNotRight = []
inRightNotLeft = []
inBoth = []
for item in left
if item in right
inBoth.push item
else
inLeftNotRight.push item
for item in right
if item not in left
inRightNotLeft.push item
return [inLeftNotRight, inRightNotLeft, inBoth]
exports.pacManMapMaker = (left, right, top, bottom) ->
1
# todo make a little map maker
exports.populateArray = (obj, key, value) ->
if not _.isArray obj[key]
obj[key] = []
obj[key].push value
setLocation = (stuff, cb) ->
log = (args...) -> console.log args...
exports.log = log
hosty = null
postMessageHelper = (yourWin, origin, methods={}) ->
self = {}
host = {}
# methods that can be called on me
self.addMethods = (fns) ->
_.extend methods, fns
self.addMethods
bind: (event, callback) ->
#?????
events = {}
callbacks = {}
#origin = yourWin.location.origin # cant do
#origin = _origin # or something
#???
#???
self.trigger = ->
self.write = -> #sream data
# then need a self.ondata self.onend callbacks
# trigger self, "data"
# trigger self, "end"
# or something else
self.trigger = (event, params...) ->
# self.bind not done yet
self.bind = (event, callback) ->
id = _.uuid()
subscribe =
channel: event
id: id
subscribeString = JSON.stringify subscribe
events[event] ||= []
events[event].push callback
yourWin.postMessage subscribeString, origin
self.call = (method, params..., callback) ->
id = _.uuid()
request =
method: method
params: params
id: id
requestString = JSON.stringify request
callbacks[id] = callback
yourWin.postMessage requestString, origin
$(window).bind "message", (e) ->
e = e.originalEvent #only needed for jQuery
if e.origin != origin and origin != "*"
return
message = JSON.parse e.data
if "result" of message
# i called another window & they're responding
{id, error, result} = message
callbacks[id]? error, result
else if "method" of message
# another window is calling me
{method, params, id} = message
# by defualt makeing it async
methods[method]? params..., (err=null, result=null) ->
response =
error: err
result: result
id: id
responseString = JSON.stringify response
#e.source.postMessage
yourWin.postMessage responseString, origin
self
# win is an iframe.contentWindow or other window
exports.postMessageHelper = postMessageHelper
exports.uuid = () ->
#http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
`'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {var r = Math.random()*16|0,v=c=='x'?r:r&0x3|0x8;return v.toString(16);});`
#maybe to one for add to array
addToObject = (obj, key, value) ->
obj[key] = value
addToObjectMaker = (obj) ->
(key, value) ->
addToObject obj, key, value
exports.addToObjectMaker = addToObjectMaker
jsonHttpMaker = (method) ->
http = (args..., callback) ->
[url, args, contentType] = args
#TODO: why does the {} work?
data = JSON.stringify args || {}
$.ajax
url: "#{url}"
type: method || "POST"
contentType: 'application/json' || contentType
data: data
dataType: 'json'
processData: false
success: (data) -> callback null, data
error: (data) ->
callback JSON.parse data.responseText
exports.jsonPost = jsonHttpMaker "POST"
exports.jsonGet = jsonHttpMaker "GET"
exports.jsonHttpMaker = jsonHttpMaker
# get = ajaxMaker "get"
# asyncTests = (batches, tests) ->
# before = addToObjectMaker()
# test = addToObjectMaker()
# prepareTests = () ->
# _.series batches
###
do ->
giveBackTheCard = takeACard()
giveBackTheCard()
###
exports.getAssertCount = -> count
exports.getFailCount = -> failCount
exports.getPassCount = -> passCount
exports.setAssertCount = (newCount) -> count = newCount
exports.setPassCount = (newCount) -> passCount = newCount
exports.setFailCount = (newCount) -> failCount = newCount
exports.getFailedMessages = () -> failedMessages
exports.assertFail = (actual, expected, message, operator, stackStartFunction) ->
failCount++
count++
failedMessages.push message
e =
message: message
actual: actual
expected: expected
operator: operator
stackStartFunction: stackStartFunction
console.log e
#throw new AssertionError e
exports.assertPass = (actual, expected, message, operator, stackStartFunction) ->
passCount++
count++
exports.assertOk = (value, message) ->
if !!!value
_.assertFail value, true, message, '==', exports.assertOk
else
_.assertPass value, true, message, "==", _.assertOk
exports.assertEqual = (actual, expected, message) ->
if `actual != expected`
_.assertFail actual, expected, message, '==', exports.assertEqual
else
_.assertPass actual, expected, message, "==", exports.assertEqual
exports.assertNotEqual = (actual, expected, message) ->
if `actual == expected`
_.assertFail actual, expected, message, '!=', exports.assertNotEqual
else
_.assertPass actual, expected, message, '!=', exports.assertNotEqual
_.mixin exports
return exports
#root._ if root._ is defined in parent script