-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3fe1ee4
commit 007d9bc
Showing
6 changed files
with
255 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
local Subject = require 'subjects/subject' | ||
local Observer = require 'observer' | ||
local util = require 'util' | ||
|
||
--- @class ReplaySubject | ||
-- @description A Subject that provides new Subscribers with some or all of the most recently | ||
-- produced values upon subscription. | ||
local ReplaySubject = setmetatable({}, Subject) | ||
ReplaySubject.__index = ReplaySubject | ||
ReplaySubject.__tostring = util.constant('ReplaySubject') | ||
|
||
--- Creates a new ReplaySubject. | ||
-- @arg {number=} bufferSize - The number of values to send to new subscribers. If nil, an infinite | ||
-- buffer is used (note that this could lead to memory issues). | ||
-- @returns {ReplaySubject} | ||
function ReplaySubject.create(n) | ||
local self = { | ||
observers = {}, | ||
stopped = false, | ||
buffer = {}, | ||
bufferSize = n | ||
} | ||
|
||
return setmetatable(self, ReplaySubject) | ||
end | ||
|
||
--- Creates a new Observer and attaches it to the ReplaySubject. Immediately broadcasts the most | ||
-- contents of the buffer to the Observer. | ||
-- @arg {function} onNext - Called when the ReplaySubject produces a value. | ||
-- @arg {function} onError - Called when the ReplaySubject terminates due to an error. | ||
-- @arg {function} onCompleted - Called when the ReplaySubject completes normally. | ||
function ReplaySubject:subscribe(onNext, onError, onCompleted) | ||
local observer | ||
|
||
if util.isa(onNext, Observer) then | ||
observer = onNext | ||
else | ||
observer = Observer.create(onNext, onError, onCompleted) | ||
end | ||
|
||
local subscription = Subject.subscribe(self, observer) | ||
|
||
for i = 1, #self.buffer do | ||
observer:onNext(util.unpack(self.buffer[i])) | ||
end | ||
|
||
return subscription | ||
end | ||
|
||
--- Pushes zero or more values to the ReplaySubject. They will be broadcasted to all Observers. | ||
-- @arg {*...} values | ||
function ReplaySubject:onNext(...) | ||
table.insert(self.buffer, util.pack(...)) | ||
if self.bufferSize and #self.buffer > self.bufferSize then | ||
table.remove(self.buffer, 1) | ||
end | ||
|
||
return Subject.onNext(self, ...) | ||
end | ||
|
||
ReplaySubject.__call = ReplaySubject.onNext | ||
|
||
return ReplaySubject |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
describe('ReplaySubject', function() | ||
describe('create', function() | ||
it('returns a ReplaySubject', function() | ||
expect(Rx.ReplaySubject.create()).to.be.an(Rx.ReplaySubject) | ||
end) | ||
|
||
it('sets an appropriate buffer size if it is specified', function() | ||
local subject = Rx.ReplaySubject.create(2) | ||
local observer = Rx.Observer.create() | ||
local onNext = spy(observer, '_onNext') | ||
subject:onNext(1) | ||
subject:onNext(2) | ||
subject:onNext(3) | ||
subject:subscribe(observer) | ||
expect(onNext).to.equal({{2}, {3}}) | ||
end) | ||
|
||
it('keeps an infinite buffer if no buffer size is specified', function() | ||
local subject = Rx.ReplaySubject.create() | ||
local observer = Rx.Observer.create() | ||
local onNext = spy(observer, '_onNext') | ||
subject:onNext(1) | ||
subject:onNext(2) | ||
subject:onNext(3) | ||
subject:subscribe(observer) | ||
expect(onNext).to.equal({{1}, {2}, {3}}) | ||
end) | ||
end) | ||
|
||
describe('subscribe', function() | ||
it('returns a Subscription', function() | ||
local subject = Rx.ReplaySubject.create() | ||
local observer = Rx.Observer.create() | ||
expect(subject:subscribe(observer)).to.be.an(Rx.Subscription) | ||
end) | ||
|
||
it('accepts 3 functions as arguments', function() | ||
local onNext, onCompleted = spy(), spy() | ||
local subject = Rx.ReplaySubject.create() | ||
subject:subscribe(onNext, nil, onCompleted) | ||
subject:onNext(5) | ||
subject:onCompleted() | ||
expect(onNext).to.equal({{5}}) | ||
expect(#onCompleted).to.equal(1) | ||
end) | ||
|
||
it('calls onNext with the current buffer', function() | ||
local subject = Rx.ReplaySubject.create(2) | ||
local observer = Rx.Observer.create() | ||
local onNext = spy(observer, '_onNext') | ||
subject:onNext(1) | ||
subject:onNext(2) | ||
subject:onNext(3) | ||
subject:subscribe(observer) | ||
expect(onNext).to.equal({{2}, {3}}) | ||
end) | ||
end) | ||
|
||
describe('onNext', function() | ||
it('pushes values to all subscribers', function() | ||
local observers = {} | ||
local spies = {} | ||
for i = 1, 2 do | ||
observers[i] = Rx.Observer.create() | ||
spies[i] = spy(observers[i], '_onNext') | ||
end | ||
|
||
local subject = Rx.ReplaySubject.create() | ||
subject:subscribe(observers[1]) | ||
subject:subscribe(observers[2]) | ||
subject:onNext(1) | ||
subject:onNext(2) | ||
subject:onNext(3) | ||
expect(spies[1]).to.equal({{1}, {2}, {3}}) | ||
expect(spies[2]).to.equal({{1}, {2}, {3}}) | ||
end) | ||
|
||
it('can be called using function syntax', function() | ||
local observer = Rx.Observer.create() | ||
local subject = Rx.ReplaySubject.create() | ||
local onNext = spy(observer, 'onNext') | ||
subject:subscribe(observer) | ||
subject(4) | ||
expect(#onNext).to.equal(1) | ||
end) | ||
end) | ||
end) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters