quad-roblox가 quad-base를 런타임 주입(QuadRoblox(Quad): QuadRoblox)으로만 받으면 pesde 의존 선언이 필요 없어 보이지만, 타입 참조용 require도 런타임에 실제 실행됨을 실측 확인 — dev-dependency로 두면 게시 후 소비자 환경에서 크래시함. 해법으로 구현 없는 타입 계약 전용 워크스페이스 패키지 quad-types 신설, quad-base/quad-roblox 모두 이것만 의존하도록 전환. AddPlugin<Self,P>(self:Self,fn:(Self)->P):Self&P — 제네릭 self로 둬야 체이닝이 누적됨을 실측 확인(고정하면 이전 확장을 잃음), quad-base에 실제 mutate 기반 구현 반영. CheckedQuad<T> 버전 체크는 배선하며 세 번 깨짐 — error() 대신 print+types.never, 함수 본문 로컬 별칭 대신 리턴 타입 표현식에 직접, 그리고 가장 중요하게 type function을 한 번이라도 거친 값(패스스루 포함)은 이후 AddPlugin 같은 제네릭 self 체이닝이 조용히 깨진다는 새 Luau 함정 발견 — typing-limits.md §6으로 승격. 최종 설계(검증 결과를 원본과 격리된 가상 필드로)만 AddPlugin과 완전히 호환. 부수로 quad-base 자신도 quad-types workspace 의존 때문에 CLI symlink 함정(지난 세션 발견)에 걸림 — 로컬 테스트용 symlink 실체화로 임시 우회. Co-authored-by: qwreey <me@qwreey.moe>
55 lines
1.6 KiB
Text
55 lines
1.6 KiB
Text
--[[ 임시 스모크 테스트 — Quad.Version/AddPlugin이 실제로 동작하는지 확인 ]]
|
|
|
|
local Quad = require("../src")
|
|
|
|
print("=== 1. Version 필드가 pesde.toml과 맞음 ===")
|
|
assert(Quad.Version == "0.0.0", "quad-base/pesde.toml의 version과 일치해야 함")
|
|
print("PASS")
|
|
|
|
print()
|
|
print("=== 2. AddPlugin이 원본 identity를 유지한 채(mutate) 확장 필드를 추가함 ===")
|
|
do
|
|
local function springPlugin(_self)
|
|
return {
|
|
Spring = function(_selfArg, v)
|
|
return v * 2
|
|
end,
|
|
}
|
|
end
|
|
|
|
local withSpring = Quad:AddPlugin(springPlugin)
|
|
assert(withSpring == Quad, "AddPlugin은 원본 module을 그대로 mutate+반환해야 함(RunInit 추적이 identity에 의존)")
|
|
assert(withSpring:Spring(21) == 42, "확장된 메소드가 실제로 동작해야 함")
|
|
assert(withSpring.debug == false, "원본 필드는 그대로 남아있어야 함")
|
|
print("PASS")
|
|
end
|
|
|
|
print()
|
|
print("=== 3. 체이닝 — 여러 플러그인을 연속으로 추가해도 전부 누적됨 ===")
|
|
do
|
|
local m = Quad.New()
|
|
|
|
local function pluginA(_self)
|
|
return {
|
|
A = function(_selfArg)
|
|
return "a"
|
|
end,
|
|
}
|
|
end
|
|
local function pluginB(_self)
|
|
return {
|
|
B = function(_selfArg)
|
|
return "b"
|
|
end,
|
|
}
|
|
end
|
|
|
|
local withBoth = m:AddPlugin(pluginA):AddPlugin(pluginB)
|
|
assert(withBoth:A() == "a", "pluginA의 확장 메소드가 동작해야 함")
|
|
assert(withBoth:B() == "b", "pluginB의 확장 메소드가 동작해야 함")
|
|
assert(withBoth.debug == false, "원본 필드는 체이닝 후에도 남아있어야 함")
|
|
print("PASS")
|
|
end
|
|
|
|
print()
|
|
print("=== ALL PASS ===")
|