1 // ==========================================================================
  2 // Project:   SproutCore Costello - Property Observing Library
  3 // Copyright: ©2006-2011 Strobe Inc. and contributors.
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 
  9 /**
 10   Standard Error that should be raised when you try to modify a frozen object.
 11 
 12   @type Error
 13 */
 14 SC.FROZEN_ERROR = "Cannot modify a frozen object";
 15 
 16 /**
 17   @class
 18 
 19   The SC.Freezable mixin implements some basic methods for marking an object
 20   as frozen.  Once an object is frozen it should be read only.  No changes
 21   may be made the internal state of the object.
 22 
 23   Enforcement
 24   ---
 25 
 26   To fully support freezing in your subclass, you must include this mixin and
 27   override any method that might alter any property on the object to instead
 28   raise an exception.  You can check the state of an object by checking the
 29   isFrozen property.
 30 
 31   Although future versions of JavaScript may support language-level freezing
 32   object objects, that is not the case today.  Even if an object is freezable,
 33   it is still technically possible to modify the object, even though it could
 34   break other parts of your application that do not expect a frozen object to
 35   change.  It is, therefore, very important that you always respect the
 36   isFrozen property on all freezable objects.
 37 
 38   Example
 39 
 40   The example below shows a simple object that implement the SC.Freezable
 41   protocol.
 42 
 43         Contact = SC.Object.extend(SC.Freezable, {
 44 
 45           firstName: null,
 46 
 47           lastName: null,
 48 
 49           // swaps the names
 50           swapNames: function() {
 51             if (this.get('isFrozen')) throw new Error(SC.FROZEN_ERROR);
 52             var tmp = this.get('firstName');
 53             this.set('firstName', this.get('lastName'));
 54             this.set('lastName', tmp);
 55             return this;
 56           }
 57 
 58         });
 59 
 60         c = Context.create({ firstName: "John", lastName: "Doe" });
 61         c.swapNames();  => returns c
 62         c.freeze();
 63         c.swapNames();  => EXCEPTION
 64 
 65   Copying
 66   ---
 67 
 68   Usually the SC.Freezable protocol is implemented in cooperation with the
 69   SC.Copyable protocol, which defines a frozenCopy() method that will return
 70   a frozen object, if the object implements this method as well.
 71 
 72 */
 73 SC.Freezable = /** @scope SC.Freezable.prototype */ {
 74 
 75   /**
 76     Walk like a duck.
 77 
 78     @type Boolean
 79   */
 80   isFreezable: YES,
 81 
 82   /**
 83     Set to YES when the object is frozen.  Use this property to detect whether
 84     your object is frozen or not.
 85 
 86     @type Boolean
 87   */
 88   isFrozen: NO,
 89 
 90   /**
 91     Freezes the object.  Once this method has been called the object should
 92     no longer allow any properties to be edited.
 93 
 94     @returns {Object} receiver
 95   */
 96   freeze: function() {
 97     // NOTE: Once someone actually implements Object.freeze() in the browser,
 98     // add a call to that here also.
 99 
100     if (this.set) this.set('isFrozen', YES);
101     else this.isFrozen = YES;
102     return this;
103   }
104 
105 };
106 
107 
108 // Add to Array
109 SC.mixin(Array.prototype, SC.Freezable);
110