Skip to content

Commit

Permalink
V1.14.1 update
Browse files Browse the repository at this point in the history
  • Loading branch information
howmanysmall committed Mar 17, 2022
1 parent d78f4da commit 85f5484
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 16 deletions.
3 changes: 3 additions & 0 deletions Luau.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9465,6 +9465,9 @@ type = "any"
required = false
type = "..."

[[task.cancel.args]]
type = {display = "coroutine"}

[task.desynchronize]
args = []

Expand Down
16 changes: 16 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 1.4.1 - 2022-03-17

### Added

- Added a new `LinkToInstance` method which will instead use `Instance.Destroying`.
- Added traceback to `Janitor:AddPromise` for invalid promises.

### Changed

- The legacy `LinkToInstance` method has been renamed to `LegacyLinkToInstance`.

### Fixed

- Fixed Janitor not warning about an invalid `MethodName` for threads and functions.
- Fixed incorrect documentation about `Janitor.CurrentlyCleaning`.

## 1.14 - 2022-03-12

### Added
Expand Down
2 changes: 1 addition & 1 deletion docs/Installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ HttpService.HttpEnabled = HttpEnabled`}

```toml
[dependencies]
Janitor = "howmanysmall/janitor@^1.14"
Janitor = "howmanysmall/janitor@^1.14.1"
```

## Next
Expand Down
4 changes: 4 additions & 0 deletions docs/WhyUseJanitor.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ With Maid, you can't tell it to do anything other than `:Destroy()`, `:Disconnec
### LinkToInstance

Janitor also allows linking to an Instance via the `Janitor:LinkToInstance()` method. This allows the Janitor to cleanup everything added to it when an Instance has its `Instance:Destroy()` method invoked.

### Native support for Promises

Janitor is the only library of its kind that supports cancelling Promises.
7 changes: 6 additions & 1 deletion moonwave.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ gitSourceBranch = "main"
tagline = "Garbage collector object implementation for Roblox"

[[navbar.items]]
href = "https://discord.gg/luau"
href = "https://discord.gg/nhDpg96Srt"
label = "Discord"
position = "right"

[[navbar.items]]
href = "https://discord.gg/luau"
label = "Luau Discord"
position = "right"

[home]
enabled = true
includeReadme = false
Expand Down
72 changes: 66 additions & 6 deletions src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ local FoundPromiseLibrary, Promise = GetPromiseLibrary()
local IndicesReference = Symbol("IndicesReference")
local LinkToInstanceIndex = Symbol("LinkToInstanceIndex")

local INVALID_METHOD_NAME = "Object is a %s and as such expected `true?` for the method name and instead got %s. Traceback: %s"
local METHOD_NOT_FOUND_ERROR = "Object %s doesn't have method %s, are you sure you want to add it? Traceback: %s"
local NOT_A_PROMISE = "Invalid argument #1 to 'Janitor:AddPromise' (Promise expected, got %s (%s))"
local NOT_A_PROMISE = "Invalid argument #1 to 'Janitor:AddPromise' (Promise expected, got %s (%s)) Traceback: %s"

type RbxScriptConnection = RbxScriptConnection.RbxScriptConnection

Expand All @@ -36,7 +37,7 @@ Janitor.__index = Janitor
@prop CurrentlyCleaning boolean
@within Janitor
Whether or not the Janitor is currently cleaning up. Will be `nil` if it is.
Whether or not the Janitor is currently cleaning up.
]=]

local TypeDefaults = {
Expand Down Expand Up @@ -161,8 +162,15 @@ function Janitor:Add<T>(Object: T, MethodName: StringOrTrue?, Index: any?): T

local TypeOf = typeof(Object)
local NewMethodName = MethodName or TypeDefaults[TypeOf] or "Destroy"
if TypeOf ~= "function" and TypeOf ~= "thread" and not (Object :: any)[NewMethodName] then
warn(string.format(METHOD_NOT_FOUND_ERROR, tostring(Object), tostring(NewMethodName), debug.traceback(nil :: any, 2)))

if TypeOf == "function" or TypeOf == "thread" then
if NewMethodName ~= true then
warn(string.format(INVALID_METHOD_NAME, TypeOf, tostring(NewMethodName), debug.traceback(nil :: any, 2)))
end
else
if not (Object :: any)[NewMethodName] then
warn(string.format(METHOD_NOT_FOUND_ERROR, tostring(Object), tostring(NewMethodName), debug.traceback(nil :: any, 2)))
end
end

self[Object] = NewMethodName
Expand Down Expand Up @@ -198,7 +206,7 @@ end
function Janitor:AddPromise(PromiseObject)
if FoundPromiseLibrary then
if not Promise.is(PromiseObject) then
error(string.format(NOT_A_PROMISE, typeof(PromiseObject), tostring(PromiseObject)))
error(string.format(NOT_A_PROMISE, typeof(PromiseObject), tostring(PromiseObject), debug.traceback(nil :: any, 2)))
end

if PromiseObject:getStatus() == Promise.Status.Started then
Expand Down Expand Up @@ -469,6 +477,57 @@ end
Janitor.__call = Janitor.Cleanup

--[=[
"Links" this Janitor to an Instance, such that the Janitor will `Cleanup` when the Instance is `Destroyed()` and garbage collected.
A Janitor may only be linked to one instance at a time, unless `AllowMultiple` is true. When called with a truthy `AllowMultiple` parameter,
the Janitor will "link" the Instance without overwriting any previous links, and will also not be overwritable.
When called with a falsy `AllowMultiple` parameter, the Janitor will overwrite the previous link which was also called with a falsy `AllowMultiple` parameter, if applicable.
### Luau:
```lua
local Obliterator = Janitor.new()
Obliterator:Add(function()
print("Cleaning up!")
end, true)
do
local Folder = Instance.new("Folder")
Obliterator:LinkToInstance(Folder)
Folder:Destroy()
end
```
### TypeScript:
```ts
import { Janitor } from "@rbxts/janitor";
const Obliterator = new Janitor();
Obliterator.Add(() => print("Cleaning up!"), true);
{
const Folder = new Instance("Folder");
Obliterator.LinkToInstance(Folder, false);
Folder.Destroy();
}
```
@param Object Instance -- The instance you want to link the Janitor to.
@param AllowMultiple? boolean -- Whether or not to allow multiple links on the same Janitor.
@return RBXScriptConnection -- A RBXScriptConnection that can be disconnected to prevent the cleanup of LinkToInstance.
]=]
function Janitor:LinkToInstance(Object: Instance, AllowMultiple: boolean?): RBXScriptConnection
local IndexToUse = AllowMultiple and newproxy(false) or LinkToInstanceIndex

return self:Add(Object.Destroying:Connect(function()
self:Cleanup()
end), "Disconnect", IndexToUse)
end

--[=[
This is the legacy LinkToInstance function. It is kept for backwards compatibility in case something is different with `Instance.Destroying`.
"Links" this Janitor to an Instance, such that the Janitor will `Cleanup` when the Instance is `Destroyed()` and garbage collected.
A Janitor may only be linked to one instance at a time, unless `AllowMultiple` is true. When called with a truthy `AllowMultiple` parameter,
the Janitor will "link" the Instance without overwriting any previous links, and will also not be overwritable.
Expand Down Expand Up @@ -506,11 +565,12 @@ Janitor.__call = Janitor.Cleanup
}
```
@deprecated v1.4.1 -- Use `Janitor:LinkToInstance` instead.
@param Object Instance -- The instance you want to link the Janitor to.
@param AllowMultiple? boolean -- Whether or not to allow multiple links on the same Janitor.
@return RbxScriptConnection -- A pseudo RBXScriptConnection that can be disconnected to prevent the cleanup of LinkToInstance.
]=]
function Janitor:LinkToInstance(Object: Instance, AllowMultiple: boolean?): RbxScriptConnection
function Janitor:LegacyLinkToInstance(Object: Instance, AllowMultiple: boolean?): RbxScriptConnection
local Connection
local IndexToUse = AllowMultiple and newproxy(false) or LinkToInstanceIndex
local IsNilParented = Object.Parent == nil
Expand Down
100 changes: 94 additions & 6 deletions test/Janitor.spec.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-- TestEZ types (for autocomplete)
type Dictionary<Value> = {[string]: Value}
type DescribeFunction = (Dictionary<any>?) -> nil
type DescribeFunction = (Dictionary<any>?) -> ()

type Expectation = {
never: {
Expand Down Expand Up @@ -30,10 +30,10 @@ type Expectation = {
},
}

type describe = (string, DescribeFunction) -> nil
type describe = (string, DescribeFunction) -> ()
type expect = (any) -> Expectation
type it = describe
type describeSKIP = (string) -> nil
type describeSKIP = (string) -> ()

return function()
local Workspace = game:GetService("Workspace")
Expand Down Expand Up @@ -475,9 +475,6 @@ return function()

expect(WasCleaned).to.equal(true)
NewJanitor:Destroy()
--expect(function()
-- NewJanitor:Destroy()
--end).never.to.throw()
end)

it("should work if the Instance is parented to nil when started", function()
Expand Down Expand Up @@ -538,6 +535,97 @@ return function()
end)
end)

describe("LegacyLinkToInstance", function()
it("should link to an Instance", function()
local NewJanitor = Janitor.new()
local Part = NewJanitor:Add(Instance.new("Part"), "Destroy")
Part.Parent = ReplicatedStorage

expect(function()
NewJanitor:LegacyLinkToInstance(Part)
end).never.to.throw()

NewJanitor:Destroy()
end)

it("should cleanup once the Instance is destroyed", function()
local NewJanitor = Janitor.new()
local WasCleaned = false

local Part = Instance.new("Part")
Part.Parent = Workspace

NewJanitor:Add(function()
WasCleaned = true
end, true)

NewJanitor:LegacyLinkToInstance(Part)

Part:Destroy()
task.wait(0.1)

expect(WasCleaned).to.equal(true)
NewJanitor:Destroy()
end)

it("should work if the Instance is parented to nil when started", function()
local NewJanitor = Janitor.new()
local WasCleaned = false

local Part = Instance.new("Part")
NewJanitor:Add(function()
WasCleaned = true
end, true)

NewJanitor:LegacyLinkToInstance(Part)
Part.Parent = Workspace

Part:Destroy()
task.wait(0.1)

expect(WasCleaned).to.equal(true)
NewJanitor:Destroy()
end)

it("should work if the Instance is parented to nil", function()
local NewJanitor = Janitor.new()
local WasCleaned = false

local Part = Instance.new("Part")
NewJanitor:Add(function()
WasCleaned = true
end, true)

NewJanitor:LegacyLinkToInstance(Part)

Part:Destroy()
task.wait(0.1)

expect(WasCleaned).to.equal(true)
NewJanitor:Destroy()
end)

it("shouldn't run if the Instance is removed or parented to nil", function()
local NewJanitor = Janitor.new()
local Part = Instance.new("Part")
Part.Parent = ReplicatedStorage

NewJanitor:Add(Noop, true, "Function")
NewJanitor:LegacyLinkToInstance(Part)

Part.Parent = nil
expect(NewJanitor:Get("Function")).to.equal(Noop)
Part.Parent = ReplicatedStorage
expect(NewJanitor:Get("Function")).to.equal(Noop)

Part:Destroy()
task.wait(0.1)
expect(function()
NewJanitor:Destroy()
end).never.to.throw()
end)
end)

describe("LinkToInstances", function()
it("should not be tested", function()
expect(not not "i should do this later").to.equal(true)
Expand Down
9 changes: 7 additions & 2 deletions wally.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ description = "A garbage collector object implementation for Roblox, featuring s
license = "MIT"
realm = "shared"
registry = "https://github.com/UpliftGames/wally-index"
version = "1.14.0"
exclude = ["example", "docs", "Packages", ".moonwave", "build", "pages", "test"]
version = "1.14.1"
exclude = [
"docs", ".moonwave", "test",
"Janitor.rbxm", "Janitor.rbxmx", "BuildJanitor.lua",
"changelog.md", "README.md", ".styluaignore", ".gitignore",
"foreman.toml", "Luau.toml", "moonwave.toml", "rotriever.toml", "selene.toml", "stylua.toml", "testez-companion.toml", "testez.toml"
]

[dependencies]

0 comments on commit 85f5484

Please sign in to comment.