Skip to content

Commit

Permalink
Reintroduce scope:insert() (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
dphfox authored Oct 27, 2024
1 parent 978adc0 commit 1030135
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 37 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/mkdocs-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ on:
- main

env:
FUSION_VERSION: 0.3
FUSION_DEPLOY_TYPE: 'release'
FUSION_VERSION: 0.4
FUSION_DEPLOY_TYPE: 'dev'

jobs:
deploy:
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ desktop.ini

# Ignore sourcemap generated by Rojo
# Regen with `rojo sourcemap -o sourcemap.json .\test-runner.project.json`
sourcemap.json
sourcemap.json

# Ignore MacOS DS_Store
.DS_Store
75 changes: 75 additions & 0 deletions docs/api-reference/memory/members/insert.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<nav class="fusiondoc-api-breadcrumbs">
<span>Memory</span>
<span>Members</span>
<span>insert</span>
</nav>

<h1 class="fusiondoc-api-header" markdown>
<span class="fusiondoc-api-icon" markdown>:octicons-workflow-24:</span>
<span class="fusiondoc-api-name">insert</span>
<span class="fusiondoc-api-type">
-> Tasks...
</span>
</h1>

```Lua
function Fusion.insert<Tasks...>(
scope: Scope<unknown>,
...: Tasks...
): Tasks...
```

Inserts destruction [tasks](../../types/task) passed in to the
[scope](../../types/scope). Returns the clean up tasks to be used for variable
declarations.


!!! success "Use scoped() method syntax"
This function is intended to be accessed as a method on a scope:
```Lua
local conn, ins = scope:insert(
RunService.Heartbeat:Connnect(doUpdate),
Instance.new("Part", workspace)
)
```

-----

## Parameters

<h3 markdown>
scope
<span class="fusiondoc-api-type">
: <a href="../../types/scope">Scope</a>&lt;unknown&gt;
</span>
</h3>

The [scope](../../types/scope) which should be used to store
destruction tasks.

<h3 markdown>
...
<span class="fusiondoc-api-type">
: Tasks...
</span>
</h3>

The destruction [tasks](../../types/task) which should be inserted into the
scope.

-----

<h2 markdown>
Returns
<span class="fusiondoc-api-type">
-> Tasks...
</span>
</h2>

The destruction [tasks](../../types/task) that has been inserted into the scope.

-----

## Learn More

- [Scopes tutorial](../../../../tutorials/fundamentals/scopes)
28 changes: 17 additions & 11 deletions docs/tutorials/fundamentals/scopes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ manage.
## Scopes

When you create many objects at once, you often want to destroy them together
later.
later.

To make this easier, some people add their objects to an array. Arrays that
group together objects like this are given a special name: *scopes*.
Expand Down Expand Up @@ -153,6 +153,16 @@ scope:doCleanup()
This makes it harder to mess up writing scopes. Your code reads more naturally,
too.

For convenience, Fusion exposes the `insert` method to insert destruction tasks
into a scope:

```Lua
local conn, ins = scope:insert(
RunService.Heartbeat:Connnect(doUpdate),
Instance.new("Part", workspace)
)
```

### Adding Methods In Bulk

Try passing `Fusion` to `scoped()` - it's a table with functions, too.
Expand Down Expand Up @@ -269,15 +279,13 @@ local uiScope = scoped(Fusion)

-- ... create the ui ...

table.insert(
uiScope,
uiScope:insert(
dropdownOpened:Connect(function()
local dropdownScope = uiScope:deriveScope()

-- ... create the dropdown ...

table.insert(
dropdownScope,
dropdownScope:insert(
dropdownClosed:Connect(function()
dropdownScope:doCleanup()
end)
Expand All @@ -298,20 +306,18 @@ To help with this, Fusion provides an `innerScope` method. It works just like
- When the original scope is cleaned up, the 'inner scope' is cleaned up too
- You can still call `doCleanup()` to clean the inner scope up early

```Lua hl_lines="8"
```Lua hl_lines="7"
local uiScope = scoped(Fusion)

-- ... create the ui ...

table.insert(
uiScope,
uiScope:insert(
dropdownOpened:Connect(function()
local dropdownScope = uiScope:innerScope()

-- ... create the dropdown ...

table.insert(
dropdownScope,
dropdownScope:insert(
dropdownClosed:Connect(function()
dropdownScope:doCleanup()
end)
Expand Down Expand Up @@ -340,4 +346,4 @@ example, you'll need to create a scope in your main code file to start using
Fusion, and you might want to make a few more in other parts of your code.

However, Fusion manages most of your scopes for you, so for large parts of your
codebase, you won't have to consider scopes and destruction at all.
codebase, you won't have to consider scopes and destruction at all.
16 changes: 9 additions & 7 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ nav:
- Sharing Values: tutorials/best-practices/sharing-values.md
- Error Safety: tutorials/best-practices/error-safety.md
- Optimisation: tutorials/best-practices/optimisation.md

- Examples:
- Examples: examples/index.md
- Cookbook:
Expand Down Expand Up @@ -118,20 +118,22 @@ nav:
- deriveScope: api-reference/memory/members/derivescope.md
- doCleanup: api-reference/memory/members/docleanup.md
- scoped: api-reference/memory/members/scoped.md
- innerScope: api-reference/memory/members/innerscope.md
- insert: api-reference/memory/members/insert.md
- Graph:
- Types:
- GraphObject: api-reference/graph/types/graphobject.md
- GraphObject: api-reference/graph/types/graphobject.md
- Observer: api-reference/graph/types/observer.md
- Members:
- Observer: api-reference/graph/members/observer.md
- State:
- Types:
- UsedAs: api-reference/state/types/usedas.md
- Computed: api-reference/state/types/computed.md
- UsedAs: api-reference/state/types/usedas.md
- Computed: api-reference/state/types/computed.md
- For: api-reference/state/types/for.md
- StateObject: api-reference/state/types/stateobject.md
- Use: api-reference/state/types/use.md
- Value: api-reference/state/types/value.md
- StateObject: api-reference/state/types/stateobject.md
- Use: api-reference/state/types/use.md
- Value: api-reference/state/types/value.md
- Members:
- Computed: api-reference/state/members/computed.md
- ForKeys: api-reference/state/members/forkeys.md
Expand Down
28 changes: 14 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"name": "@dphfox/fusion",
"version": "0.3.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/dphfox/Fusion.git"
},
"contributors": [
"dphfox"
],
"bugs": {
"url": "https://github.com/dphfox/Fusion/issues"
}
{
"name": "@dphfox/fusion",
"version": "0.3.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/dphfox/Fusion.git"
},
"contributors": [
"dphfox"
],
"bugs": {
"url": "https://github.com/dphfox/Fusion/issues"
}
}
22 changes: 22 additions & 0 deletions src/Memory/insert.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
Inserts clean up tasks passed in to the scope.
]]
local Package = script.Parent.Parent
local Types = require(Package.Types)

local function insert<Tasks...>(
scope: Types.Scope<unknown>,
...: Tasks...
): Tasks...
for index = 1, select("#", ...) do
table.insert(scope, select(index, ...))
end
return ...
end

return insert
3 changes: 2 additions & 1 deletion src/Types.luau
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ export type Fusion = {
scoped: ScopedConstructor,
deriveScope: DeriveScopeConstructor,
innerScope: DeriveScopeConstructor,
insert: <Tasks...>(scope: Scope<unknown>, Tasks...) -> Tasks...,

peek: Use,
Value: ValueConstructor,
Expand Down Expand Up @@ -288,7 +289,7 @@ export type ExternalProvider = {
logWarn: (
errorString: string
) -> (),

doTaskImmediate: (
resume: () -> ()
) -> (),
Expand Down
3 changes: 2 additions & 1 deletion src/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ local Fusion: Fusion = table.freeze {
deriveScope = require(script.Memory.deriveScope),
doCleanup = require(script.Memory.doCleanup),
innerScope = require(script.Memory.innerScope),
insert = require(script.Memory.insert),
scoped = require(script.Memory.scoped),

-- Graph
Observer = require(script.Graph.Observer),

Expand Down
80 changes: 80 additions & 0 deletions test/Spec/Memory/insert.spec.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
--!strict
--!nolint LocalUnused
local task = nil -- Disable usage of Roblox's task scheduler

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Fusion = ReplicatedStorage.Fusion

local doCleanup = require(Fusion.Memory.doCleanup)
local insert = require(Fusion.Memory.insert)

return function()
local it = getfenv().it

it("should accept zero tasks", function()
local expect = getfenv().expect

local scope = scoped()
insert(scope)

expect(#scope).to.equal(0)
end)

it("should accept single tasks", function()
local expect = getfenv().expect

local isDestroyed = false
local scope = scoped()
insert(scope, function()
isDestroyed = true
end)

expect(#scope).to.equal(1)
doCleanup(scope)

expect(isDestroyed).to.equal(true)
end)

it("should accept multiple tasks", function()
local expect = getfenv().expect

local counter = 0
local scope = scoped()

insert(scope, function()
counter += 1
end)
insert(scope, function()
counter += 1
end)
insert(scope, {
function()
counter += 1
end
})

expect(#scope).to.equal(3)
doCleanup(scope)
expect(counter).to.equal(3)
end)

it("should return the given tasks", function()
local expect = getfenv().expect

local counter = 0
local function onDestroy()
counter += 1
end
local function onDestroy2()
counter += 2
end
local scope = scoped()

local returnedDestroy, returnedDestroy2 = insert(scope, onDestroy, onDestroy2)
expect(returnedDestroy).to.equal(onDestroy)
expect(returnedDestroy2).to.equal(onDestroy2)
expect(#scope).to.equal(2)
doCleanup(scope)
expect(counter).to.equal(3)
end)
end

0 comments on commit 1030135

Please sign in to comment.