It would make it much easier to program complex systems if require statements could be used.
This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
Support Lua require
Started by DrSpork, 18 November 2012 - 11:39 AMPosted 18 November 2012 - 12:39 PM
Provided the Lua engine you use supports it, the require statement provides a more convenient and robust way to import functions vs. CC's built in API system (e.g. Metatables work properly, Can change the namespace the file uses, etc.)
It would make it much easier to program complex systems if require statements could be used.
It would make it much easier to program complex systems if require statements could be used.
Posted 18 November 2012 - 12:50 PM
The LuaJ library supports it - but it is disabled (for good reason, it allowed Java classes to be loaded including the LuaJ native IO). I do however plan to allow API's to have metatables providing it can be done without causing any security issues (highly likely).
Posted 18 November 2012 - 12:57 PM
Ahh, OK. Thanks for the response. Sucks that the LuaJ version has that many security holes.
Posted 18 November 2012 - 01:04 PM
To be quite honest it would be easy to code require yourself in Lua - but once loadAPI supports metatables all should be fine.
Posted 18 November 2012 - 01:33 PM
Any articles on this you know of the top of your head to link me to? My current project could use this.To be quite honest it would be easy to code require yourself in Lua - but once loadAPI supports metatables all should be fine.
Posted 18 November 2012 - 07:31 PM
Will this work or will it become security hole?To be quite honest it would be easy to code require yourself in Lua - but once loadAPI supports metatables all should be fine.
Spoiler
local tAPIsLoading = {}
function os.loadAPI( _sPath )
local sName = fs.getName( _sPath )
if tAPIsLoading[sName] == true then
printError( "API "..sName.." is already being loaded" )
return false
end
tAPIsLoading[sName] = true
local tEnv = {}
setmetatable( tEnv, { __index = _G } )
local fnAPI, err = loadfile( _sPath )
if fnAPI then
setfenv( fnAPI, tEnv )
fnAPI()
else
printError( err )
tAPIsLoading[sName] = nil
return false
end
local tAPImt=getmetatable(tENV)
if tAPImt.__index == _G then
tAPImt.__index = nil
end
_G[sName] = tENV
tAPIsLoading[sName] = nil
return true
end
Posted 18 November 2012 - 07:53 PM
Will this work or will it become security hole?To be quite honest it would be easy to code require yourself in Lua - but once loadAPI supports metatables all should be fine.Spoiler
local tAPIsLoading = {} function os.loadAPI( _sPath ) local sName = fs.getName( _sPath ) if tAPIsLoading[sName] == true then printError( "API "..sName.." is already being loaded" ) return false end tAPIsLoading[sName] = true local tEnv = {} setmetatable( tEnv, { __index = _G } ) local fnAPI, err = loadfile( _sPath ) if fnAPI then setfenv( fnAPI, tEnv ) fnAPI() else printError( err ) tAPIsLoading[sName] = nil return false end local tAPImt=getmetatable(tENV) if tAPImt.__index == _G then tAPImt.__index = nil end _G[sName] = tENV tAPIsLoading[sName] = nil return true end
It will stop the API from being able to access _G once it's loaded (unless it saves it in a local variable)
Posted 18 November 2012 - 08:41 PM
Thanks. I did not thought about it :)/>/>It will stop the API from being able to access _G once it's loaded (unless it saves it in a local variable)
Would this variant be better? API can return value needed or old default scheme used. No APIs needs to be rewritten.
Spoiler
local tAPIsLoading = {}
function os.loadAPI( _sPath )
local sName = fs.getName( _sPath )
if tAPIsLoading[sName] == true then
printError( "API "..sName.." is already being loaded" )
return false
end
tAPIsLoading[sName] = true
local tEnv = {}
setmetatable( tEnv, { __index = _G } )
local fnAPI, err = loadfile( _sPath )
if fnAPI then
setfenv( fnAPI, tEnv )
local tAPI = fnAPI()
if not tAPI then
tAPI = {}
for k,v in pairs( tEnv ) do
tAPI[k] = v
end
end
_G[sName] = tAPI
tAPIsLoading[sName] = nil
return true
else
printError( err )
tAPIsLoading[sName] = nil
return false
end
end
Posted 19 November 2012 - 12:55 AM
That would workThanks. I did not thought about it :)/>/>It will stop the API from being able to access _G once it's loaded (unless it saves it in a local variable)
Would this variant be better? API can return value needed or old default scheme used. No APIs needs to be rewritten.Spoiler
local tAPIsLoading = {} function os.loadAPI( _sPath ) local sName = fs.getName( _sPath ) if tAPIsLoading[sName] == true then printError( "API "..sName.." is already being loaded" ) return false end tAPIsLoading[sName] = true local tEnv = {} setmetatable( tEnv, { __index = _G } ) local fnAPI, err = loadfile( _sPath ) if fnAPI then setfenv( fnAPI, tEnv ) local tAPI = fnAPI() if not tAPI then tAPI = {} for k,v in pairs( tEnv ) do tAPI[k] = v end end _G[sName] = tAPI tAPIsLoading[sName] = nil return true else printError( err ) tAPIsLoading[sName] = nil return false end end
Posted 19 November 2012 - 02:24 AM
This was creater proir to seeing this suggestion but as it's kind of relevant I thought I would post it;
Would this suffice or are you looking for something more/less/different?
http://www.computercraft.info/forums2/index.php?/topic/6101-api-classy-classes-in-lua-v11-inheritance/
Would this suffice or are you looking for something more/less/different?
http://www.computercraft.info/forums2/index.php?/topic/6101-api-classy-classes-in-lua-v11-inheritance/
Posted 19 November 2012 - 02:33 AM
Thanks. I did not thought about it :)/>/>It will stop the API from being able to access _G once it's loaded (unless it saves it in a local variable)
Would this variant be better? API can return value needed or old default scheme used. No APIs needs to be rewritten.Spoiler
local tAPIsLoading = {} function os.loadAPI( _sPath ) local sName = fs.getName( _sPath ) if tAPIsLoading[sName] == true then printError( "API "..sName.." is already being loaded" ) return false end tAPIsLoading[sName] = true local tEnv = {} setmetatable( tEnv, { __index = _G } ) local fnAPI, err = loadfile( _sPath ) if fnAPI then setfenv( fnAPI, tEnv ) local tAPI = fnAPI() if not tAPI then tAPI = {} for k,v in pairs( tEnv ) do tAPI[k] = v end end _G[sName] = tAPI tAPIsLoading[sName] = nil return true else printError( err ) tAPIsLoading[sName] = nil return false end end
I like it! I'll speak to dan and see what he thinks.
Posted 19 November 2012 - 03:34 AM
Thanks! Yet another time :)/>/>
Posted 19 November 2012 - 06:48 AM
I tried using that version of loadAPI (renaming it and dropping it into my file), and it loads OK, but metatables still break. I can still get the metatable using getmetatable(), and I can do getmetatable(object).functionName(), but not object.functionName().
Posted 19 November 2012 - 09:22 AM
That's because you would do object:functionName(), right? And the function would have to be defined like that in the API as well. The dot notation works only for the metatables themselves. You could of course create the objects with the functions as a member, that's a whole different deal.I tried using that version of loadAPI (renaming it and dropping it into my file), and it loads OK, but metatables still break. I can still get the metatable using getmetatable(), and I can do getmetatable(object).functionName(), but not object.functionName().
Posted 19 November 2012 - 09:32 AM
Have you __index in metatable?I tried using that version of loadAPI (renaming it and dropping it into my file), and it loads OK, but metatables still break. I can still get the metatable using getmetatable(), and I can do getmetatable(object).functionName(), but not object.functionName().
Posted 19 November 2012 - 10:02 AM
Yes , I do. It works fine when run from the same file. I know you use : to call the function but using . allows you to print out the id of the function (cause I was testing if it existed by doing print(object.functionName))Have you __index in metatable?
EDIT: I just checked and it works fine if I dofile() in the api file. I lose the namespacing though :)/>/>
EDIT 2: Never mind, fixed, now it works with that version of os.LoadAPI. I had it defined like this:
Class = {}
Class:function(a,:D/>/>
SOMETHING
end
And turns out it only works if you do
Class = {
function = function(self,a,:D/>/>{
SOMETHING
}
}
Posted 20 November 2012 - 11:45 AM
I just finished part of my plan to implement a proper require, which is providing an efficient search function that can use glob's.
EDIT: just noticed require doesn't do that much, it just replaces ? wih the file to be loaded..oh well, I'll call it an improvement!
Check it out here if interested. It's also there in github, folow the link!
EDIT: just noticed require doesn't do that much, it just replaces ? wih the file to be loaded..oh well, I'll call it an improvement!
Check it out here if interested. It's also there in github, folow the link!
Posted 22 November 2012 - 01:37 PM
snip
I've implemented require. Check it out if interested:
http://www.computercraft.info/forums2/index.php?/topic/6286-loadreq-api-require-implemented-in-ccsome-goodies/