Last active
May 20, 2018 09:35
-
-
Save notpeelz/ac7ff23fa1c8498720628d38e9c99528 to your computer and use it in GitHub Desktop.
Lua implementation of tostring(table) docs for OpenComputers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local serialization = require('serialization') | |
local serialize, deserialize = serialization.serialize, serialization.deserialize | |
local stringBuilder = require('stringBuilder') | |
local MAX_LINES = 10 | |
local docsBuilder = {} | |
docsBuilder.MAX_LINES = MAX_LINES | |
function formatValueEntry(value) | |
local sb = stringBuilder() | |
local mspace = '' | |
for s in string.gmatch(value, '[^\r\n]+') do | |
sb.append(mspace .. s) | |
mspace = '\n ' | |
end | |
return sb.value | |
end | |
function isShortKeyAble(key) | |
if type(key) ~= 'string' then return false end | |
if string.match(key, '[0-9].*') == key then return false end | |
if string.match(key, '[a-zA-Z0-9_]+') == key then return true end | |
return false | |
end | |
return setmetatable(docsBuilder, { | |
__call = function(_, obj, maxLines) | |
assert(type(obj) == 'table', 'bad argument #1 (table expected, got ' .. type(obj) .. ')') | |
assert( | |
type(maxLines) == 'number' or type(maxLines) == 'boolean' or maxLines == nil, | |
'bad argument #2 (number, boolean or nil expected, got ' .. type(maxLines) .. ')' | |
) | |
maxLines = maxLines or MAX_LINES | |
if type(maxLines) == 'boolean' then | |
maxLines = maxLines and math.huge or MAX_LINES | |
else | |
assert(maxLines > 0, 'bad argument #2 (nuber greater than 0 expected)') | |
end | |
local builder = {} | |
return setmetatable(builder, { | |
__tostring = function() | |
local sb = stringBuilder() | |
local lineCount = 1 | |
sb.append('{') | |
local i = 0 | |
local mspace = '' | |
function appendMember(name, value) | |
if i ~= #obj and lineCount ~= 1 then | |
sb.append(',\n') | |
end | |
local shortKey = isShortKeyAble(name) | |
local newEntry | |
if shortKey then | |
newEntry = mspace .. name .. '=' .. formatValueEntry(value) | |
else | |
if type(name) == 'boolean' or type(name) == 'number' then | |
newEntry = mspace .. '[' .. name .. ']=' .. formatValueEntry(value) | |
else | |
newEntry = mspace .. '["' .. name .. '"]=' .. formatValueEntry(value) | |
end | |
end | |
if lineCount == 1 then | |
mspace = shortKey and '\x20' or '\x20\x20' | |
end | |
local lines = (function() | |
local t = {} | |
local c = 0 | |
for v in string.gmatch(newEntry, '[^\r\n]+') do | |
c = c + 1 | |
t[c] = v | |
end | |
return t | |
end)() | |
local lineNumber = 0 | |
while lineCount <= maxLines do | |
lineNumber = lineNumber + 1 | |
local line = lines[lineNumber] | |
if line == nil then break end | |
sb.append(line) | |
if lineNumber < #lines then | |
sb.append('\n') | |
end | |
lineCount = lineCount + 1 | |
end | |
end | |
for memberName, member in pairs(obj) do | |
i = i + 1 | |
if lineCount > maxLines then break end | |
local docEntry = builder[memberName] | |
if docEntry == true or docEntry == nil then | |
if type(member) == 'table' then | |
appendMember(memberName, serialize(member, maxLines)) | |
else | |
appendMember(memberName, tostring(member)) | |
end | |
elseif type(docEntry) == 'string' then | |
appendMember(memberName, docEntry) | |
end | |
end | |
if lineCount > maxLines then | |
sb.append(',\n...') | |
else | |
sb.append('}') | |
end | |
return sb.value | |
end | |
}) | |
end | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local stringBuilder = {} | |
local keyBlacklist = {internal = true} | |
return setmetatable({}, { | |
__call = function() | |
local t = {} | |
local props = { | |
value = function() | |
return table.concat(t) | |
end | |
} | |
local methods = { | |
append = function(...) | |
for _, v in ipairs({...}) do | |
table.insert(t, v) | |
end | |
end, | |
remove = function(n) | |
return table.remove(t, n) | |
end, | |
compile = function(...) | |
return table.concat(t, ...) | |
end, | |
len = function() | |
return #t | |
end | |
} | |
local builder = {internal = { t = t }} | |
return setmetatable({}, { | |
__index = function(_, key) | |
if builder[key] then return builder[key] end | |
if props[key] then return props[key]() end | |
return methods[key] | |
end, | |
__newindex = function(_, key, value) | |
builder[key] = value | |
end, | |
__pairs = function() | |
local prevKey | |
local enum = 'builder' | |
local enumProps, enumMethods, enumBuilder | |
enumProps = function() | |
local propKey, propValue = next(props, prevKey) | |
if propKey then | |
prevKey = propKey | |
return propKey, propValue | |
end | |
prevKey = nil | |
enum = 'methods' | |
return enumMethods() | |
end | |
enumMethods = function() | |
local methodKey, methodValue = next(methods, prevKey) | |
if methodKey then | |
prevKey = methodKey | |
return methodKey, methodValue | |
end | |
prevKey = nil | |
enum = 'builder' | |
return -- return nothing (terminates the iterator) | |
end | |
enumBuilder = function() | |
local builderKey, builderValue = next(builder, prevKey) | |
prevKey = builderKey | |
while keyBlacklist[builderKey] ~= nil do | |
builderKey, builderValue = next(builder, prevKey) | |
prevKey = builderKey | |
end | |
if builderKey ~= nil then return builderKey, builderValue end | |
prevKey = nil | |
enum = 'props' | |
return enumProps() | |
end | |
return function() | |
if enum == 'builder' then return enumBuilder() end | |
if enum == 'props' then return enumProps() end | |
if enum == 'methods' then return enumMethods() end | |
error('unexpected stringBuilder iterator error') | |
end | |
end, | |
__len = function(self) | |
local count = 0 | |
for _ in pairs(self) do count = count + 1 end | |
return count | |
end | |
}) | |
end | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment