mirror of
https://github.com/littensy/charm.git
synced 2026-10-21 03:36:11 +00:00
feat: allow conditional dependencies (#4)
* feat: allow conditional dependencies * docs: remove conditional deps warnings * fix: allow nested captures * docs: add dev flag * fix: `try()` uses pcall if passed `finally()` * docs: interval is optional * docs: update readme * docs: add client/server tags
This commit is contained in:
parent
fbc86d22c6
commit
a90d131fed
14 changed files with 290 additions and 98 deletions
|
|
@ -7,34 +7,23 @@ local atom = require(Package.atom)
|
|||
local computed = require(Package.computed)
|
||||
|
||||
local function parameterGenerator()
|
||||
return atom({ count = 0 })
|
||||
return atom(0)
|
||||
end
|
||||
|
||||
local benchmarks = {
|
||||
atom = function(_, source: any)
|
||||
for _ = 1, 500 do
|
||||
source({ count = math.random(1, 2) })
|
||||
source(math.random(1, 2))
|
||||
end
|
||||
end,
|
||||
|
||||
computed = function(_, source: any)
|
||||
computed(function()
|
||||
return { count = 2 * source().count }
|
||||
return 2 * source()
|
||||
end)
|
||||
for _ = 1, 500 do
|
||||
source({ count = math.random(1, 2) })
|
||||
end
|
||||
end,
|
||||
|
||||
computed_nested = function(_, source: any)
|
||||
local double = computed(function()
|
||||
return { count = 2 * source().count }
|
||||
end)
|
||||
computed(function()
|
||||
return { count = 2 * double().count }
|
||||
end)
|
||||
for _ = 1, 500 do
|
||||
source({ count = math.random(1, 2) })
|
||||
source(math.random(1, 2))
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,21 +2,47 @@ local atom = require(script.Parent.Parent.atom)
|
|||
local store = require(script.Parent.Parent.store)
|
||||
|
||||
return function()
|
||||
it("gracefully handles yielding", function()
|
||||
expect(function()
|
||||
store.capture(function()
|
||||
task.wait(10)
|
||||
return 1
|
||||
end)
|
||||
end).to.throw()
|
||||
end)
|
||||
|
||||
it("captures atoms from a function", function()
|
||||
local a, b, c = atom(1), atom(1), atom(2)
|
||||
local captured, result = store.capture(function()
|
||||
local deps, result = store.capture(function()
|
||||
return a() + b()
|
||||
end)
|
||||
expect(captured[a]).to.be.ok()
|
||||
expect(captured[b]).to.be.ok()
|
||||
expect(captured[c]).to.never.be.ok()
|
||||
expect(deps[a]).to.be.ok()
|
||||
expect(deps[b]).to.be.ok()
|
||||
expect(deps[c]).to.never.be.ok()
|
||||
expect(result).to.equal(2)
|
||||
end)
|
||||
|
||||
it("captures an atom by itself", function()
|
||||
local a = atom(1)
|
||||
local captured, result = store.capture(a)
|
||||
expect(captured[a]).to.be.ok()
|
||||
local deps, result = store.capture(a)
|
||||
expect(deps[a]).to.be.ok()
|
||||
expect(result).to.equal(1)
|
||||
end)
|
||||
|
||||
it("allows nested captures", function()
|
||||
local a = atom(1)
|
||||
local b = atom(1)
|
||||
local inner
|
||||
local outer = store.capture(function()
|
||||
inner = store.capture(function()
|
||||
return b()
|
||||
end)
|
||||
return a()
|
||||
end)
|
||||
|
||||
assert(outer[a], "outer did not capture a")
|
||||
assert(outer[b], "outer did not capture b")
|
||||
assert(inner[a] == nil, "inner captured a")
|
||||
assert(inner[b], "inner did not capture b")
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -68,4 +68,35 @@ return function()
|
|||
|
||||
assert(count(store.listeners[source]) == 0, "nested computed atom did not gc")
|
||||
end)
|
||||
|
||||
it("tracks conditional dependencies", function()
|
||||
local condition = atom(false)
|
||||
local a = atom(0)
|
||||
local b = atom(1)
|
||||
local reruns = 0
|
||||
local current
|
||||
|
||||
-- assign variable to avoid gc
|
||||
local _ = computed(function()
|
||||
reruns += 1
|
||||
current = if condition() then a() else b()
|
||||
return current
|
||||
end)
|
||||
|
||||
expect(reruns).to.equal(1)
|
||||
expect(current).to.equal(1)
|
||||
|
||||
condition(true)
|
||||
expect(reruns).to.equal(2)
|
||||
expect(current).to.equal(0)
|
||||
|
||||
a(1)
|
||||
b(2)
|
||||
expect(reruns).to.equal(3)
|
||||
expect(current).to.equal(1)
|
||||
|
||||
condition(false)
|
||||
expect(reruns).to.equal(4)
|
||||
expect(current).to.equal(2)
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -43,4 +43,33 @@ return function()
|
|||
unsubscribe()
|
||||
expect(cleanups).to.equal(2)
|
||||
end)
|
||||
|
||||
it("tracks conditional dependencies", function()
|
||||
local condition = atom(false)
|
||||
local a = atom(0)
|
||||
local b = atom(1)
|
||||
local reruns = 0
|
||||
local current
|
||||
|
||||
effect(function()
|
||||
reruns += 1
|
||||
current = if condition() then a() else b()
|
||||
end)
|
||||
|
||||
expect(reruns).to.equal(1)
|
||||
expect(current).to.equal(1)
|
||||
|
||||
condition(true)
|
||||
expect(reruns).to.equal(2)
|
||||
expect(current).to.equal(0)
|
||||
|
||||
a(1)
|
||||
b(2)
|
||||
expect(reruns).to.equal(3)
|
||||
expect(current).to.equal(1)
|
||||
|
||||
condition(false)
|
||||
expect(reruns).to.equal(4)
|
||||
expect(current).to.equal(2)
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ local store = require(script.Parent.Parent.store)
|
|||
return function()
|
||||
it("calls an atom without capturing it", function()
|
||||
local a, b, c = atom(1), atom(1), atom(1)
|
||||
local captured, result = store.capture(function()
|
||||
local deps, result = store.capture(function()
|
||||
return a() + store.peek(b) + c()
|
||||
end)
|
||||
expect(captured[a]).to.be.ok()
|
||||
expect(captured[b]).to.never.be.ok()
|
||||
expect(captured[c]).to.be.ok()
|
||||
expect(deps[a]).to.be.ok()
|
||||
expect(deps[b]).to.never.be.ok()
|
||||
expect(deps[c]).to.be.ok()
|
||||
expect(result).to.equal(3)
|
||||
end)
|
||||
|
||||
|
|
|
|||
|
|
@ -67,4 +67,32 @@ return function()
|
|||
|
||||
assert(count(store.listeners[source]) == 0, "computed atom did not collect")
|
||||
end)
|
||||
|
||||
it("tracks conditional dependencies", function()
|
||||
local condition = atom(false)
|
||||
local a = atom(0)
|
||||
local b = atom(1)
|
||||
local reruns = 0
|
||||
local current
|
||||
|
||||
subscribe(function()
|
||||
return if condition() then a() else b()
|
||||
end, function(state)
|
||||
reruns += 1
|
||||
current = state
|
||||
end)
|
||||
|
||||
condition(true)
|
||||
expect(reruns).to.equal(1)
|
||||
expect(current).to.equal(0)
|
||||
|
||||
a(1)
|
||||
b(2)
|
||||
expect(reruns).to.equal(2)
|
||||
expect(current).to.equal(1)
|
||||
|
||||
condition(false)
|
||||
expect(reruns).to.equal(3)
|
||||
expect(current).to.equal(2)
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue