Skip to content

Instantly share code, notes, and snippets.

@josher19
Created January 14, 2010 11:03
Show Gist options
  • Save josher19/277078 to your computer and use it in GitHub Desktop.
Save josher19/277078 to your computer and use it in GitHub Desktop.
/**
* 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