Skip to content
This repository has been archived by the owner on Dec 13, 2023. It is now read-only.

Expose access to GetPropertyChangedSignal, take two #51

Merged
merged 8 commits into from
Mar 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions lib/Change.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
local Change = {}

local changeMetatable = {
__tostring = function(self)
return ("ChangeListener(%s)"):format(self.name)
end
}

setmetatable(Change, {
__index = function(self, propertyName)
local changeListener = {
type = Change,
name = propertyName
}

setmetatable(changeListener, changeMetatable)
Change[propertyName] = changeListener

return changeListener
end,
})

return Change
15 changes: 15 additions & 0 deletions lib/Change.spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
return function()
local Change = require(script.Parent.Change)

it("should yield change listener objects when indexed", function()
expect(Change.Text).to.be.ok()
expect(Change.Selected).to.be.ok()
end)

it("should yield the same object when indexed again", function()
local a = Change.Text
local b = Change.Text

expect(a).to.equal(b)
end)
end
5 changes: 4 additions & 1 deletion lib/Reconciler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

local Core = require(script.Parent.Core)
local Event = require(script.Parent.Event)
local Change = require(script.Parent.Change)
local getDefaultPropertyValue = require(script.Parent.getDefaultPropertyValue)
local SingleEventManager = require(script.Parent.SingleEventManager)
local Symbol = require(script.Parent.Symbol)
Expand Down Expand Up @@ -512,6 +513,8 @@ function Reconciler._setRbxProp(rbx, key, value, element)

if key.type == Event then
Reconciler._singleEventManager:connect(rbx, key.name, value)
elseif key.type == Change then
Reconciler._singleEventManager:connectProperty(rbx, key.name, value)
else
local source = element.source or DEFAULT_SOURCE

Expand Down Expand Up @@ -539,4 +542,4 @@ function Reconciler._setRbxProp(rbx, key, value, element)
end
end

return Reconciler
return Reconciler
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like files' trailing newlines keep getting shuffled there and back, I feel like I should normalize those.

In the meantime, do you have an EditorConfig plugin enabled for your editor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do, but sometimes it doesn't work (see all the times my commits sometimes get spaces instead of tabs).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What editor do you use? The one for Sublime Text seems to horrifically break the automatic indentation detection. :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VS Code and this extension.

45 changes: 44 additions & 1 deletion lib/SingleEventManager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ local function createHook(rbx, key, method)
return hook
end

local function createChangeHook(rbx, key, method)
local hook = {
method = method,
connection = rbx:GetPropertyChangedSignal(key):Connect(function(...)
method(rbx, ...)
end)
}

return hook
end

local function formatChangeKey(key)
return ("!PropertyChangeEvent:%s"):format(key)
end

function SingleEventManager.new()
local self = {}

Expand Down Expand Up @@ -64,6 +79,30 @@ function SingleEventManager:connect(rbx, key, method)
end
end

function SingleEventManager:connectProperty(rbx, key, method)
local rbxHooks = self._hookCache[rbx]
local formattedKey = formatChangeKey(key)

if rbxHooks then
local existingHook = rbxHooks[formattedKey]

if existingHook then
if existingHook.method == method then
return
end

existingHook.connection:Disconnect()
end

rbxHooks[formattedKey] = createChangeHook(rbx, key, method)
else
rbxHooks = {}
rbxHooks[formattedKey] = createChangeHook(rbx, key, method)

self._hookCache[rbx] = rbxHooks
end
end

function SingleEventManager:disconnect(rbx, key)
local rbxHooks = self._hookCache[rbx]

Expand All @@ -85,6 +124,10 @@ function SingleEventManager:disconnect(rbx, key)
end
end

function SingleEventManager:disconnectProperty(rbx, key)
self:disconnect(rbx, formatChangeKey(key))
end

function SingleEventManager:disconnectAll(rbx)
local rbxHooks = self._hookCache[rbx]

Expand All @@ -99,4 +142,4 @@ function SingleEventManager:disconnectAll(rbx)
self._hookCache[rbx] = nil
end

return SingleEventManager
return SingleEventManager
86 changes: 86 additions & 0 deletions lib/SingleEventManager.spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,57 @@ return function()
end)
end)

describe("connectProperty", function()
it("should connect to property changes", function()
local target = Instance.new("BindableEvent")
local manager = SingleEventManager.new()

local changeCount = 0

manager:connectProperty(target, "Name", function(rbx)
changeCount = changeCount + 1
end)

target.Name = "hi"
expect(changeCount).to.equal(1)
end)

it("should disconnect the existing connection if present", function()
local target = Instance.new("IntValue")
local manager = SingleEventManager.new()

local changeCountA = 0
local changeCountB = 0

manager:connectProperty(target, "Name", function(rbx)
changeCountA = changeCountA + 1
end)

manager:connectProperty(target, "Name", function(rbx)
changeCountB = changeCountB + 1
end)

target.Name = "hi"
expect(changeCountA).to.equal(0)
expect(changeCountB).to.equal(1)
end)

it("should only connect to the property specified", function()
local target = Instance.new("IntValue")
local manager = SingleEventManager.new()

local changeCount = 0

manager:connectProperty(target, "Name", function(rbx)
changeCount = changeCount + 1
end)

target.Name = "hi"
target.Value = 0
expect(changeCount).to.equal(1)
end)
end)

describe("disconnect", function()
it("should disconnect handlers on an object", function()
local target = Instance.new("BindableEvent")
Expand Down Expand Up @@ -146,13 +197,41 @@ return function()
end)
end)

describe("disconnectProperty", function()
it("should disconnect property change handlers on an object", function()
local target = Instance.new("IntValue")
local manager = SingleEventManager.new()

local changeCount = 0

manager:connectProperty(target, "Name", function(rbx)
changeCount = changeCount + 1
end)

target.Name = "hi"
expect(changeCount).to.equal(1)

manager:disconnectProperty(target, "Name")
target.Name = "test"
expect(changeCount).to.equal(1)
end)

it("should succeed even if no handler is attached", function()
local target = Instance.new("IntValue")
local manager = SingleEventManager.new()

manager:disconnectProperty(target, "Name")
end)
end)

describe("disconnectAll", function()
it("should disconnect all listeners on an object", function()
local target = Instance.new("BindableEvent")
local manager = SingleEventManager.new()

local callCountEvent = 0
local callCountChanged = 0
local changeCount = 0

manager:connect(target, "Event", function(rbx)
expect(rbx).to.equal(target)
Expand All @@ -164,11 +243,17 @@ return function()
callCountChanged = callCountChanged + 1
end)

manager:connectProperty(target, "Name", function(rbx)
expect(rbx).to.equal(target)
changeCount = changeCount + 1
end)

target:Fire()
target.Name = "bar"

expect(callCountEvent).to.equal(1)
expect(callCountChanged).to.equal(1)
expect(changeCount).to.equal(1)

manager:disconnectAll(target)

Expand All @@ -177,6 +262,7 @@ return function()

expect(callCountEvent).to.equal(1)
expect(callCountChanged).to.equal(1)
expect(changeCount).to.equal(1)
end)

it("should succeed with no events attached", function()
Expand Down
2 changes: 2 additions & 0 deletions lib/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
local Component = require(script.Component)
local Core = require(script.Core)
local Event = require(script.Event)
local Change = require(script.Change)
local GlobalConfig = require(script.GlobalConfig)
local PureComponent = require(script.PureComponent)
local Reconciler = require(script.Reconciler)
Expand Down Expand Up @@ -37,6 +38,7 @@ apply(Roact, {
Component = Component,
PureComponent = PureComponent,
Event = Event,
Change = Change,
})

apply(Roact, {
Expand Down
1 change: 1 addition & 0 deletions lib/init.spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ return function()
expect(Roact.Portal).to.be.ok()
expect(Roact.Children).to.be.ok()
expect(Roact.Event).to.be.ok()
expect(Roact.Change).to.be.ok()
expect(Roact.Ref).to.be.ok()
expect(Roact.None).to.be.ok()
end)
Expand Down