UNPKG

node-simple-router

Version:

Yet another minimalistic router for node.js

330 lines (252 loc) 10.1 kB
######################################################################################################################################## # The Promise Resolution Procedure resolve = (promise, x) -> ## If promise and x refer to the same object, reject promise with a TypeError as the reason. if promise is x return reject promise, new TypeError "promise and resolution value can't be the same object" ## If x is a promise, adopt its state if x?.constructor.name is 'Promise' if x.isPending() return x._dependants.push promise if x.isFulfilled() return fulfill promise, x.value if x.isRejected() return reject promise, x.reason ## If x is an object or a function ## Pending for now... ## Else, fulfill this way... #console.log "resolve: fulfilling promise with", x return fulfill promise, x ######################################################################################################################################## # Fulfillment Procedure fulfill = (promise, value) -> return promise unless promise.isPending() promise._state = Promise.states.fulfilled promise._value = value fireHandlers promise, value promise._dependants.forEach (dependant) -> resolve dependant, value promise ######################################################################################################################################## # Rejection Procedure reject = (promise, reason) -> return promise unless promise.isPending() promise._state = Promise.states.rejected promise._reason = reason fireHandlers promise, reason promise._dependants.forEach (dependant) -> reject dependant, reason promise ######################################################################################################################################## # fireHandlers Procedure fireHandlers = (promise, what) -> switch promise._state when Promise.states.rejected handlers = promise._rejectHandlers when Promise.states.fulfilled handlers = promise._fulfillHandlers else return handlers.forEach (handler, index) -> return if promise._handlerCalls[index] isnt 0 promise._handlerCalls[index] += 1 cascade_promise = promise._retPromises[index] if handler?.constructor.name is "Function" #setImmediate -> #console.log "Resolving cascade promise through handler invocation result" try result = handler what #console.log "Result of handler invocation is #{result}" if promise._state is Promise.states.fulfilled resolve cascade_promise, result else reject cascade_promise, result catch e reject cascade_promise, e else #console.log "Resolving cascade promise with received argument (named what)" if promise._state is Promise.states.fulfilled resolve cascade_promise, what else reject cascade_promise, what promise ######################################################################################################################################## # The Promise class class Promise "Returns a promise object which complies (really?) with promises A+ spec" @states: {pending: 0, rejected: -1, fulfilled: 1} ## ** Define value and reason getters Object.defineProperties @prototype, value: get: -> @_value reason: get: -> @_reason state: get: -> @_state ## **constructor/initializer** method of Promise class constructor: (@_options = {}) -> Promise.init @ @init: (obj) -> obj._state = Promise.states.pending obj._fulfillHandlers = [] obj._rejectHandlers = [] obj._retPromises = [] obj._handlerCalls = [] obj._dependants = [] obj ## **then** method of Promise class then: (onFulfilled, onRejected) => @_fulfillHandlers.push onFulfilled or null @_rejectHandlers.push onRejected or null retPromise = new Promise level: @_options.level + 1 @_retPromises.push retPromise if @isPending() @_handlerCalls.push 0 else @_handlerCalls.push 1 if @isRejected() reject retPromise, @_reason if @isFulfilled() if onFulfilled?.constructor.name is "Function" resolve retPromise, onFulfilled(@_value) else resolve retPromise, @_value #console.log "Returning from Promise.then a new promise with level: #{retPromise._options.level}" retPromise ## **done, fail** sugar methods for calling then done: (onFulfilled) => @then onFulfilled, null fail: (onRejected) => @then null, onRejected ## **utility methods** of Promise object isRejected: => if @_state is Promise.states.rejected then true else false isFulfilled: => if @_state is Promise.states.fulfilled then true else false isPending: => if @_state is Promise.states.pending then true else false isResolved: => not @isPending() # The Deferred class class Deferred "Promise manager object" constructor: -> @_promise = new Promise level: 0 promise: => @_promise resolve: (value) => setImmediate => return if not @_promise.isPending() resolve @_promise, value reject: (reason) => setImmediate => return if not @_promise.isPending() reject @_promise, reason # The Deferred creation function defer = -> new Deferred # Exports PromiseA Object module?.exports = PromiseA = {Promise, Deferred, defer} ## End of objects definition, beginning of tests # Run standalone test if it isnt being required if not module?.parent thousand_sep = (num, sep = ",") -> return num.toString() unless num.toString().length > 3 resp = num.toString().split('').reverse().join('').replace(/(\d{3})/g, "$1#{sep}").split('').reverse().join('') if resp.charAt(0) is sep then resp.slice(1) else resp pad = (stri, quantity, direction = "r", padchar = " ") -> stri = stri.toString() if stri.constructor.name is "Number" len = stri.length dif = quantity - len return stri if dif <= 0 padstri = (padchar for n in [1..dif]).join '' if direction is "r" then "#{stri}#{padstri}" else "#{padstri}#{stri}" testFunc = -> #util = require 'util' d = defer() setTimeout ( -> d.resolve 10), 100 p = d.promise() ### setTimeout (-> console.log "\n" console.log util.inspect p._fulfillHandlers console.log util.inspect p._retPromises[0]?._fulfillHandlers console.log util.inspect p._retPromises[0]?._retPromises[0]?._fulfillHandlers console.log "\n"), 50 ### console.log "Running test function" console.log "---------------------\n" p ### testFunc() .then( (number) -> console.log "Promise level 0 received number #{number}" number + 1 (err) => console.log "First promise triggered an error:", err.toString() ) .then( (number) -> console.log "Promise level 1 received number #{number}" number + 1 ) .then( (number) -> console.log "Promise level 2 received number #{number}" number * 3 ) .then( (resp) -> console.log "Promise level 3 received number #{resp}" resp ) ### fs = require 'fs' readDir = -> d = defer() fs.readdir process.cwd(), (err, files) -> if err console.log "ERROR reading directory: " else console.log "Current working directory: #{process.cwd()}\n" if err then d.reject err else d.resolve files console.log "Running file system test function" console.log "---------------------------------\n" d.promise() readDir() .then( (files) -> len = files.length - 1 stats = [] d = defer() p = d.promise() files.forEach (file, index) -> fs.stat file, (err, stat) -> return d.reject err if err stats[index] = stat if index is len console.log "Retrieved", stats.length, "items.\n" d.resolve [files, stats] p (err) -> console.log "ERROR reading current directory: #{err.message}" ) .then( (arrs) -> [files, stats] = arrs fileSizes = [] for file, index in files fileSizes.push name: ('' + file + if stats[index]?.isDirectory() then ' [DIR]' else ''), size: stats[index]?.size, isFile: stats[index]?.isFile() fileSizes.sort (info1, info2) -> info1.isFile - info2.isFile for fileInfo in fileSizes console.log pad(fileInfo.name, 40), " --- ", pad(thousand_sep(fileInfo.size), 40, "l"), "bytes." fileSizes (err) -> console.log "Something horrible happened while processing file names and stats:", err.message ) .then( (fileSizes) -> info = "\nTotal Size of files in #{process.cwd()}: " info += "#{thousand_sep(fileSizes.reduce ((acum, fileInfo) -> acum + if fileInfo.isFile then fileInfo.size else 0), 0)} bytes.\n" console.log info (err) -> console.log "Something horrible happened while processing total files size:", err.message )