Refactor table.lua
Reduce Code Duplication Make table.equals work with nested tables Add/Improve assert() for complex functions Add table.match to improve table.searchmaster
parent
b6640b32e5
commit
7b70895ea5
|
@ -1,17 +1,36 @@
|
|||
function table.equals(a, b)
|
||||
for k, v in pairs(a) do
|
||||
if not (b[k] and b[k] == v) then
|
||||
local t2s = minetest.serialize
|
||||
local error_message = [[
|
||||
Function %s does not pass self-test!
|
||||
Expected results: %s
|
||||
Test Results: %s
|
||||
]]
|
||||
|
||||
local function half_equals(t1, t2)
|
||||
for k, v in pairs(t1) do
|
||||
if not t2[k] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
for k, v in pairs(b) do
|
||||
if not (a[k] and a[k] == v) then
|
||||
elseif (type(v) == "table") then
|
||||
if not half_equals(t2[k], v) then
|
||||
return false
|
||||
end
|
||||
elseif not (t2[k] == v) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function table.equals(t1, t2)
|
||||
if half_equals(t1, t2) and half_equals(t2, t1) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
assert(table.equals({"a", "b", c = "d", e = {"f", "g", "h", {"h"}}}, {"a", "b", c = "d", e = {"f", "g", "h", {"h"}}}))
|
||||
assert(not table.equals({a = 1}, {a = 2}))
|
||||
|
||||
function table.shuffle(t)
|
||||
for i = #t, 2, -1 do
|
||||
local j = math.random(i)
|
||||
|
@ -28,13 +47,41 @@ end
|
|||
|
||||
function table.is_in(t, value)
|
||||
for _, v in ipairs(t) do
|
||||
if v == value then
|
||||
if (type(value) == "table") and table.equals(t, value) then
|
||||
return true
|
||||
elseif v == value then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Returns matching values between two tables
|
||||
function table.match(t1, t2)
|
||||
local results = {}
|
||||
for k, v in pairs(t2) do
|
||||
if (type(k) == "number") and table.is_in(t1, v) then
|
||||
table.insert(results, v)
|
||||
elseif not t1[k] then
|
||||
break
|
||||
elseif type(v) == "table" then
|
||||
local tmp_tbl = table.match(t1[k], v)
|
||||
if not table.equals(tmp_tbl, {}) then
|
||||
results[k] = tmp_tbl
|
||||
end
|
||||
elseif t1[k] == t2[k] then
|
||||
results[k] = v
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
local match_test_table = {"foo", "bar", bar = {1, 2, 3}, baz = "boo", foo = {"baz"}}
|
||||
local match_expected_results = {"foo", bar = {1, 3}, baz = "boo"}
|
||||
local match_test_results = table.match(match_test_table, {"foo", bar = {1, 3}, baz = "boo", "furb", foo = {"bar"}})
|
||||
local match_error_message = error_message:format("table.match", t2s(match_expected_results), t2s(match_test_results))
|
||||
assert(table.equals(match_expected_results, match_test_results), match_error_message)
|
||||
|
||||
-- Returns a sub-set of an indexed table which matches the given parameters
|
||||
function table.search(t, params)
|
||||
params = params or {}
|
||||
|
@ -43,30 +90,10 @@ function table.search(t, params)
|
|||
local results = {}
|
||||
|
||||
for _, entree in ipairs(t) do
|
||||
local should_include = true
|
||||
for key, value in pairs(params.includes) do
|
||||
if type(value) == "table" then
|
||||
for _, v in ipairs(value) do
|
||||
if (not entree[key]) or (not table.is_in(entree[key], v)) then
|
||||
should_include = false
|
||||
end
|
||||
end
|
||||
elseif (entree[key] == nil) or (entree[key] ~= value) then
|
||||
should_include = false
|
||||
end
|
||||
end
|
||||
for key, value in pairs(params.excludes) do
|
||||
if type(value) == "table" then
|
||||
for _, v in ipairs(value) do
|
||||
if entree[key] and (table.is_in(entree[key], v)) then
|
||||
should_include = false
|
||||
end
|
||||
end
|
||||
elseif entree[key] and entree[key] == value then
|
||||
should_include = false
|
||||
end
|
||||
end
|
||||
if should_include then
|
||||
local includes_match = table.match(entree, params.includes)
|
||||
local excludes_match = table.match(entree, params.excludes)
|
||||
|
||||
if table.equals(includes_match, params.includes) and table.equals(excludes_match, {}) then
|
||||
table.insert(results, entree)
|
||||
end
|
||||
end
|
||||
|
@ -74,7 +101,7 @@ function table.search(t, params)
|
|||
return results
|
||||
end
|
||||
|
||||
local test_table = {
|
||||
local search_test_table = {
|
||||
{tags = {"a", "b", "c"}, num = 1, num2 = 3},
|
||||
{tags = {"b", "c"}, num = 1, num2 = 4},
|
||||
{tags = {"b"}, num = 2, num2 = 3},
|
||||
|
@ -82,15 +109,9 @@ local test_table = {
|
|||
{tags = {"a", "b"}, num = 1, num2 = 3},
|
||||
}
|
||||
|
||||
local expected_results = {test_table[4]}
|
||||
|
||||
local test_results = table.search(test_table, {includes = {tags = {"b"}, num = 1}, excludes = {tags = {"a"}, num2 = 4}})
|
||||
|
||||
local error_message = [[
|
||||
Function table.search does not pass self-test!
|
||||
Expected results: %s
|
||||
Test Results: %s
|
||||
]]
|
||||
error_message:format(minetest.serialize(expected_results), minetest.serialize(test_results))
|
||||
|
||||
assert(table.equals(test_results, expected_results), error_message)
|
||||
local search_expected_results = {search_test_table[4]}
|
||||
local search_test_results = table.search(search_test_table,
|
||||
{includes = {tags = {"b"}, num = 1}, excludes = {tags = {"a"}, num2 = 4}})
|
||||
local search_error_message =
|
||||
error_message:format("table.search", t2s(search_expected_results), t2s(search_test_results))
|
||||
assert(table.equals(search_test_results, search_expected_results), search_error_message)
|
||||
|
|
Loading…
Reference in New Issue