1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-24 06:03:28 +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:
SquidDev 2019-07-09 08:04:49 +01:00 committed by GitHub
parent e05c262468
commit bafab1ac07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 102 additions and 86 deletions

View File

@ -1,48 +1,19 @@
local native_select, native_type = select, type
--- Expect an argument to have a specific type.
-- Load in expect from the module path.
--
-- @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
-- Ideally we'd use require, but that is part of the shell, and so is not
-- available to the BIOS or any APIs. All APIs load this using dofile, but that
-- has not been defined at this point.
local expect
local types = table.pack(...)
for i = types.n, 1, -1 do
if types[i] == "nil" then table.remove(types, i) end
end
do
local h = fs.open("rom/modules/main/craftos/expect.lua", "r")
local f, err = loadstring(h.readAll(), "@expect.lua")
h.close()
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
if not f then error(err) end
expect = f().expect
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 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

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
-- Colors
white = 1

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
CHANNEL_GPS = 65534

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
local sPath = "/rom/help"

View File

@ -1,6 +1,6 @@
-- 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.
-- We use this weird wrapper function as we wish to preserve the varargs

View File

@ -1,7 +1,7 @@
-- Minecraft key code bindings
-- 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 = {
nil, "one", "two", "three", "four", -- 1

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
local function drawPixelInternal( xPos, yPos )
term.setCursorPos( xPos, yPos )

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
local native = peripheral

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
CHANNEL_BROADCAST = 65535
CHANNEL_REPEAT = 65533

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
local tSettings = {}

View File

@ -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 redirectTarget = native

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
function slowWrite( sText, nRate )
expect(2, nRate, "number", "nil")

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
local tHex = {
[ colors.white ] = "0",

View File

@ -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 }

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
-- Setup process switching
local parentTerm = term.current()

View File

@ -1,4 +1,4 @@
local expect = _G["~expect"]
local expect = dofile("rom/modules/main/craftos/expect.lua").expect
local multishell = multishell
local parentShell = shell

View File

@ -1,36 +1,4 @@
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()
it("validates arguments", function()
sleep(0)

View 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)