refactor: move peek function to store module

This commit is contained in:
Richard 2024-06-01 18:44:48 -07:00
parent 5fd064e70a
commit 3e128448e0
3 changed files with 65 additions and 24 deletions

View file

@ -1,12 +1,11 @@
local atom = require(script.Parent.Parent.atom) local atom = require(script.Parent.Parent.atom)
local peek = require(script.Parent.Parent.peek)
local store = require(script.Parent.Parent.store) local store = require(script.Parent.Parent.store)
return function() return function()
it("calls an atom without capturing it", function() it("calls an atom without capturing it", function()
local a, b, c = atom(1), atom(1), atom(1) local a, b, c = atom(1), atom(1), atom(1)
local captured, result = store.capture(function() local captured, result = store.capture(function()
return a() + peek(b) + c() return a() + store.peek(b) + c()
end) end)
expect(captured[a]).to.be.ok() expect(captured[a]).to.be.ok()
expect(captured[b]).to.never.be.ok() expect(captured[b]).to.never.be.ok()
@ -15,8 +14,8 @@ return function()
end) end)
it("passes through arguments", function() it("passes through arguments", function()
expect(peek(1)).to.equal(1) expect(store.peek(1)).to.equal(1)
expect(peek(function() expect(store.peek(function()
return 1 return 1
end)).to.equal(1) end)).to.equal(1)
end) end)

View file

@ -1,19 +0,0 @@
local store = require(script.Parent.store)
local function peek<T, U...>(callback: ((U...) -> T) | T, ...: U...): T
if type(callback) ~= "function" then
return callback
end
if not store.isCapturing() then
return callback(...)
end
store.setCapturing(false)
local result = callback(...)
store.setCapturing(true)
return result
end
return peek

View file

@ -10,10 +10,21 @@ local capturing = false
local batched: { [() -> ()]: true } = {} local batched: { [() -> ()]: true } = {}
local batching = false local batching = false
--[=[
Returns whether the given value is an atom.
@param value The value to check.
@return `true` if the value is an atom, otherwise `false`.
]=]
local function isAtom(value: any) local function isAtom(value: any)
return not not (value and listeners[value]) return not not (value and listeners[value])
end end
--[=[
Notifies all subscribers of the given atom that the state has changed.
@param atom The atom to notify.
]=]
local function notify(atom: Atom<any>) local function notify(atom: Atom<any>)
if batching then if batching then
for listener in next, listeners[atom] do for listener in next, listeners[atom] do
@ -27,6 +38,13 @@ local function notify(atom: Atom<any>)
end end
end end
--[=[
Captures all atoms that are read during the function call and returns them
along with the result of the function. Useful for tracking dependencies.
@param molecule The function to run.
@return A tuple containing the captured atoms and the result of the function.
]=]
local function capture<T>(callback: () -> T): ({ [Atom<any>]: true }, T) local function capture<T>(callback: () -> T): ({ [Atom<any>]: true }, T)
if listeners[callback] then if listeners[callback] then
return { [callback] = true }, callback() return { [callback] = true }, callback()
@ -42,9 +60,16 @@ local function capture<T>(callback: () -> T): ({ [Atom<any>]: true }, T)
return dependencies, result return dependencies, result
end end
--[=[
Runs the given function and schedules listeners to be notified only once
after the function has completed. Useful for batching multiple changes.
@param callback The function to run.
]=]
local function batch(callback: () -> ()) local function batch(callback: () -> ())
if batching then if batching then
return callback() callback()
return
end end
batching = true batching = true
@ -58,10 +83,45 @@ local function batch(callback: () -> ())
table.clear(batched) table.clear(batched)
end end
--[=[
Returns the result of the function without subscribing to changes. If a
non-function value is provided, it is returned as is.
@param molecule The atom or molecule to get the state of.
@param args Arguments to pass to the molecule.
@return The current state.
]=]
local function peek<T, U...>(callback: ((U...) -> T) | T, ...: U...): T
if type(callback) ~= "function" then
return callback
end
if not capturing then
return callback(...)
end
capturing = false
local result = callback(...)
capturing = true
return result
end
--[=[
Sets whether the store is capturing atoms. If `true`, atoms that are read
will be tracked and returned by `capture`.
@param value Whether to capture atoms.
]=]
local function setCapturing(value: boolean) local function setCapturing(value: boolean)
capturing = value capturing = value
end end
--[=[
Returns whether the store is currently capturing atoms.
@return `true` if the store is capturing atoms, otherwise `false`.
]=]
local function isCapturing() local function isCapturing()
return capturing return capturing
end end
@ -73,6 +133,7 @@ return {
notify = notify, notify = notify,
capture = capture, capture = capture,
batch = batch, batch = batch,
peek = peek,
setCapturing = setCapturing, setCapturing = setCapturing,
isCapturing = isCapturing, isCapturing = isCapturing,
} }