mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-03-24 04:16:58 +00:00
Expose expect as a module (#267)
This moves expect from the bios into a new craftos.expect module, removing the internal _G["~expect"] definition. Apparently people were using this irrespective of the "don't use this" comment, so we need to find another solution. While this does introduce some ugliness (having to load the module in weird ways for programs, duplicating the expect function in memory), it does allow people to use the function in a supported way, and removes the global ugliness.
This commit is contained in:
parent
e05c262468
commit
bafab1ac07
src
main/resources/assets/computercraft/lua
bios.lua
rom
apis
colors.luagps.luahelp.luaio.luakeys.luapaintutils.luaperipheral.luarednet.luasettings.luaterm.luatextutils.luawindow.lua
modules/main/craftos
programs
test/resources/test-rom/spec
@ -1,48 +1,19 @@
|
|||||||
local native_select, native_type = select, type
|
-- Load in expect from the module path.
|
||||||
|
|
||||||
--- Expect an argument to have a specific type.
|
|
||||||
--
|
--
|
||||||
-- @tparam int index The 1-based argument index.
|
-- Ideally we'd use require, but that is part of the shell, and so is not
|
||||||
-- @param value The argument's value.
|
-- available to the BIOS or any APIs. All APIs load this using dofile, but that
|
||||||
-- @tparam string ... The allowed types of the argument.
|
-- has not been defined at this point.
|
||||||
-- @throws If the value is not one of the allowed types.
|
local expect
|
||||||
local function expect(index, value, ...)
|
|
||||||
local t = native_type(value)
|
|
||||||
for i = 1, native_select("#", ...) do
|
|
||||||
if t == native_select(i, ...) then return true end
|
|
||||||
end
|
|
||||||
|
|
||||||
local types = table.pack(...)
|
do
|
||||||
for i = types.n, 1, -1 do
|
local h = fs.open("rom/modules/main/craftos/expect.lua", "r")
|
||||||
if types[i] == "nil" then table.remove(types, i) end
|
local f, err = loadstring(h.readAll(), "@expect.lua")
|
||||||
end
|
h.close()
|
||||||
|
|
||||||
local type_names
|
if not f then error(err) end
|
||||||
if #types <= 1 then
|
expect = f().expect
|
||||||
type_names = tostring(...)
|
|
||||||
else
|
|
||||||
type_names = table.concat(types, ", ", 1, #types - 1) .. " or " .. types[#types]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- If we can determine the function name with a high level of confidence, try to include it.
|
|
||||||
local name
|
|
||||||
if native_type(debug) == "table" and native_type(debug.getinfo) == "function" then
|
|
||||||
local ok, info = pcall(debug.getinfo, 3, "nS")
|
|
||||||
if ok and info.name and #info.name ~= "" and info.what ~= "C" then name = info.name end
|
|
||||||
end
|
|
||||||
|
|
||||||
if name then
|
|
||||||
error( ("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3 )
|
|
||||||
else
|
|
||||||
error( ("bad argument #%d (expected %s, got %s)"):format(index, type_names, t), 3 )
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- We expose expect in the global table as APIs need to access it, but give it
|
|
||||||
-- a non-identifier name - meaning it does not show up in auto-completion.
|
|
||||||
-- expect is an internal function, and should not be used by users.
|
|
||||||
_G["~expect"] = expect
|
|
||||||
|
|
||||||
if _VERSION == "Lua 5.1" then
|
if _VERSION == "Lua 5.1" then
|
||||||
-- If we're on Lua 5.1, install parts of the Lua 5.2/5.3 API so that programs can be written against it
|
-- If we're on Lua 5.1, install parts of the Lua 5.2/5.3 API so that programs can be written against it
|
||||||
local type = type
|
local type = type
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
-- Colors
|
-- Colors
|
||||||
white = 1
|
white = 1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
CHANNEL_GPS = 65534
|
CHANNEL_GPS = 65534
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
local sPath = "/rom/help"
|
local sPath = "/rom/help"
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
-- Definition for the IO API
|
-- Definition for the IO API
|
||||||
|
|
||||||
local expect, typeOf = _G["~expect"], _G.type
|
local expect, typeOf = dofile("rom/modules/main/craftos/expect.lua").expect, _G.type
|
||||||
|
|
||||||
--- If we return nil then close the file, as we've reached the end.
|
--- If we return nil then close the file, as we've reached the end.
|
||||||
-- We use this weird wrapper function as we wish to preserve the varargs
|
-- We use this weird wrapper function as we wish to preserve the varargs
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
-- Minecraft key code bindings
|
-- Minecraft key code bindings
|
||||||
-- See http://www.minecraftwiki.net/wiki/Key_codes for more info
|
-- See http://www.minecraftwiki.net/wiki/Key_codes for more info
|
||||||
|
|
||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
local tKeys = {
|
local tKeys = {
|
||||||
nil, "one", "two", "three", "four", -- 1
|
nil, "one", "two", "three", "four", -- 1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
local function drawPixelInternal( xPos, yPos )
|
local function drawPixelInternal( xPos, yPos )
|
||||||
term.setCursorPos( xPos, yPos )
|
term.setCursorPos( xPos, yPos )
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
local native = peripheral
|
local native = peripheral
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
CHANNEL_BROADCAST = 65535
|
CHANNEL_BROADCAST = 65535
|
||||||
CHANNEL_REPEAT = 65533
|
CHANNEL_REPEAT = 65533
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
local tSettings = {}
|
local tSettings = {}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
local native = (term.native and term.native()) or term
|
local native = (term.native and term.native()) or term
|
||||||
local redirectTarget = native
|
local redirectTarget = native
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
function slowWrite( sText, nRate )
|
function slowWrite( sText, nRate )
|
||||||
expect(2, nRate, "number", "nil")
|
expect(2, nRate, "number", "nil")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
local tHex = {
|
local tHex = {
|
||||||
[ colors.white ] = "0",
|
[ colors.white ] = "0",
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
--- The @{craftos.expect} library provides helper functions for verifying that
|
||||||
|
-- function arguments are well-formed and of the correct type.
|
||||||
|
--
|
||||||
|
-- @module craftos.expect
|
||||||
|
|
||||||
|
local native_select, native_type = select, type
|
||||||
|
|
||||||
|
--- Expect an argument to have a specific type.
|
||||||
|
--
|
||||||
|
-- @tparam int index The 1-based argument index.
|
||||||
|
-- @param value The argument's value.
|
||||||
|
-- @tparam string ... The allowed types of the argument.
|
||||||
|
-- @throws If the value is not one of the allowed types.
|
||||||
|
local function expect(index, value, ...)
|
||||||
|
local t = native_type(value)
|
||||||
|
for i = 1, native_select("#", ...) do
|
||||||
|
if t == native_select(i, ...) then return true end
|
||||||
|
end
|
||||||
|
|
||||||
|
local types = table.pack(...)
|
||||||
|
for i = types.n, 1, -1 do
|
||||||
|
if types[i] == "nil" then table.remove(types, i) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local type_names
|
||||||
|
if #types <= 1 then
|
||||||
|
type_names = tostring(...)
|
||||||
|
else
|
||||||
|
type_names = table.concat(types, ", ", 1, #types - 1) .. " or " .. types[#types]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we can determine the function name with a high level of confidence, try to include it.
|
||||||
|
local name
|
||||||
|
if native_type(debug) == "table" and native_type(debug.getinfo) == "function" then
|
||||||
|
local ok, info = pcall(debug.getinfo, 3, "nS")
|
||||||
|
if ok and info.name and #info.name ~= "" and info.what ~= "C" then name = info.name end
|
||||||
|
end
|
||||||
|
|
||||||
|
if name then
|
||||||
|
error( ("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3 )
|
||||||
|
else
|
||||||
|
error( ("bad argument #%d (expected %s, got %s)"):format(index, type_names, t), 3 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { expect = expect }
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
-- Setup process switching
|
-- Setup process switching
|
||||||
local parentTerm = term.current()
|
local parentTerm = term.current()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
local expect = _G["~expect"]
|
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
|
||||||
|
|
||||||
local multishell = multishell
|
local multishell = multishell
|
||||||
local parentShell = shell
|
local parentShell = shell
|
||||||
|
@ -1,36 +1,4 @@
|
|||||||
describe("The Lua base library", function()
|
describe("The Lua base library", function()
|
||||||
describe("expect", function()
|
|
||||||
local e = _G["~expect"]
|
|
||||||
|
|
||||||
it("checks a single type", function()
|
|
||||||
expect(e(1, "test", "string")):eq(true)
|
|
||||||
expect(e(1, 2, "number")):eq(true)
|
|
||||||
|
|
||||||
expect.error(e, 1, nil, "string"):eq("bad argument #1 (expected string, got nil)")
|
|
||||||
expect.error(e, 2, 1, "nil"):eq("bad argument #2 (expected nil, got number)")
|
|
||||||
end)
|
|
||||||
|
|
||||||
it("checks multiple types", function()
|
|
||||||
expect(e(1, "test", "string", "number")):eq(true)
|
|
||||||
expect(e(1, 2, "string", "number")):eq(true)
|
|
||||||
|
|
||||||
expect.error(e, 1, nil, "string", "number"):eq("bad argument #1 (expected string or number, got nil)")
|
|
||||||
expect.error(e, 2, false, "string", "table", "number", "nil")
|
|
||||||
:eq("bad argument #2 (expected string, table or number, got boolean)")
|
|
||||||
end)
|
|
||||||
|
|
||||||
it("includes the function name", function()
|
|
||||||
local function worker()
|
|
||||||
expect(e(1, nil, "string")):eq(true)
|
|
||||||
end
|
|
||||||
local function trampoline()
|
|
||||||
worker()
|
|
||||||
end
|
|
||||||
|
|
||||||
expect.error(trampoline):eq("base_spec.lua:27: bad argument #1 to 'worker' (expected string, got nil)")
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|
|
||||||
describe("sleep", function()
|
describe("sleep", function()
|
||||||
it("validates arguments", function()
|
it("validates arguments", function()
|
||||||
sleep(0)
|
sleep(0)
|
||||||
|
31
src/test/resources/test-rom/spec/modules/expect_spec.lua
Normal file
31
src/test/resources/test-rom/spec/modules/expect_spec.lua
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
describe("craftos.expect", function()
|
||||||
|
local e = require("craftos.expect")
|
||||||
|
|
||||||
|
it("checks a single type", function()
|
||||||
|
expect(e.expect(1, "test", "string")):eq(true)
|
||||||
|
expect(e.expect(1, 2, "number")):eq(true)
|
||||||
|
|
||||||
|
expect.error(e.expect, 1, nil, "string"):eq("bad argument #1 (expected string, got nil)")
|
||||||
|
expect.error(e.expect, 2, 1, "nil"):eq("bad argument #2 (expected nil, got number)")
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("checks multiple types", function()
|
||||||
|
expect(e.expect(1, "test", "string", "number")):eq(true)
|
||||||
|
expect(e.expect(1, 2, "string", "number")):eq(true)
|
||||||
|
|
||||||
|
expect.error(e.expect, 1, nil, "string", "number"):eq("bad argument #1 (expected string or number, got nil)")
|
||||||
|
expect.error(e.expect, 2, false, "string", "table", "number", "nil")
|
||||||
|
:eq("bad argument #2 (expected string, table or number, got boolean)")
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("includes the function name", function()
|
||||||
|
local function worker()
|
||||||
|
expect(e.expect(1, nil, "string")):eq(true)
|
||||||
|
end
|
||||||
|
local function trampoline()
|
||||||
|
worker()
|
||||||
|
end
|
||||||
|
|
||||||
|
expect.error(trampoline):eq("expect_spec.lua:26: bad argument #1 to 'worker' (expected string, got nil)")
|
||||||
|
end)
|
||||||
|
end)
|
Loading…
x
Reference in New Issue
Block a user