util = require 'util' #========================================================= exports.BaseError = BaseError = (msg, constructor) -> Error.captureStackTrace? @, @constructor @message = msg or 'Error' util.inherits BaseError, Error BaseError.prototype.name = "BaseError" #========================================================= to_lower = (s) -> (s[0].toUpperCase() + s[1...].toLowerCase()) c_to_camel = (s) -> (to_lower p for p in s.split /_/).join '' make_error_klass = (k, code, default_msg) -> ctor = (msg) -> BaseError.call(this, (msg or default_msg), this.constructor) this.istack = [] this.code = code this util.inherits ctor, BaseError ctor.prototype.name = k ctor.prototype.inspect = () -> "[#{k}: #{this.message} (code #{this.code})]" ctor #========================================================= exports.make_errors = make_errors = (d) -> out = msg : {} name : {} code : {} # Constants d.OK = "Success" errno = 100 for k,msg of d if k isnt "OK" enam = (c_to_camel k) + "Error" val = errno++ out[enam] = make_error_klass enam, val, msg else val = 0 out[k] = val out.msg[k] = out.msg[val] = msg out.name[k] = out.name[val] = k out.code[k] = val out #========================================================= ipush = (e, msg) -> if msg? e.istack = [] unless e.istack? e.istack.push msg # Error short-circuit connector exports.make_esc = make_esc = (gcb, where) -> (lcb) -> (err, args...) -> if not err? then lcb args... else if not gcb.__esc gcb.__esc = true ipush err, where gcb err #================================================ # A class-based Error short-circuiter; output OK exports.EscOk = class EscOk constructor : (@gcb, @where) -> bailout : () -> if @gcb t = @gcb @gcb = null t false check_ok : (cb) -> (ok, args...) => if not ok then @bailout() else cb args... check_err : (cb) -> (err, args...) => if err? ipush err, @where @bailout() else cb args... check_non_null : (cb) -> (args...) => if not args[0]? then @bailout() else cb args... #================================================ exports.EscErr = class EscErr constructor : (@gcb, @where) -> finish : (err) -> if @gcb t = @gcb @gcb = null t err check_ok : (cb, eclass = Error, emsg = null) -> (ok, args...) -> if not ok err = new eclass emsg ipush err, @where @finish err else cb args... check_err : (cb) -> (err, args...) -> if err? ipush err, @where @finish err else cb args... #================================================ # # A class for canceling an expensive operation. # You can either generate a generic Error or one of the # Class of your choosing. # exports.Canceler = class Canceler constructor : (@klass = Error) -> @_canceled = false is_canceled : () -> @_canceled is_ok : () -> not @_canceled cancel : () -> @_canceled = true err : () -> if @_canceled then (new @klass "Aborted") else null #================================================ # Chain callback cb and f # Call f first, and throw away whatever it calls back with. # Then call cb, and pass it the args the chain was called back # with. This is useful for doing a cleanup routine before # something exits. exports.chain = (cb, f) -> (args...) -> f () -> cb args... #================================================ # Chain callback cb and f # Call f first, and see if it calls back with a first positional error. # The error is either the original error, or the error from f. # Call cb back with args0 unless there was an error in cleanup and no # error in the original. exports.chain_err = (cb, f) -> (args0...) -> f (args1...) -> cb (if args1[0]? and not(args0[0]?) then args1 else args0)... #================================================