preventLoop = function(inputFunction){ if(!_.isFunction(inputFunction)) throw new Meteor.Error("Not a function", "preventLoop can only take a function as an argument"); //store a private array of arguments we have been given without returning //if we try to visit the same argument twice before resolving its value //we are in a dependency loop and need to GTFO var visitedArgs = []; return function(argument){ var value; //we're still evaluating this attribute, must be in a loop if(_.contains(visitedArgs, argument)) { console.warn("dependency loop detected"); return NaN; } else{ //push this skill to the list of visited skills //we can't visit it again unless it returns first visitedArgs.push(argument); } try{ value = inputFunction.call(this, argument); } finally{ //this argument returns or fails, pull it from the array visitedArgs = _.without(visitedArgs, argument); } return value; } };