sproutcore 0.9.14 → 0.9.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. data/History.txt +43 -0
  2. data/Manifest.txt +12 -3
  3. data/bin/sc-build +19 -3
  4. data/bin/sc-install +5 -0
  5. data/bin/sc-remove +5 -0
  6. data/bin/sc-update +5 -0
  7. data/frameworks/prototype/prototype.js +267 -230
  8. data/frameworks/sproutcore/HISTORY +281 -135
  9. data/frameworks/sproutcore/controllers/array.js +133 -22
  10. data/frameworks/sproutcore/controllers/collection.js +4 -5
  11. data/frameworks/sproutcore/controllers/object.js +8 -2
  12. data/frameworks/sproutcore/core.js +361 -159
  13. data/frameworks/sproutcore/{foundation → debug}/unittest.js +3 -3
  14. data/frameworks/sproutcore/english.lproj/detect-browser +1 -1
  15. data/frameworks/sproutcore/english.lproj/theme.css +2 -2
  16. data/frameworks/sproutcore/foundation/application.js +6 -1
  17. data/frameworks/sproutcore/foundation/benchmark.js +37 -11
  18. data/frameworks/sproutcore/foundation/date.js +1 -1
  19. data/frameworks/sproutcore/foundation/enumerator.js +105 -0
  20. data/frameworks/sproutcore/foundation/object.js +19 -20
  21. data/frameworks/sproutcore/foundation/responder.js +1 -1
  22. data/frameworks/sproutcore/foundation/set.js +164 -57
  23. data/frameworks/sproutcore/foundation/string.js +151 -47
  24. data/frameworks/sproutcore/foundation/utils.js +84 -3
  25. data/frameworks/sproutcore/lib/collection_view.rb +1 -0
  26. data/frameworks/sproutcore/license.js +28 -0
  27. data/frameworks/sproutcore/mixins/array.js +73 -209
  28. data/frameworks/sproutcore/mixins/delegate_support.js +1 -1
  29. data/frameworks/sproutcore/mixins/enumerable.js +1006 -0
  30. data/frameworks/sproutcore/mixins/observable.js +153 -84
  31. data/frameworks/sproutcore/mixins/selection_support.js +13 -1
  32. data/frameworks/sproutcore/models/record.js +74 -27
  33. data/frameworks/sproutcore/models/store.js +7 -3
  34. data/frameworks/sproutcore/server/rails_server.js +82 -0
  35. data/frameworks/sproutcore/server/rest_server.js +178 -0
  36. data/frameworks/sproutcore/{foundation → server}/server.js +101 -48
  37. data/frameworks/sproutcore/tests/core/guidFor.rhtml +114 -0
  38. data/frameworks/sproutcore/tests/foundation/array.rhtml +6 -7
  39. data/frameworks/sproutcore/tests/foundation/set.rhtml +254 -0
  40. data/frameworks/sproutcore/tests/mixins/enumerable.rhtml +421 -0
  41. data/frameworks/sproutcore/tests/mixins/observable.rhtml +127 -0
  42. data/frameworks/sproutcore/tests/models/model.rhtml +23 -22
  43. data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +2 -2
  44. data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +112 -109
  45. data/frameworks/sproutcore/tests/views/view/frame.rhtml +91 -88
  46. data/frameworks/sproutcore/validators/date.js +1 -7
  47. data/frameworks/sproutcore/views/collection/collection.js +7 -2
  48. data/frameworks/sproutcore/views/list_item.js +141 -3
  49. data/frameworks/sproutcore/views/split.js +14 -11
  50. data/frameworks/sproutcore/views/view.js +9 -6
  51. data/lib/sproutcore/build_tools/html_builder.rb +19 -3
  52. data/lib/sproutcore/build_tools/resource_builder.rb +9 -3
  53. data/lib/sproutcore/bundle.rb +21 -0
  54. data/lib/sproutcore/bundle_manifest.rb +64 -20
  55. data/lib/sproutcore/helpers/capture_helper.rb +2 -2
  56. data/lib/sproutcore/library.rb +33 -9
  57. data/lib/sproutcore/merb/bundle_controller.rb +16 -5
  58. data/lib/sproutcore/version.rb +1 -1
  59. data/lib/sproutcore/view_helpers.rb +1 -1
  60. data/{sc-config.rb → sc-config} +5 -2
  61. metadata +24 -5
@@ -0,0 +1,254 @@
1
+ <% content_for('final') do %>
2
+ <script>
3
+
4
+ Test.context("creating SC.Set instances", {
5
+
6
+ setup: function() {
7
+ // create objects...
8
+ a = { name: "a" } ;
9
+ b = { name: "b" } ;
10
+ c = { name: "c" } ;
11
+ },
12
+
13
+ teardown: function() {
14
+ delete a;
15
+ delete b;
16
+ delete c;
17
+ },
18
+
19
+ "new SC.Set() should create empty set": function() {
20
+ var set = new SC.Set() ;
21
+ assertEqual(set.length, 0) ;
22
+ },
23
+
24
+ "new SC.Set([1,2,3]) should create set with three items in them": function(){
25
+ var set = new SC.Set([a,b,c]) ;
26
+ set.length.shouldEqual(3) ;
27
+ set.contains(a).shouldEqual(YES) ;
28
+ set.contains(b).shouldEqual(YES) ;
29
+ set.contains(c).shouldEqual(YES) ;
30
+ },
31
+
32
+ "SC.Set.create() is an alias for new SC.Set()": function() {
33
+ var set = SC.Set.create() ;
34
+ set.length.shouldEqual(0) ;
35
+
36
+ var set = SC.Set.create([a,b,c]) ;
37
+ set.length.shouldEqual(3) ;
38
+ set.contains(a).shouldEqual(YES) ;
39
+ set.contains(b).shouldEqual(YES) ;
40
+ set.contains(c).shouldEqual(YES) ;
41
+ },
42
+
43
+ "new SC.Set() should accept anything that implements SC.Array": function() {
44
+ var arrayLikeObject = SC.Object.create(SC.Array, {
45
+
46
+ _content: [a,b,c],
47
+ length: 3,
48
+ objectAt: function(idx) { return this._content[idx]; }
49
+ }) ;
50
+
51
+ var set = SC.Set.create(arrayLikeObject) ;
52
+ set.length.shouldEqual(3) ;
53
+ set.contains(a).shouldEqual(YES) ;
54
+ set.contains(b).shouldEqual(YES) ;
55
+ set.contains(c).shouldEqual(YES) ;
56
+ },
57
+
58
+ "new SC.Set() should accept anything that looks like an array, even if it does not implement SC.Array": function() {
59
+ var arrayLikeObject = { length: 3, '0': a, '1': b, '2': c } ;
60
+
61
+ var set = SC.Set.create(arrayLikeObject) ;
62
+ set.length.shouldEqual(3) ;
63
+ set.contains(a).shouldEqual(YES) ;
64
+ set.contains(b).shouldEqual(YES) ;
65
+ set.contains(c).shouldEqual(YES) ;
66
+ }
67
+
68
+ });
69
+
70
+ // The tests below also end up testing the contains() method pretty
71
+ // exhaustively.
72
+ Test.context("SC.Set.add + SC.Set.contains", {
73
+
74
+ setup: function() {
75
+ set = SC.Set.create() ;
76
+ },
77
+
78
+ teardown: function() {
79
+ delete set ;
80
+ },
81
+
82
+ "should add an SC.Object": function() {
83
+ var obj = SC.Object.create() ;
84
+
85
+ var oldLength = set.length ;
86
+ set.add(obj);
87
+ assertEqual(set.contains(obj), YES, "contains()") ;
88
+ assertEqual(oldLength+1, set.length, "new set length") ;
89
+ },
90
+
91
+ "should add a regular hash": function() {
92
+ var obj = {} ;
93
+
94
+ var oldLength = set.length ;
95
+ set.add(obj);
96
+ assertEqual(set.contains(obj), YES, "contains()") ;
97
+ assertEqual(oldLength+1, set.length, "new set length") ;
98
+ },
99
+
100
+ "should add a string": function() {
101
+ var obj = "String!" ;
102
+
103
+ var oldLength = set.length ;
104
+ set.add(obj);
105
+ assertEqual(set.contains(obj), YES, "contains()") ;
106
+ assertEqual(oldLength+1, set.length, "new set length") ;
107
+ },
108
+
109
+ "should add a number": function() {
110
+ var obj = 23 ;
111
+
112
+ var oldLength = set.length ;
113
+ set.add(obj);
114
+ assertEqual(set.contains(obj), YES, "contains()") ;
115
+ assertEqual(oldLength+1, set.length, "new set length") ;
116
+ },
117
+
118
+ "should add a bool": function() {
119
+ var obj = true ;
120
+
121
+ var oldLength = set.length ;
122
+ set.add(obj);
123
+ assertEqual(set.contains(obj), YES, "contains()") ;
124
+ assertEqual(oldLength+1, set.length, "new set length") ;
125
+ },
126
+
127
+ "should add a function": function() {
128
+ var obj = function() { return "Test function"; } ;
129
+
130
+ var oldLength = set.length ;
131
+ set.add(obj);
132
+ assertEqual(set.contains(obj), YES, "contains()") ;
133
+ assertEqual(oldLength+1, set.length, "new set length") ;
134
+ },
135
+
136
+ "should NOT add a null": function() {
137
+ set.add(null) ;
138
+ assertEqual(set.length, 0) ;
139
+ assertEqual(set.contains(null), NO) ;
140
+ },
141
+
142
+ "should NOT add an undefined": function() {
143
+ set.add(undefined) ;
144
+ assertEqual(set.length, 0) ;
145
+ assertEqual(set.contains(undefined), NO) ;
146
+ }
147
+
148
+ });
149
+
150
+ Test.context("SC.Set.remove + SC.Set.contains", {
151
+
152
+ // generate a set with every type of object, but none of the specific
153
+ // ones we add in the tests below...
154
+ setup: function() {
155
+ set = SC.Set.create([
156
+ SC.Object.create({ dummy: YES }),
157
+ { isHash: YES },
158
+ "Not the String",
159
+ 16, false]) ;
160
+ },
161
+
162
+ teardown: function() {
163
+ delete set ;
164
+ },
165
+
166
+ "should remove an SC.Object and reduce length": function() {
167
+ var obj = SC.Object.create() ;
168
+ set.add(obj);
169
+ assertEqual(set.contains(obj), YES) ;
170
+ var oldLength = set.length ;
171
+
172
+ set.remove(obj) ;
173
+ assertEqual(NO, set.contains(obj), "should be removed") ;
174
+ assertEqual(oldLength-1, set.length, "should be 1 shorter") ;
175
+ },
176
+
177
+ "should remove a regular hash and reduce length": function() {
178
+ var obj = {} ;
179
+ set.add(obj);
180
+ assertEqual(set.contains(obj), YES) ;
181
+ var oldLength = set.length ;
182
+
183
+ set.remove(obj) ;
184
+ assertEqual(NO, set.contains(obj), "should be removed") ;
185
+ assertEqual(oldLength-1, set.length, "should be 1 shorter") ;
186
+ },
187
+
188
+ "should remove a string and reduce length": function() {
189
+ var obj = "String!" ;
190
+ set.add(obj);
191
+ assertEqual(set.contains(obj), YES) ;
192
+ var oldLength = set.length ;
193
+
194
+ set.remove(obj) ;
195
+ assertEqual(NO, set.contains(obj), "should be removed") ;
196
+ assertEqual(oldLength-1, set.length, "should be 1 shorter") ;
197
+ },
198
+
199
+ "should remove a number and reduce length": function() {
200
+ var obj = 23 ;
201
+ set.add(obj);
202
+ assertEqual(set.contains(obj), YES) ;
203
+ var oldLength = set.length ;
204
+
205
+ set.remove(obj) ;
206
+ assertEqual(NO, set.contains(obj), "should be removed") ;
207
+ assertEqual(oldLength-1, set.length, "should be 1 shorter") ;
208
+ },
209
+
210
+ "should remove a bool and reduce length": function() {
211
+ var obj = true ;
212
+ set.add(obj);
213
+ assertEqual(set.contains(obj), YES) ;
214
+ var oldLength = set.length ;
215
+
216
+ set.remove(obj) ;
217
+ assertEqual(NO, set.contains(obj), "should be removed") ;
218
+ assertEqual(oldLength-1, set.length, "should be 1 shorter") ;
219
+ },
220
+
221
+ "should remove a function and reduce length": function() {
222
+ var obj = function() { return "Test function"; } ;
223
+ set.add(obj);
224
+ assertEqual(set.contains(obj), YES) ;
225
+ var oldLength = set.length ;
226
+
227
+ set.remove(obj) ;
228
+ assertEqual(NO, set.contains(obj), "should be removed") ;
229
+ assertEqual(oldLength-1, set.length, "should be 1 shorter") ;
230
+ },
231
+
232
+ "should NOT remove a null": function() {
233
+ var oldLength = set.length ;
234
+ set.remove(null) ;
235
+ assertEqual(oldLength, set.length) ;
236
+ },
237
+
238
+ "should NOT remove an undefined": function() {
239
+ var oldLength = set.length ;
240
+ set.remove(undefined) ;
241
+ assertEqual(oldLength, set.length) ;
242
+ },
243
+
244
+ "should ignore removing an object not in the set": function() {
245
+ var obj = SC.Object.create() ;
246
+ var oldLength = set.length ;
247
+ set.remove(obj) ;
248
+ assertEqual(oldLength, set.length) ;
249
+ }
250
+
251
+ });
252
+
253
+ </script>
254
+ <% end %>
@@ -0,0 +1,421 @@
1
+ <% content_for('final') do %>
2
+ <script>
3
+
4
+ // Define some standard tests. We need to test both on a custom enumerable
5
+ // and on a real Array.
6
+ var EnumerableTests = {
7
+
8
+ "should get enumerator that iterates through objects": function() {
9
+ var e = src.enumerator() ;
10
+ assertNotEqual(e, null, 'enumerator must not be null');
11
+
12
+ var idx = 0;
13
+ var cur ;
14
+ while(cur = e.nextObject()) {
15
+ assertEqual(src.objectAt(idx), cur, "object at index %@".fmt(idx)) ;
16
+ idx++;
17
+ }
18
+
19
+ assertEqual(src.get('length'), idx) ;
20
+ },
21
+
22
+ "should run forEach() to go through objects": function() {
23
+ var idx = 0;
24
+
25
+ // save for testing later
26
+ var items = [] ;
27
+ var indexes = [] ;
28
+ var arrays = [] ;
29
+ var targets = [] ;
30
+
31
+ src.forEach(function(item, index, array) {
32
+ items.push(item);
33
+ indexes.push(index);
34
+ arrays.push(array);
35
+ targets.push(this);
36
+ }, this);
37
+
38
+ var len = src.get('length') ;
39
+ for(var idx=0;idx<len;idx++) {
40
+ assertEqual(items[idx], src.objectAt(idx)) ;
41
+ assertEqual(indexes[idx], idx) ;
42
+ assertEqual(arrays[idx], src) ;
43
+ assertEqual(targets[idx], this) ;
44
+ }
45
+ },
46
+
47
+ "should map to values while passing proper params": function() {
48
+ var idx = 0;
49
+
50
+ // save for testing later
51
+ var items = [] ;
52
+ var indexes = [] ;
53
+ var arrays = [] ;
54
+ var targets = [] ;
55
+
56
+ var mapped = src.map(function(item, index, array) {
57
+ items.push(item);
58
+ indexes.push(index);
59
+ arrays.push(array);
60
+ targets.push(this);
61
+
62
+ return index ;
63
+ }, this);
64
+
65
+ var len = src.get('length') ;
66
+ for(var idx=0;idx<len;idx++) {
67
+ assertEqual(src.objectAt(idx), items[idx], "items") ;
68
+ assertEqual(idx, indexes[idx], "indexes") ;
69
+ assertEqual(src, arrays[idx], 'arrays') ;
70
+ assertEqual(SC.guidFor(this), SC.guidFor(targets[idx]), "this") ;
71
+
72
+ assertEqual(idx, mapped[idx], "mapped") ;
73
+ }
74
+ },
75
+
76
+ "should filter to items that return for callback": function() {
77
+ var idx = 0;
78
+
79
+ // save for testing later
80
+ var items = [] ;
81
+ var indexes = [] ;
82
+ var arrays = [] ;
83
+ var targets = [] ;
84
+
85
+ var filtered = src.filter(function(item, index, array) {
86
+ items.push(item);
87
+ indexes.push(index);
88
+ arrays.push(array);
89
+ targets.push(this);
90
+
91
+ return item.gender === "female" ;
92
+ }, this);
93
+
94
+ var len = src.get('length') ;
95
+ for(var idx=0;idx<len;idx++) {
96
+ assertEqual(src.objectAt(idx), items[idx], "items") ;
97
+ assertEqual(idx, indexes[idx], "indexes") ;
98
+ assertEqual(src, arrays[idx], 'arrays') ;
99
+ assertEqual(SC.guidFor(this), SC.guidFor(targets[idx]), "this") ;
100
+ }
101
+
102
+ filtered.length.shouldEqual(1) ;
103
+ filtered[0].first.shouldEqual("Jenna") ;
104
+ },
105
+
106
+ "should return true if function for every() returns true": function() {
107
+ var idx = 0;
108
+
109
+ // save for testing later
110
+ var items = [] ;
111
+ var indexes = [] ;
112
+ var arrays = [] ;
113
+ var targets = [] ;
114
+
115
+ var result = src.every(function(item, index, array) {
116
+ items.push(item);
117
+ indexes.push(index);
118
+ arrays.push(array);
119
+ targets.push(this);
120
+
121
+ return true ;
122
+ }, this);
123
+
124
+ var len = src.get('length') ;
125
+ for(var idx=0;idx<len;idx++) {
126
+ assertEqual(src.objectAt(idx), items[idx], "items") ;
127
+ assertEqual(idx, indexes[idx], "indexes") ;
128
+ assertEqual(src, arrays[idx], 'arrays') ;
129
+ assertEqual(SC.guidFor(this), SC.guidFor(targets[idx]), "this") ;
130
+ }
131
+
132
+ assertEqual(result, YES) ;
133
+ },
134
+
135
+ "should return false if one function for every() returns false": function() {
136
+ var result = src.every(function(item, index, array) {
137
+ return item.gender === "male" ;
138
+ }, this);
139
+ assertEqual(result, NO) ;
140
+ },
141
+
142
+ "should return false if all functions for some() returns false": function() {
143
+ var idx = 0;
144
+
145
+ // save for testing later
146
+ var items = [] ;
147
+ var indexes = [] ;
148
+ var arrays = [] ;
149
+ var targets = [] ;
150
+
151
+ var result = src.some(function(item, index, array) {
152
+ items.push(item);
153
+ indexes.push(index);
154
+ arrays.push(array);
155
+ targets.push(this);
156
+
157
+ return false ;
158
+ }, this);
159
+
160
+ var len = src.get('length') ;
161
+ for(var idx=0;idx<len;idx++) {
162
+ assertEqual(src.objectAt(idx), items[idx], "items") ;
163
+ assertEqual(idx, indexes[idx], "indexes") ;
164
+ assertEqual(src, arrays[idx], 'arrays') ;
165
+ assertEqual(SC.guidFor(this), SC.guidFor(targets[idx]), "this") ;
166
+ }
167
+
168
+ assertEqual(result, NO) ;
169
+ },
170
+
171
+ "should return true if one function for some() returns true": function() {
172
+ var result = src.some(function(item, index, array) {
173
+ return item.gender !== "male" ;
174
+ }, this);
175
+ assertEqual(result, YES) ;
176
+ },
177
+
178
+
179
+ "should mapProperty for all items": function() {
180
+ var mapped = src.mapProperty("first") ;
181
+ var idx ;
182
+ var len = src.get('length') ;
183
+ for(idx=0;idx<len;idx++) {
184
+ mapped[idx].shouldEqual(src.objectAt(idx).first) ;
185
+ }
186
+ },
187
+
188
+ "should filterProperty with match": function() {
189
+ var filtered = src.filterProperty("gender", "female") ;
190
+ filtered.length.shouldEqual(1) ;
191
+ filtered[0].first.shouldEqual("Jenna") ;
192
+ },
193
+
194
+ "should filterProperty with default bool": function() {
195
+ var filtered = src.filterProperty("californian") ;
196
+ filtered.length.shouldEqual(1) ;
197
+ filtered[0].first.shouldEqual("Jenna") ;
198
+ },
199
+
200
+
201
+
202
+ "everyProperty should return true if all properties macth": function() {
203
+ var ret = src.everyProperty('visited', 'Prague') ;
204
+ assertEqual(YES, ret, "visited") ;
205
+ },
206
+
207
+ "everyProperty should return true if all properties true": function() {
208
+ var ret = src.everyProperty('ready') ;
209
+ assertEqual(YES, ret, "ready") ;
210
+ },
211
+
212
+ "everyProperty should return false if any properties false": function() {
213
+ var ret = src.everyProperty('gender', 'male') ;
214
+ assertEqual(NO, ret, "ready") ;
215
+ },
216
+
217
+
218
+ "someProperty should return false if all properties not match": function() {
219
+ var ret = src.someProperty('visited', 'Timbuktu') ;
220
+ assertEqual(NO, ret, "visited") ;
221
+ },
222
+
223
+ "someProperty should return false if all properties false": function() {
224
+ var ret = src.someProperty('doneTravelling') ;
225
+ assertEqual(NO, ret, "doneTravelling") ;
226
+ },
227
+
228
+ "someProperty should return true if any properties true": function() {
229
+ var ret = src.someProperty('first', 'Charles') ;
230
+ assertEqual(YES, ret, "first") ;
231
+ },
232
+
233
+ "invokeWhile should call method on member objects until return does not match": function() {
234
+ var ret = src.invokeWhile("OK", "invokeWhileTest", "item2") ;
235
+ assertEqual("FAIL", ret, "return value");
236
+ },
237
+
238
+ "get @min(balance) should return the minimum balance": function() {
239
+ assertEqual(1, src.get('@min(balance)')) ;
240
+ },
241
+
242
+ "get @max(balance) should return the maximum balance": function() {
243
+ assertEqual(4, src.get('@max(balance)')) ;
244
+ },
245
+
246
+ "get @minObject(balance) should return the record with min balance": function() {
247
+ assertEqual(src.objectAt(0), src.get('@minObject(balance)')) ;
248
+ },
249
+
250
+ "get @maxObject(balance) should return the record with the max balance": function() {
251
+ assertEqual(src.objectAt(0), src.get('@maxObject(balance)')) ;
252
+ },
253
+
254
+ "get @sum(balance) should return the sum of the balances.": function() {
255
+ assertEqual(1+2+3+4, src.get("@sum(balance)")) ;
256
+ },
257
+
258
+ "get @average(balance) should return the average of balances": function() {
259
+ assertEqual((1+2+3+4)/4, src.get("@average(balance)")) ;
260
+ },
261
+
262
+ "should invoke custom reducer": function() {
263
+ // install reducer method
264
+ src.reduceTest = reduceTestFunc ;
265
+ assertEqual("TEST", src.get("@test")) ;
266
+ assertEqual("prop", src.get("@test(prop)")) ;
267
+ },
268
+ "should trigger observer of reduced prop when array changes once property retrieved once": function() {
269
+
270
+ // get the property...this will install the reducer property...
271
+ src.get("@max(balance)") ;
272
+
273
+ // install observer
274
+ var observedValue = null ;
275
+ src.addObserver("@max(balance)", function() {
276
+ observedValue = src.get("@max(balance)");
277
+ }) ;
278
+
279
+ src.addProbe('[]') ;
280
+ src.addProbe('@max(balance)');
281
+
282
+ // add record to array
283
+ src.pushObject({
284
+ first: "John",
285
+ gender: "male",
286
+ californian: NO,
287
+ ready: YES,
288
+ visited: "Paris",
289
+ balance: 5
290
+ }) ;
291
+
292
+ //SC.NotificationQueue.flush() ; // force observers to trigger
293
+
294
+ // observed value should now be set because the reduced property observer
295
+ // was triggered when we changed the array contents.
296
+ assertEqual(5, observedValue) ;
297
+ },
298
+
299
+ "should trigger observer of reduced prop when array changes - even if you never retrieved the property before": function() {
300
+ // install observer
301
+ var observedValue = null ;
302
+ src.addObserver("@max(balance)", function() {
303
+ observedValue = src.get("@max(balance)");
304
+ }) ;
305
+
306
+ // add record to array
307
+ src.pushObject({
308
+ first: "John",
309
+ gender: "male",
310
+ californian: NO,
311
+ ready: YES,
312
+ visited: "Paris",
313
+ balance: 5
314
+ }) ;
315
+
316
+ //SC.NotificationQueue.flush() ; // force observers to trigger
317
+
318
+ // observed value should now be set because the reduced property observer
319
+ // was triggered when we changed the array contents.
320
+ assertEqual(5, observedValue) ;
321
+ }
322
+
323
+ };
324
+
325
+ var DummyEnumerable = SC.Object.extend(SC.Enumerable, {
326
+
327
+ content: [],
328
+
329
+ length: function() { return this.content.length; }.property(),
330
+
331
+ objectAt: function(idx) { return this.content[idx]; },
332
+
333
+ nextObject: function(idx) { return this.content[idx]; },
334
+
335
+ // add support for reduced properties.
336
+ unknownProperty: function(key, value) {
337
+ var ret = this.reducedProperty(key, value) ;
338
+ if (ret === undefined) {
339
+ if (value !== undefined) this[key] = value ;
340
+ ret = value ;
341
+ }
342
+ return ret ;
343
+ },
344
+
345
+ pushObject: function(object) {
346
+ this.content.push(object) ;
347
+ this.enumerableContentDidChange() ;
348
+ }
349
+
350
+ }) ;
351
+
352
+ var runFunc = function(a,b) { return ['DONE', a, b]; } ;
353
+ var invokeWhileOK = function() { return "OK"; } ;
354
+ var invokeWhileNotOK = function() { return "FAIL"; };
355
+ var reduceTestFunc = function(prev, item, idx, e, pname) { return pname||'TEST'; } ;
356
+
357
+ var CommonArray = [
358
+ { first: "Charles",
359
+ gender: "male",
360
+ californian: NO,
361
+ ready: YES,
362
+ visited: "Prague",
363
+ doneTravelling: NO,
364
+ run: runFunc,
365
+ invokeWhileTest: invokeWhileOK,
366
+ balance: 1
367
+ },
368
+
369
+ { first: "Jenna",
370
+ gender: "female",
371
+ californian: YES,
372
+ ready: YES,
373
+ visited: "Prague",
374
+ doneTravelling: NO,
375
+ run: runFunc,
376
+ invokeWhileTest: invokeWhileOK,
377
+ balance: 2
378
+ },
379
+
380
+ { first: "Peter",
381
+ gender: "male",
382
+ californian: NO,
383
+ ready: YES,
384
+ visited: "Prague",
385
+ doneTravelling: NO,
386
+ run: runFunc,
387
+ invokeWhileTest: invokeWhileNotOK,
388
+ balance: 3
389
+ },
390
+
391
+ { first: "Chris",
392
+ gender: "male",
393
+ californian: NO,
394
+ ready: YES,
395
+ visited: "Prague",
396
+ doneTravelling: NO,
397
+ run: runFunc,
398
+ invokeWhileTest: invokeWhileOK,
399
+ balance: 4
400
+ } ] ;
401
+
402
+ Test.context("Real Array", SC.mixin(EnumerableTests, {
403
+
404
+ setup: function() { src = CommonArray.clone(); },
405
+
406
+ teardown: function() { src = null ; }
407
+
408
+ }));
409
+
410
+ Test.context("DummyEnumerable", SC.mixin(EnumerableTests, {
411
+
412
+ setup: function() {
413
+ src = DummyEnumerable.create({ content: CommonArray }) ;
414
+ },
415
+
416
+ teardown: function() { src = null ; }
417
+
418
+ }));
419
+
420
+ </script>
421
+ <% end %>