@quenty/observablecollection 6.0.0-canary.367.e9fdcbc.0 → 6.0.0

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.
package/CHANGELOG.md CHANGED
@@ -3,7 +3,123 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- # [6.0.0-canary.367.e9fdcbc.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.16.0...@quenty/observablecollection@6.0.0-canary.367.e9fdcbc.0) (2023-06-05)
6
+ # [6.0.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.26.0...@quenty/observablecollection@6.0.0) (2023-10-11)
7
+
8
+
9
+ ### Features
10
+
11
+ * Make observable sorted list stable and use binary search ([6ca9dc7](https://github.com/Quenty/NevermoreEngine/commit/6ca9dc74724e8446aceac432dca95a647c3ef0c2))
12
+
13
+
14
+
15
+
16
+
17
+ # [5.26.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.25.0...@quenty/observablecollection@5.26.0) (2023-09-21)
18
+
19
+ **Note:** Version bump only for package @quenty/observablecollection
20
+
21
+
22
+
23
+
24
+
25
+ # [5.25.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.24.0...@quenty/observablecollection@5.25.0) (2023-09-04)
26
+
27
+
28
+ ### Features
29
+
30
+ * Add ObservableMapList.new() and fix unit tests ([84e16ed](https://github.com/Quenty/NevermoreEngine/commit/84e16ed86af9bbc1ad19486f0298a9f7f3484b3e))
31
+
32
+
33
+
34
+
35
+
36
+ # [5.24.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.23.0...@quenty/observablecollection@5.24.0) (2023-08-23)
37
+
38
+
39
+ ### Bug Fixes
40
+
41
+ * Handle items after connecting to events ([800364b](https://github.com/Quenty/NevermoreEngine/commit/800364b77ce0b7fc42ad141846265657876512f8))
42
+
43
+
44
+ ### Features
45
+
46
+ * ObservableMap uses subscription table ([fa39e53](https://github.com/Quenty/NevermoreEngine/commit/fa39e539c809e77f7d9539442727c48505f98ea1))
47
+
48
+
49
+
50
+
51
+
52
+ # [5.23.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.22.0...@quenty/observablecollection@5.23.0) (2023-08-01)
53
+
54
+ **Note:** Version bump only for package @quenty/observablecollection
55
+
56
+
57
+
58
+
59
+
60
+ # [5.22.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.21.0...@quenty/observablecollection@5.22.0) (2023-07-28)
61
+
62
+ **Note:** Version bump only for package @quenty/observablecollection
63
+
64
+
65
+
66
+
67
+
68
+ # [5.21.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.20.0...@quenty/observablecollection@5.21.0) (2023-07-23)
69
+
70
+ **Note:** Version bump only for package @quenty/observablecollection
71
+
72
+
73
+
74
+
75
+
76
+ # [5.20.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.19.1...@quenty/observablecollection@5.20.0) (2023-07-15)
77
+
78
+
79
+ ### Features
80
+
81
+ * Add :Observe() API calls to a variety of systems and allow Blend to :Observe() stuff ([ca29c68](https://github.com/Quenty/NevermoreEngine/commit/ca29c68164dfdaf136e9168faf48f487bed26088))
82
+
83
+
84
+
85
+
86
+
87
+ ## [5.19.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.19.0...@quenty/observablecollection@5.19.1) (2023-07-11)
88
+
89
+ **Note:** Version bump only for package @quenty/observablecollection
90
+
91
+
92
+
93
+
94
+
95
+ # [5.19.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.18.1...@quenty/observablecollection@5.19.0) (2023-07-10)
96
+
97
+ **Note:** Version bump only for package @quenty/observablecollection
98
+
99
+
100
+
101
+
102
+
103
+ ## [5.18.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.18.0...@quenty/observablecollection@5.18.1) (2023-07-03)
104
+
105
+
106
+ ### Bug Fixes
107
+
108
+ * Fix missing dependency in ObservableCollection ([f6e7834](https://github.com/Quenty/NevermoreEngine/commit/f6e7834c02142dbe6c941e7cf4226cfd723ed0b1))
109
+
110
+
111
+
112
+
113
+
114
+ # [5.18.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.17.0...@quenty/observablecollection@5.18.0) (2023-06-17)
115
+
116
+ **Note:** Version bump only for package @quenty/observablecollection
117
+
118
+
119
+
120
+
121
+
122
+ # [5.17.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@5.16.0...@quenty/observablecollection@5.17.0) (2023-06-05)
7
123
 
8
124
  **Note:** Version bump only for package @quenty/observablecollection
9
125
 
package/README.md CHANGED
@@ -17,5 +17,5 @@ A set of observable collections, such as sets, maps, sorted lists, and more. Gre
17
17
 
18
18
  ## Installation
19
19
  ```
20
- npm install @quenty/observableset --save
20
+ npm install @quenty/observablecollection --save
21
21
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/observablecollection",
3
- "version": "6.0.0-canary.367.e9fdcbc.0",
3
+ "version": "6.0.0",
4
4
  "description": "A set of observable collections, such as sets, maps, sorted lists, and more.",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -27,17 +27,22 @@
27
27
  "Quenty"
28
28
  ],
29
29
  "dependencies": {
30
- "@quenty/brio": "8.13.0",
31
- "@quenty/loader": "6.2.1",
32
- "@quenty/maid": "2.5.0",
33
- "@quenty/promise": "6.5.0",
34
- "@quenty/rx": "7.11.0",
35
- "@quenty/signal": "2.4.0",
36
- "@quenty/symbol": "2.2.0",
37
- "@quenty/valueobject": "8.0.0-canary.367.e9fdcbc.0"
30
+ "@quenty/baseobject": "^7.0.0",
31
+ "@quenty/brio": "^9.0.0",
32
+ "@quenty/loader": "^7.0.0",
33
+ "@quenty/maid": "^2.6.0",
34
+ "@quenty/promise": "^7.0.0",
35
+ "@quenty/rx": "^8.0.0",
36
+ "@quenty/signal": "^3.0.0",
37
+ "@quenty/steputils": "^3.3.0",
38
+ "@quenty/symbol": "^2.2.0",
39
+ "@quenty/valueobject": "^8.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@quenty/blend": "^7.0.0"
38
43
  },
39
44
  "publishConfig": {
40
45
  "access": "public"
41
46
  },
42
- "gitHead": "e9fdcbc6ea1d46e068bf42a08b833099e9005259"
47
+ "gitHead": "fdeae46099587019ec5fc15317dc673aed379400"
43
48
  }
@@ -25,10 +25,10 @@ function FilteredObservableListView.new(observableList, observeScoreCallback, co
25
25
  self._baseList = assert(observableList, "No observableList")
26
26
  self._observeScoreCallback = assert(observeScoreCallback, "No observeScoreCallback")
27
27
 
28
- self._scoredList = ObservableSortedList.new(function(a, b)
28
+ self._scoredList = ObservableSortedList.new(false, function(a, b)
29
29
  -- Preserve index when scoring does not
30
30
  if a.score == b.score then
31
- return a.index < b.index
31
+ return a.index - b.index
32
32
  else
33
33
  return self._compare(a.score, b.score)
34
34
  end
@@ -25,8 +25,7 @@ function ObservableCountingMap.new()
25
25
  self._maid = Maid.new()
26
26
  self._map = {}
27
27
 
28
- self._totalKeyCountValue = ValueObject.new(0, "number")
29
- self._maid:GiveTask(self._totalKeyCountValue)
28
+ self._totalKeyCountValue = self._maid:Add(ValueObject.new(0, "number"))
30
29
 
31
30
  --[=[
32
31
  Fires when an key is added
@@ -34,8 +33,7 @@ function ObservableCountingMap.new()
34
33
  @prop KeyAdded Signal<T>
35
34
  @within ObservableCountingMap
36
35
  ]=]
37
- self.KeyAdded = Signal.new()
38
- self._maid:GiveTask(self.KeyAdded)
36
+ self.KeyAdded = self._maid:Add(Signal.new())
39
37
 
40
38
  --[=[
41
39
  Fires when an key is removed.
@@ -43,8 +41,7 @@ function ObservableCountingMap.new()
43
41
  @prop KeyRemoved Signal<T>
44
42
  @within ObservableCountingMap
45
43
  ]=]
46
- self.KeyRemoved = Signal.new()
47
- self._maid:GiveTask(self.KeyRemoved)
44
+ self.KeyRemoved = self._maid:Add(Signal.new())
48
45
 
49
46
  --[=[
50
47
  Fires when an item count changes
@@ -52,8 +49,7 @@ function ObservableCountingMap.new()
52
49
  @prop KeyChanged Signal<T>
53
50
  @within ObservableCountingMap
54
51
  ]=]
55
- self.KeyChanged = Signal.new()
56
- self._maid:GiveTask(self.KeyChanged)
52
+ self.KeyChanged = self._maid:Add(Signal.new())
57
53
 
58
54
  --[=[
59
55
  Fires when the total count changes.
@@ -311,7 +307,7 @@ end
311
307
  Gets a list of all keys.
312
308
  @return { T }
313
309
  ]=]
314
- function ObservableCountingMap:GetKeysList()
310
+ function ObservableCountingMap:GetKeyList()
315
311
  local list = {}
316
312
  for key, _ in pairs(self._map) do
317
313
  table.insert(list, key)
@@ -5,13 +5,15 @@
5
5
 
6
6
  local require = require(script.Parent.loader).load(script)
7
7
 
8
- local Signal = require("Signal")
9
- local Observable = require("Observable")
10
- local Maid = require("Maid")
11
8
  local Brio = require("Brio")
9
+ local Maid = require("Maid")
10
+ local Observable = require("Observable")
11
+ local ObservableSubscriptionTable = require("ObservableSubscriptionTable")
12
+ local Rx = require("Rx")
13
+ local RxBrioUtils = require("RxBrioUtils")
14
+ local Signal = require("Signal")
12
15
  local Symbol = require("Symbol")
13
16
  local ValueObject = require("ValueObject")
14
- local Rx = require("Rx")
15
17
 
16
18
  local ObservableList = {}
17
19
  ObservableList.ClassName = "ObservableList"
@@ -30,10 +32,9 @@ function ObservableList.new()
30
32
  self._contents = {} -- { [Symbol]: T }
31
33
  self._indexes = {} -- { [Symbol]: number }
32
34
 
33
- self._keyObservables = {} -- { [Symbol]: { Subscription } }
34
-
35
- self._countValue = ValueObject.new(0, "number")
36
- self._maid:GiveTask(self._countValue)
35
+ self._indexObservers = self._maid:Add(ObservableSubscriptionTable.new())
36
+ self._keyIndexObservables = self._maid:Add(ObservableSubscriptionTable.new())
37
+ self._countValue = self._maid:Add(ValueObject.new(0, "number"))
37
38
 
38
39
  --[=[
39
40
  Fires when an item is added
@@ -41,8 +42,7 @@ function ObservableList.new()
41
42
  @prop ItemAdded Signal<T, number, Symbol>
42
43
  @within ObservableList
43
44
  ]=]
44
- self.ItemAdded = Signal.new()
45
- self._maid:GiveTask(self.ItemAdded)
45
+ self.ItemAdded = self._maid:Add(Signal.new())
46
46
 
47
47
  --[=[
48
48
  Fires when an item is removed.
@@ -50,8 +50,7 @@ function ObservableList.new()
50
50
  @prop ItemRemoved Signal<T, Symbol>
51
51
  @within ObservableList
52
52
  ]=]
53
- self.ItemRemoved = Signal.new()
54
- self._maid:GiveTask(self.ItemRemoved)
53
+ self.ItemRemoved = self._maid:Add(Signal.new())
55
54
 
56
55
  --[=[
57
56
  Fires when the count changes.
@@ -103,15 +102,15 @@ function ObservableList:ObserveItemsBrio()
103
102
  sub:Fire(brio)
104
103
  end
105
104
 
106
- for index, key in pairs(self._keyList) do
107
- handleItem(self._contents[key], index, key)
108
- end
109
-
110
105
  maid:GiveTask(self.ItemAdded:Connect(handleItem))
111
106
  maid:GiveTask(self.ItemRemoved:Connect(function(_item, includeKey)
112
107
  maid[includeKey] = nil
113
108
  end))
114
109
 
110
+ for index, key in pairs(self._keyList) do
111
+ handleItem(self._contents[key], index, key)
112
+ end
113
+
115
114
  self._maid[sub] = maid
116
115
  maid:GiveTask(function()
117
116
  self._maid[sub] = nil
@@ -134,12 +133,43 @@ function ObservableList:ObserveIndex(indexToObserve)
134
133
 
135
134
  local key = self._keyList[indexToObserve]
136
135
  if not key then
137
- error(("No entry at index %q, cannot observe changes"):format(indexToObserve))
136
+ error(string.format("No entry at index %q, cannot observe changes", indexToObserve))
138
137
  end
139
138
 
140
139
  return self:ObserveIndexByKey(key)
141
140
  end
142
141
 
142
+ --[=[
143
+ Observes the current value at a given index. This can be useful for observing
144
+ the first entry, or matching stuff up to a given slot.
145
+
146
+ @param indexToObserve number
147
+ @return Observable<T?>
148
+ ]=]
149
+ function ObservableList:ObserveAtIndex(indexToObserve)
150
+ assert(type(indexToObserve) == "number", "Bad indexToObserve")
151
+
152
+ return self._indexObservers:Observe(indexToObserve, function(sub)
153
+ sub:Fire(self:Get(indexToObserve))
154
+ end)
155
+ end
156
+
157
+ --[=[
158
+ Observes the current value at a given index. This can be useful for observing
159
+ the first entry, or matching stuff up to a given slot.
160
+
161
+ @param indexToObserve number
162
+ @return Observable<Brio<T>>
163
+ ]=]
164
+ function ObservableList:ObserveAtIndexBrio(indexToObserve)
165
+ assert(type(indexToObserve) == "number", "Bad indexToObserve")
166
+
167
+ return self:ObserveAtIndex(indexToObserve):Pipe({
168
+ RxBrioUtils.toBrio();
169
+ RxBrioUtils.onlyLastBrioSurvives();
170
+ })
171
+ end
172
+
143
173
  --[=[
144
174
  Removes the first instance found in contents
145
175
 
@@ -176,35 +206,8 @@ end
176
206
  function ObservableList:ObserveIndexByKey(key)
177
207
  assert(type(key) == "userdata", "Bad key")
178
208
 
179
- return Observable.new(function(sub)
180
- local currentIndex = self._indexes[key]
181
- if not currentIndex then
182
- sub:Complete()
183
- return
184
- end
185
-
186
- local maid = Maid.new()
187
- self._keyObservables[key] = self._keyObservables[key] or {}
188
- table.insert(self._keyObservables[key], sub)
189
-
190
- sub:Fire(currentIndex)
191
-
192
- maid:GiveTask(function()
193
- local list = self._keyObservables[key]
194
- if not list then
195
- return
196
- end
197
-
198
- local index = table.find(list, sub)
199
- if index then
200
- table.remove(list, index)
201
- if #list == 0 then
202
- self._keyObservables[key] = nil
203
- end
204
- end
205
- end)
206
-
207
- return maid
209
+ return self._keyIndexObservables:Observe(key, function(sub)
210
+ sub:Fire(self:GetIndexByKey(key))
208
211
  end)
209
212
  end
210
213
 
@@ -256,6 +259,8 @@ end
256
259
  function ObservableList:Get(index)
257
260
  assert(type(index) == "number", "Bad index")
258
261
 
262
+ index = self:_toPositiveIndex(index)
263
+
259
264
  local key = self._keyList[index]
260
265
  if not key then
261
266
  return nil
@@ -289,17 +294,14 @@ function ObservableList:InsertAt(item, index)
289
294
  self._indexes[nextKey] = i + 1
290
295
  self._keyList[i + 1] = nextKey
291
296
 
292
- local subs = self._keyObservables[nextKey]
293
- if subs then
294
- table.insert(changed, {
295
- key = nextKey;
296
- newIndex = i + 1;
297
- subs = subs;
298
- })
299
- end
297
+ table.insert(changed, {
298
+ key = nextKey;
299
+ newIndex = i + 1;
300
+ })
300
301
  end
301
302
 
302
303
  self._keyList[index] = key
304
+ local listLength = #self._keyList
303
305
 
304
306
  -- Fire off count
305
307
  self._countValue.Value = self._countValue.Value + 1
@@ -307,23 +309,17 @@ function ObservableList:InsertAt(item, index)
307
309
  -- Fire off add
308
310
  self.ItemAdded:Fire(item, index, key)
309
311
 
310
- -- Fire off the index change on the value
311
- do
312
- local subs = self._keyObservables[key]
313
- if subs then
314
- table.insert(changed, {
315
- key = key;
316
- newIndex = index;
317
- subs = subs;
318
- })
319
- end
320
- end
321
312
 
313
+ -- Fire off the index change on the value
314
+ self._keyIndexObservables:Fire(key, index)
315
+ self._indexObservers:Fire(index, item)
316
+ self._indexObservers:Fire(self:_toNegativeIndex(listLength, index), item)
322
317
 
323
- -- Fire off index change on each key list (if the data isn't stale)
324
318
  for _, data in pairs(changed) do
325
319
  if self._indexes[data.key] == data.newIndex then
326
- self:_fireSubs(data.subs, data.newIndex)
320
+ self._indexObservers:Fire(data.newIndex, self._contents[data.key])
321
+ self._indexObservers:Fire(self:_toNegativeIndex(listLength, index), self._contents[data.key])
322
+ self._keyIndexObservables:Fire(data.key, data.newIndex)
327
323
  end
328
324
  end
329
325
 
@@ -368,8 +364,6 @@ function ObservableList:RemoveByKey(key)
368
364
  return nil
369
365
  end
370
366
 
371
- local observableSubs = self._keyObservables[key]
372
- self._keyObservables[key] = nil
373
367
  self._indexes[key] = nil
374
368
  self._contents[key] = nil
375
369
 
@@ -382,16 +376,13 @@ function ObservableList:RemoveByKey(key)
382
376
  self._indexes[nextKey] = i
383
377
  self._keyList[i] = nextKey
384
378
 
385
- local subs = self._keyObservables[nextKey]
386
- if subs then
387
- table.insert(changed, {
388
- key = nextKey;
389
- newIndex = i;
390
- subs = subs;
391
- })
392
- end
379
+ table.insert(changed, {
380
+ key = nextKey;
381
+ newIndex = i;
382
+ })
393
383
  end
394
384
  self._keyList[n] = nil
385
+ local listLength = #self._keyList
395
386
 
396
387
  -- Fire off that count changed
397
388
  self._countValue.Value = self._countValue.Value - 1
@@ -401,39 +392,25 @@ function ObservableList:RemoveByKey(key)
401
392
  end
402
393
 
403
394
  -- Fire off the index change on the value
404
- if observableSubs then
405
- self:_completeSubs(observableSubs)
395
+ self._keyIndexObservables:Complete(key)
396
+ self._indexObservers:Fire(listLength, nil)
397
+
398
+ if listLength == 0 then
399
+ self._indexObservers:Fire(-1, nil)
406
400
  end
407
401
 
408
402
  -- Fire off index change on each key list (if the data isn't stale)
409
403
  for _, data in pairs(changed) do
410
404
  if self._indexes[data.key] == data.newIndex then
411
- self:_fireSubs(data.subs, data.newIndex)
405
+ self._indexObservers:Fire(data.newIndex, self._contents[data.key])
406
+ self._indexObservers:Fire(self:_toNegativeIndex(listLength, index), self._contents[data.key])
407
+ self._keyIndexObservables:Fire(data.key, data.newIndex)
412
408
  end
413
409
  end
414
410
 
415
411
  return item
416
412
  end
417
413
 
418
- function ObservableList:_fireSubs(list, index)
419
- for _, sub in pairs(list) do
420
- if sub:IsPending() then
421
- task.spawn(function()
422
- sub:Fire(index)
423
- end)
424
- end
425
- end
426
- end
427
-
428
- function ObservableList:_completeSubs(list)
429
- for _, sub in pairs(list) do
430
- if sub:IsPending() then
431
- sub:Fire(nil)
432
- sub:Complete()
433
- end
434
- end
435
- end
436
-
437
414
  --[=[
438
415
  Gets a list of all entries.
439
416
  @return { T }
@@ -446,6 +423,20 @@ function ObservableList:GetList()
446
423
  return list
447
424
  end
448
425
 
426
+ function ObservableList:_toPositiveIndex(index)
427
+ if index > 0 then
428
+ return index
429
+ elseif index < 0 then
430
+ return #self._keyList + index + 1
431
+ else
432
+ error(string.format("[ObservableList._toPositiveIndex] - Bad index %d", index))
433
+ end
434
+ end
435
+
436
+ function ObservableList:_toNegativeIndex(listLength, index)
437
+ return -listLength + index - 1
438
+ end
439
+
449
440
  --[=[
450
441
  Cleans up the ObservableList and sets the metatable to nil.
451
442
  ]=]
@@ -23,6 +23,10 @@ return function()
23
23
  expect(observableList:GetCount()).to.equal(1)
24
24
  end)
25
25
 
26
+ it("should allow negative queries", function()
27
+ expect(observableList:Get(-1)).to.equal("a")
28
+ expect(observableList:Get(-2)).to.equal(nil)
29
+ end)
26
30
 
27
31
  it("should allow false as a value", function()
28
32
  expect(observableList:Get(2)).to.equal(nil)
@@ -30,6 +34,14 @@ return function()
30
34
  expect(observableList:Get(2)).to.equal(false)
31
35
  end)
32
36
 
37
+ it("should allow negative queries after false", function()
38
+ expect(observableList:Get(1)).to.equal("a")
39
+ expect(observableList:Get(2)).to.equal(false)
40
+
41
+ expect(observableList:Get(-1)).to.equal(false)
42
+ expect(observableList:Get(-2)).to.equal("a")
43
+ end)
44
+
33
45
  it("should fire off events for a specific key", function()
34
46
  local seen = {}
35
47
  local sub = observableList:ObserveIndex(1):Subscribe(function(value)
@@ -61,6 +73,42 @@ return function()
61
73
  expect(seen[4]:IsDead()).to.equal(true)
62
74
  end)
63
75
 
76
+ it("it should be able to observe a specific key", function()
77
+ local seen = {}
78
+ local sub = observableList:ObserveAtIndex(1):Subscribe(function(value)
79
+ table.insert(seen, value)
80
+ end)
81
+
82
+ local originalList = observableList:GetList()
83
+ expect(originalList[1]).to.equal("c")
84
+
85
+ observableList:InsertAt("dragon", 1)
86
+
87
+ sub:Destroy()
88
+
89
+ expect(#seen).to.equal(2)
90
+ expect(seen[1]).to.equal("c")
91
+ expect(seen[2]).to.equal("dragon")
92
+ end)
93
+
94
+ it("it should be able to observe a specific negative key", function()
95
+ local seen = {}
96
+ local sub = observableList:ObserveAtIndex(-1):Subscribe(function(value)
97
+ table.insert(seen, value)
98
+ end)
99
+
100
+ local originalList = observableList:GetList()
101
+ expect(originalList[#originalList]).to.equal("a")
102
+
103
+ observableList:Add("fire")
104
+
105
+ sub:Destroy()
106
+
107
+ expect(#seen).to.equal(2)
108
+ expect(seen[1]).to.equal("a")
109
+ expect(seen[2]).to.equal("fire")
110
+ end)
111
+
64
112
  it("should fire off events on removal", function()
65
113
  local seen = {}
66
114
  local sub = observableList:ObserveIndex(2):Subscribe(function(value)