Patches accessor functions into future for the browsers I'm supporting.
authordsc <david.schoonover@gmail.com>
Thu, 9 Dec 2010 22:08:10 +0000 (14:08 -0800)
committerdsc <david.schoonover@gmail.com>
Thu, 9 Dec 2010 22:08:10 +0000 (14:08 -0800)
src/future.js

index 5531d95..f30db9d 100644 (file)
@@ -1,15 +1,23 @@
 (function(_Object, _Array, _Function){
 
-var P           = "prototype"
-,   AP          = _Array[P]
-,   FP          = _Function[P]
-,   slice       = AP.slice
-,   objToString = _Object[P].toString
+var P  = "prototype"
+,   FP = _Function[P]
+
+,   AP     = _Array[P]
+,   _slice = AP.slice
+
+,   OP          = _Object[P]
+,   hasOwn      = OP.hasOwnProperty
+,   getget      = OP.__lookupGetter__
+,   getset      = OP.__lookupSetter__
+,   setget      = OP.__defineGetter__
+,   setset      = OP.__defineSetter__
+,   objToString = OP.toString
 ;
 
 if ( !_Array.slice ) {
     _Array.slice = function slice(a){
-        return slice.apply(a, slice.call(arguments, 1));
+        return _slice.apply(a, _slice.call(arguments, 1));
     };
 }
 
@@ -80,30 +88,138 @@ if ( !AP.reduce ) {
     }
 }
 
-
+if ( !_Array.isArray ) {
+    _Array.isArray = function isArray(o) { return objToString.call(o) === '[object Array]'; };
+}
 
 // JavaScript 1.8.5
 
 if ( !FP.bind ) {
     FP.bind = function bind( context ){
         var fn = this,
-            args = slice.call(arguments, 1);
+            args = _slice.call(arguments,1);
         return function(){
-            return fn.apply(context, args.concat( slice.call(arguments,0) ));
+            return fn.apply(context, args.concat( _slice.call(arguments,0) ));
         };
     };
 }
 
 if ( !_Object.getPrototypeOf ) {
-    _Object.getPrototypeOf =
+    _Object['getPrototypeOf'] =
         ( (typeof "".__proto__ === "object")
-            ? function(object){ return object.__proto__; }
-            : function(object){ return object.constructor[P]; }
+            ? function getPrototypeOf(o){ return o.__proto__; }
+            : function getPrototypeOf(o){ return o.constructor[P]; }
         );
 }
 
-if ( !_Array.isArray ) {
-    _Array.isArray = function isArray(o) { return objToString.call(o) === '[object Array]'; };
+if ( !_Object.keys ) {
+    _Object['keys'] =
+        function keys(o){
+            var k, keys = [];
+            for ( k in o )
+                if (hasOwn.call(o,k)) keys.push(k);
+            return keys;
+        };
+}
+
+if ( !_Object.defineProperty ) {
+    
+    function isFunction(f){
+        return typeof f === "function";
+    }
+    
+    function cleanDescriptor(desc){
+        if (typeof desc !== "object" || desc === null)
+            throw new TypeError("Property description must be an object: "+desc);
+        
+        var d = {}
+        ,   get = desc.get, set = desc.set
+        ,   hasValue = hasOwn.call(desc, 'value')
+        ;
+        
+        if (hasOwn.call(desc, 'get') && get !== undefined) {
+            if (!isFunction(get))
+                throw new TypeError("Getter must be a function: "+get);
+            d.get = get;
+        }
+        
+        if (hasOwn.call(desc, 'set') && set !== undefined) {
+            if (!isFunction(set))
+                throw new TypeError("Setter must be a function: "+set);
+            d.set = set;
+        }
+        
+        if ( hasValue && (d.get || d.set) )
+            throw new TypeError("Invalid property. A property cannot both have accessors and be writable or have a value: "+desc);
+        
+        if ( hasValue )
+            d.value = desc.value;
+        
+        return d;
+    }
+    
+    _Object['defineProperty'] =
+        function defineProperty(o, prop, desc){
+            if (typeof o !== "object" || o === null)
+                throw new TypeError("Object.defineProperty called on non-object: "+o);
+            
+            desc = cleanDescriptor(desc);
+            if ( 'value' in desc ) {
+                delete o[prop];
+                o[prop] = desc.value;
+            } else {
+                if ( desc.get ) setget.call(o, prop, desc.get);
+                if ( desc.set ) setset.call(o, prop, desc.set);
+            }
+            
+            return o;
+        };
+    
+    _Object['defineProperties'] =
+        function defineProperties(o, props) {
+            if (typeof o !== "object" || o === null)
+                throw new TypeError("Object.defineProperty called on non-object: "+o);
+            
+            props = Object(props);
+            var k, descs = {};
+            
+            // Perform all the error checks before mutating anything
+            for (k in props)
+                if (hasOwn.call(props,k)) descs[k] = cleanDescriptor(props[k]);
+            
+            // Now we can start changing things
+            for (k in descs)
+                _Object.defineProperty(o, k, descs[k]);
+            
+            return o;
+        }
+    
+    _Object['getOwnPropertyDescriptor'] = 
+        function getOwnPropertyDescriptor(o, prop){
+            if (typeof o !== "object" || o === null)
+                throw new TypeError("Object.getOwnPropertyDescriptor called on non-object: "+o);
+            
+            if ( !hasOwn.call(o,prop) )
+                return undefined;
+            
+            var getter = getget.call(o, prop)
+            ,   setter = getset.call(o, prop)
+            ,   desc   = { 'configurable':true, 'enumerable':true };
+            
+            // Data Descriptor
+            if (getter === undefined && setter === undefined) {
+                desc['value']    = o[prop];
+                desc['writable'] = true;
+            
+            // Accessor Descriptor
+            } else {
+                if (getter) desc['get'] = getter;
+                if (setter) desc['set'] = setter;
+            }
+            
+            return desc;
+        };
 }
 
+
 })(Object, Array, Function);