Created
January 14, 2010 11:03
-
-
Save josher19/277078 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* isType return true if obj is of class klass or a superclass of klass (such as Object). | |
* If type is a Function, will match if obj instanceof type (includes subclasses). | |
* If type is a String, will match if typeof(obj) === type or obj.constructor.name === type, | |
* so if tom is a Horse, which is a subclass of Animal, | |
* then isClass(tom, "Animal") is false but isClass(tom, Animal) is true. | |
* @Param {obj} Object to test | |
* @Param {type} Function or String with name or constructor of object. | |
* @Return {boolean} true if obj is of given type, using typeof, instanceof, or obj.constructor. | |
*/ | |
isType = function isType(obj, type) { | |
if (obj === null) return type === "null" || type === "object" || type === null; | |
if (typeof(obj) === "undefined") return type === "undefined" || typeof(type) === "undefined"; | |
return typeof(obj) === type || | |
obj.constructor === type || | |
(typeof(type) === "function" ? obj instanceof type : getType(obj) === type); | |
} | |
// Hack for IE 7 to find .constructor.name | |
function getFunc(func) { | |
var m=func.toString().match(/function ([^(]*)/); | |
return m && m.length > 1 && m[1] || func /*.toString() */ | |
} | |
function getName(cons) { return cons.name || getFunc(cons) ; } | |
// get constructor or typeof. Note that getType(null) == "object". | |
function getType(obj) { | |
return obj != null && getName(obj.constructor) || typeof(obj); | |
} | |
// This should actually be a Compile Time error while CoffeeScript is compiled, if possible. | |
function ArgTypeError(obj,type,error) { | |
return SyntaxError( | |
"Barf on args. Expected: " + (type.name || type) + | |
". Got: " + obj + | |
" of type " + | |
(obj === null ? "null" : | |
(obj.constructor ? (obj.constructor.name||obj.constructor) : obj)) + | |
(error ? "\n\n" + error.stack : "") | |
); | |
} | |
/// the rest is optional | |
/* Older version */ | |
isType_Long = function isType_Long (obj, klass) { | |
// try { | |
if (obj === null) return "null" === klass || null === klass; | |
if (typeof(obj) === "undefined") return "undefined" === klass || obj === klass; | |
if (obj.constructor === klass) return true; | |
//// uncomment next line to make Subclasses of Object return false, such as isType([], Object); | |
//if (obj.constructor === Object) return klass === Object; | |
//// uncomment next line to make isType(5, "NUMBER") return true ... 5 will only return true for "number" or Number | |
//if (typeof(obj) === klass.toString().toLowerCase()) return true; | |
if (typeof(obj) === klass) return true; // if klass is a String | |
// Should isType(tom, "Horse") return true? No easy way to make isType(tom, "Animal") true. | |
if (obj.constructor && typeof(klass) === "string") return obj.constructor.name === klass | |
if (typeof(klass) !== "function") return false; // instanceof throws errors unless it is a function. | |
// for inheritance: | |
if (obj instanceof klass) return true; | |
return false; | |
// } catch(error) { | |
// throw new ArgTypeError(obj,type,error); | |
// return false; | |
// } | |
} | |
//// TESTING FOLLOWS | |
try { | |
// Unit Testing w/o JSUnit. Call w/o any arguments | |
function test_isType(undef) { | |
// CoffeeScript examples | |
var Animal, Horse, Snake, __a, __b, sam, tom; | |
Animal = function Animal() { | |
}; | |
Animal.prototype.move = function move(meters) { | |
return (this.name + " moved " + meters + "m."); | |
}; | |
Snake = function Snake(name) { | |
var __a; | |
__a = this.name = name; | |
return Snake === this.constructor ? this : __a; | |
}; | |
__a = function(){}; | |
__a.prototype = Animal.prototype; | |
Snake.__superClass__ = Animal.prototype; | |
Snake.prototype = new __a(); | |
Snake.prototype.constructor = Snake; | |
Snake.prototype.move = function move() { | |
return ("Slithering...") + | |
Snake.__superClass__.move.call(this, 5); | |
}; | |
Horse = function Horse(name) { | |
var __b; | |
__b = this.name = name; | |
return Horse === this.constructor ? this : __b; | |
}; | |
__b = function(){}; | |
__b.prototype = Animal.prototype; | |
Horse.__superClass__ = Animal.prototype; | |
Horse.prototype = new __b(); | |
Horse.prototype.constructor = Horse; | |
Horse.prototype.move = function move() { | |
return ("Galloping..."); | |
return Horse.__superClass__.move.call(this, 45); | |
}; | |
sam = new Snake("Sammy the Python"); | |
tom = new Horse("Tommy the Palomino"); | |
//sam.move(); | |
//tom.move(); | |
//Boa extends Snake; | |
var Boa = function Boa(name) { | |
var __a; | |
__a = this.name = name; | |
return Boa === this.constructor ? this : __a; | |
}; | |
__c = function(){}; | |
__c.prototype = Snake.prototype; | |
Boa.__superClass__ = Snake.prototype; | |
Boa.prototype = new __c(); | |
Boa.prototype.constructor = Boa; | |
Boa.prototype.move = function move() { | |
return ("Sneaking...") + | |
Boa.__superClass__.move.call(this, 5); | |
}; | |
Animal.prototype.toString = function() { return this.name || this.constructor.name || "ANIMAL"; } | |
biggy = new Boa("VHC the Very Hungy Constrictor"); | |
// anonymous functions could cause problems | |
var Anon = function() {}; | |
var Anon2 = function() {}; | |
var nobody = new Anon(); | |
var who = new Anon2(); | |
testTypes = [true, false, 0, 123.4, "123", 'str', [], {},null,undefined, sam, tom, biggy, Anon, nobody, Anon2, who]; | |
if (!testTypes.map && self._) testTypes = _(testTypes); // need underscore for map for IE | |
//// Test Framework | |
// Error unless isType(obj, type) == bool | |
function expectClass(obj,type,bool) { | |
var res = isType(obj,type); | |
return res === bool ? res : /* throw */ new ArgTypeError(obj,type).message/* .stack */ | |
} | |
// count unique instances | |
function uniqCount(ra) { | |
//return ra | |
if (!ra || ra.length == 0) return []; | |
var i, uniqueArray=[], cnt=1; | |
uniqueArray.orig = ra; | |
for (i=1; i<=ra.length; ++i) { | |
if (ra[i] === ra[i-1]) ++cnt; else {uniqueArray.push([ra[i-1], cnt>1?"x"+cnt:""].join(" ")); cnt=1;} | |
} | |
return uniqueArray; | |
} | |
if (arguments.length > 0) undef = arguments[argument.length]; | |
var unset; | |
return uniqCount([ | |
"\nShould be false x9: ", | |
// false | |
expectClass(unset, null, false), | |
expectClass(unset, false, false), | |
expectClass(unset, 0, false), | |
expectClass("123", Number, false), | |
expectClass(123, String, false), | |
expectClass([1,2,3], String, false), | |
expectClass(null, "undefined", false), | |
expectClass({}, Array, false), | |
expectClass(arguments, Array, false), | |
"\nShould be true x28: ", | |
// javascript primitives and simple builtin classes | |
expectClass(true, Boolean, true), | |
expectClass(false, Boolean, true), | |
expectClass(0, Number, true), | |
expectClass(123, Number, true), | |
expectClass("123", String, true), | |
expectClass("", String, true), | |
expectClass([1,2,3], Array, true), | |
expectClass({}, Object, true), | |
expectClass(Math.PI, Number, true), | |
// typeof for primitives | |
expectClass(true, "boolean", true), | |
expectClass(false, "boolean", true), | |
expectClass(0, "number", true), | |
expectClass(123, "number", true), | |
expectClass("123", "string", true), | |
expectClass("", "string", true), | |
expectClass({}, "object", true), | |
expectClass([], "object", true), | |
// Null and undefined | |
expectClass(null, "null", true), | |
expectClass(null, null, true), | |
expectClass(undef, "undefined", true), | |
expectClass(unset, "undefined", true), | |
expectClass(unset, undefined, true), | |
// Object almost always true (because of inheritance / instanceof) | |
expectClass(new Boolean(false), Object, true), | |
expectClass(new Number(123.4), Object, true), | |
expectClass(new String("123"), Object, true), | |
expectClass([1,2,3], Object, true), | |
expectClass([1,2,3], "object", true), | |
[].constructor !== Object, | |
"\nShould be false x10: ", | |
// Except for primitives: | |
expectClass(true, Object, false), | |
expectClass(false, Object, false), | |
expectClass(123.4, Object, false), | |
expectClass("123", Object, false), | |
expectClass(new Number(123.4).toString(), Object, false), | |
expectClass(new String("123").toString(), Object, false), | |
expectClass({}, "Objective", false), | |
expectClass(nobody, Anon2, false), | |
expectClass(who, Anon, false), | |
expectClass(nobody, "Anon", false), // can't match anonymous functions | |
"\nAnonymous funcs can't be called by name x4:", | |
expectClass(Anon, Function, true), | |
expectClass(Anon, "function", true), | |
expectClass(nobody, Anon, true), | |
expectClass(who, Anon2, true), | |
"\nCheck if CoffeeScript Examples loaded: ", | |
// True if CoffeeScript Examples are loaded | |
typeof sam != "undefined" && expectClass(sam, Snake, true) , | |
typeof sam != "undefined" && expectClass(sam, Animal, true), | |
typeof tom != "undefined" && expectClass(tom, Horse, true), | |
typeof tom != "undefined" && expectClass(tom, Animal, true), | |
typeof biggy != "undefined" && expectClass(biggy, Snake, true), | |
typeof biggy != "undefined" && expectClass(biggy, Animal, true), | |
typeof biggy != "undefined" && expectClass(biggy, Animal, true), // biggy is an Animal Class | |
typeof biggy != "undefined" && expectClass(biggy, Boa, true), | |
typeof biggy != "undefined" && expectClass(biggy, Snake, true), | |
typeof biggy != "undefined" && expectClass(biggy, "object", true), | |
typeof biggy != "undefined" && expectClass(biggy, Object, true), | |
//typeof biggy != "undefined" && expectClass(biggy, "Boa", true), | |
expectClass(Boa, Function, true), // Function | |
"\nFalse x5 if CoffeeScript Examples are loaded: ", | |
typeof biggy != "undefined" && expectClass(biggy, Horse, false), // biggy not a Horse | |
typeof tom != "undefined" && expectClass(tom, Snake, false), // tom not a Snake | |
//typeof biggy != "undefined" && expectClass(biggy, "Animal", false), // biggy not an "Animal" | |
expectClass(biggy, null, false), | |
expectClass(biggy, undef, false), | |
expectClass(Boa, Boa, false), // Function | |
"\ngetTypes:", | |
testTypes.map && testTypes.map(getType), | |
testTypes.map && testTypes.map( function(obj) { | |
return isType(obj, getType(obj)); | |
}), | |
'\nComparing str="hello";', | |
'\nstr instanceof String:', | |
(str="hello", str instanceof String), | |
'\nisType(str, String):', | |
isType(str, String), | |
//"hmmm", | |
//Boa.name, | |
//biggy.constructor.name, | |
//[].constructor.name, | |
"\nDONE!!" | |
]); | |
} | |
/* | |
// Need underscore library for IE 7. | |
scr = document.createElement('script'); | |
scr.src = 'http://documentcloud.github.com/underscore/underscore-min.js'; | |
document.body.appendChild(scr); | |
*/ | |
test_isType().join("") | |
// .orig.map(function(item,ndx) { return "\n#" + ndx + ". " + item; }) | |
} catch(error) { | |
self.console ? console.log(error) : alert(error.message); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment