1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  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 // @global SC
  8 
  9 sc_require('ext/function');
 10 
 11 /**
 12   @class
 13 
 14   An error, used to represent an error state.
 15 
 16   Many API's within SproutCore will return an instance of this object whenever
 17   they have an error occur.  An error includes an error code, description,
 18   and optional human readable label that indicates the item that failed.
 19 
 20   Depending on the error, other properties may also be added to the object
 21   to help you recover from the failure.
 22 
 23   You can pass error objects to various UI elements to display the error in
 24   the interface. You can easily determine if the value returned by some API is
 25   an error or not using the helper SC.ok(value).
 26 
 27   Faking Error Objects
 28   ---
 29 
 30   You can actually make any object you want to be treated like an Error object
 31   by simply implementing two properties: isError and errorValue.  If you
 32   set isError to YES, then calling SC.ok(obj) on your object will return NO.
 33   If isError is YES, then SC.val(obj) will return your errorValue property
 34   instead of the receiver.
 35 
 36   When using SC.typeOf(obj), SC.T_ERROR will only be returned if the obj
 37   is an instance of SC.Error
 38 
 39   @extends SC.Object
 40   @since SproutCore 1.0
 41 */
 42 SC.Error = SC.Object.extend(
 43 /** @scope SC.Error.prototype */ {
 44 
 45   /**
 46     error code.  Used to designate the error type.
 47 
 48     @type Number
 49   */
 50   code: -1,
 51 
 52   /**
 53     Human readable description of the error.  This can also be a non-localized
 54     key.
 55 
 56     @type String
 57   */
 58   message: '',
 59 
 60   /**
 61     The value the error represents.  This is used when wrapping a value inside
 62     of an error to represent the validation failure.
 63 
 64     @type Object
 65   */
 66   errorValue: null,
 67 
 68   /**
 69     The original error object.  Normally this will return the receiver.
 70     However, sometimes another object will masquerade as an error; this gives
 71     you a way to get at the underlying error.
 72 
 73     @type SC.Error
 74   */
 75   errorObject: function() {
 76     return this;
 77   }.property().cacheable(),
 78 
 79   /**
 80     Throw the error.
 81 
 82     @type SC.Error
 83   */
 84   'throw': function() {
 85     var error = this.toString();
 86     SC.Logger.error(error);
 87 
 88     throw new Error(error);
 89   },
 90 
 91   /**
 92     The error stacktrace.
 93 
 94     @type SC.Error
 95   */
 96   trace: function() {
 97     return (new Error()).trace;
 98   }.property().cacheable(),
 99 
100   /**
101     Human readable name of the item with the error.
102 
103     @type String
104   */
105   label: null,
106 
107   /** @private */
108   toString: function() {
109     return "SC.Error:%@:%@ (%@)".fmt(SC.guidFor(this), this.get('message'), this.get('code'));
110   },
111 
112   /**
113     Walk like a duck.
114 
115     @type Boolean
116   */
117   isError: YES
118 });
119 
120 SC.Error.mixin({
121 
122   /**
123     Creates a new SC.Error instance with the passed description, label, and
124     code.  All parameters are optional.
125 
126     @param description {String} human readable description of the error
127     @param label {String} human readable name of the item with the error
128     @param code {Number} an error code to use for testing.
129     @returns {SC.Error} new error instance.
130   */
131   desc: function(description, label, value, code) {
132     var opts = { message: description } ;
133     if (label !== undefined) opts.label = label ;
134     if (code !== undefined) opts.code = code ;
135     if (value !== undefined) opts.errorValue = value ;
136     return this.create(opts) ;
137   },
138 
139   /**
140     Throw a new SC.Error instance with the passed description, label, and
141     code.  All parameters are optional.
142 
143     @param description {String} human readable description of the error
144     @param label {String} human readable name of the item with the error
145     @param code {Number} an error code to use for testing.
146     @returns {SC.Error} new error instance.
147   */
148   'throw': function(description, label, value, code) {
149     this.desc.apply(this, arguments).throw();
150   }
151 
152 });
153 
154 /**
155   Shorthand form of the SC.Error.desc method.
156 
157   @param description {String} human readable description of the error
158   @param label {String} human readable name of the item with the error
159   @param code {Number} an error code to use for testing.
160   @returns {SC.Error} new error instance.
161 */
162 SC.$error = function(description, label, value, c) {
163   return SC.Error.desc(description, label, value, c);
164 };
165 
166 /**
167   Shorthand form of the SC.Error.throw method.
168 
169   @param description {String} human readable description of the error
170   @param label {String} human readable name of the item with the error
171   @param code {Number} an error code to use for testing.
172   @returns {SC.Error} new error instance.
173 */
174 SC.throw = function(description, label, value, c) {
175   SC.Error.throw(description, label, value, c);
176 };
177 
178 /** @private */
179 SC.$throw = SC.throw;
180 
181 /**
182   Returns NO if the passed value is an error object or false.
183 
184   @param {Object} ret object value
185   @returns {Boolean}
186 */
187 SC.ok = function(ret) {
188   return (ret !== false) && !(ret && ret.isError);
189 };
190 
191 /** @private */
192 SC.$ok = SC.ok;
193 
194 /**
195   Returns the value of an object.  If the passed object is an error, returns
196   the value associated with the error; otherwise returns the receiver itself.
197 
198   @param {Object} obj the object
199   @returns {Object} value
200 */
201 SC.val = function(obj) {
202   if (obj && obj.isError) {
203     return obj.get ? obj.get('errorValue') : null ; // Error has no value
204   } else return obj ;
205 };
206 
207 /** @private */
208 SC.$val = SC.val;
209 
210 // STANDARD ERROR OBJECTS
211 
212 /**
213   Standard error code for errors that do not support multiple values.
214 
215   @type Number
216 */
217 SC.Error.HAS_MULTIPLE_VALUES = -100 ;
218