This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
oeed's profile picture

Inherited Key Include

Started by oeed, 15 March 2013 - 09:05 AM
oeed #1
Posted 15 March 2013 - 10:05 AM
Essentially what I am trying to do is make a custom include function so that if I include the file 'One' and that contains an include to file 'Two', Two becomes One.Two

For example:

Startup or whatever

include("One")
print(One.Two) --should be Testing123

One

include("Two")

Two

return "Testing123"

So essentially rather than two being _G.Two I would like it to be _G.One.Two

The way I've been trying to do it doesn't really work. Anyone have a suggestion on how to do this?
Lyqyd #2
Posted 15 March 2013 - 10:14 AM
Try customizing os.loadAPI. It nearly has the functionality you're looking for. getfenv() maaay be able to get you the rest of the way there.
oeed #3
Posted 15 March 2013 - 10:21 AM
Try customizing os.loadAPI. It nearly has the functionality you're looking for. getfenv() maaay be able to get you the rest of the way there.

That's what I've tried. It's setting the key for _G[…] = tAPI that I can't get.

Here's the (rather messy) code I have at the moment:

function include(_sPath)
-- the os.loadAPI slightly modified
local sName = fs.getName( _sPath )
 
local tEnv = {
  include = include
}
setmetatable( tEnv, { __index = _G } )
local fnAPI, err = loadfile( _sPath )
if fnAPI then
  setfenv( fnAPI, tEnv )
  includeStack[#includeStack + 1] = sName
  print(#includeStack)
  fnAPI()
else
  error("Failed to include '"..sName.."'. "..err)
  return false
end

local tAPI = {}
for k,v in pairs( tEnv ) do
  tAPI[k] =  v
end

--[[
--another failed attempt
local tTbl = _G
for _,v in ipairs( includeStack ) do
  if tTbl == nil then
   tTbl = {}
  end
  tTbl = tTbl[v]
end]]--

kStr = "_G"
for _,v in ipairs( includeStack ) do
  kStr = kStr.."."..v
  print(kStr)
end
tTbl = loadstring(kStr)
	    --this should just be replacing the load string, how do i set the key?
tTbl = tAPI
includeStack[#includeStack] = nil
return true
end
GopherAtl #4
Posted 15 March 2013 - 10:39 AM
some fiddling, using loadAPI as a base, came up with this, which seemed to work


local isIncluding = {}
local includeContext={_G}
function include(_sPath)
  local sName = fs.getName( _sPath )
  if isIncluding[sName] == true then
    printError( "circular inclusion detected!" )
    return false
  end
  isIncluding[sName] = true
  local tAPI = {}
   
  local myEnv=getfenv(1)
  local tEnv = {}
  setmetatable( tEnv, { __index = _G } )
  local fnAPI, err = loadfile( _sPath )
  if fnAPI then
    setfenv( fnAPI, tEnv )
    includeContext[#includeContext+1]=tAPI
    fnAPI()
    table.remove(includeContext)
  else
    printError( err )
    isIncluding[sName] = nil
    return false
  end
 
  for k,v in pairs( tEnv ) do
    tAPI[k] =  v
  end
 
  includeContext[#includeContext][sName] = tAPI 
  isIncluding[sName] = nil
  return true
end

The test code I used:
Spoilerfile "a"

include.include("b")

function foo()
  print("lib a")
end
file "b"

function foo()
  print("lib b")
end
file "test"

os.loadAPI("include")

include.include("a")

a.foo()
a.b.foo()
oeed #5
Posted 15 March 2013 - 11:03 AM
some fiddling, using loadAPI as a base, came up with this, which seemed to work


local isIncluding = {}
local includeContext={_G}
function include(_sPath)
  local sName = fs.getName( _sPath )
  if isIncluding[sName] == true then
	printError( "circular inclusion detected!" )
	return false
  end
  isIncluding[sName] = true
  local tAPI = {}
  
  local myEnv=getfenv(1)
  local tEnv = {}
  setmetatable( tEnv, { __index = _G } )
  local fnAPI, err = loadfile( _sPath )
  if fnAPI then
	setfenv( fnAPI, tEnv )
	includeContext[#includeContext+1]=tAPI
	fnAPI()
	table.remove(includeContext)
  else
	printError( err )
	isIncluding[sName] = nil
	return false
  end

  for k,v in pairs( tEnv ) do
	tAPI[k] =  v
  end

  includeContext[#includeContext][sName] = tAPI
  isIncluding[sName] = nil
  return true
end

The test code I used:
Spoilerfile "a"

include.include("b")

function foo()
  print("lib a")
end
file "b"

function foo()
  print("lib b")
end
file "test"

os.loadAPI("include")

include.include("a")

a.foo()
a.b.foo()

Cheers, this looks good. I'll try it out soon.
GopherAtl #6
Posted 15 March 2013 - 11:09 AM
just noticed I forgot to remove that "myEnv=getfenv(1)" line. It is meaningless and should be snipped.