cajwine
cajwine

Reputation: 3160

Lua emulating the require function

In the embeded lua environment (World of Warcraft - WoW) is missing the require function.

I want port one existing lua source code (an great OO-library) for the use it in the WoW. The library itself is relatively small (approx 8 small files) but of course it heavily uses the require.

World of Warcraft loads files and libraries by defining it in an XML file, like:

<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
    <Script file="LibOne.lua"/>
    <Script file="LibTwo.lua"/>
</Ui>

but i don't know how the low level library manipulation is done in the WoW.

AFAIK in the WoW is missing even the package. table too. :(

So the question(s): For me, the streamlined way would be write an function which will emulate the require function using the interface available in WoW. The question is how. Could someone give me some directions?

Or as alternative, for the porting the mentioned existing source to WoW, I need replace the require Some.Other.Module lines in the lua sources to something what WoW will understand. What is the equivalent/replacement for such require Some.Module in the WoW?

How the WoW handles modules/libraries at low-level?

Upvotes: 6

Views: 4180

Answers (2)

siffiejoe
siffiejoe

Reputation: 4271

You could merge all files into one using one of the various amalgamation scripts, e.g. amalg. Then you can load this file and a stub that implements the require function using the usual WoW way:

<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
    <Script file="RequireStub.lua"/>
    <Script file="AllModules.lua"/><!-- amalgamated Lua modules -->
    <Script file="YourCode.lua"/>
</Ui>

The file RequireStub.lua could look like:

package = {}
local preload, loaded = {}, {
  string = string,
  debug = debug,
  package = package,
  _G = _G,
  io = io,
  os = os,
  table = table,
  math = math,
  coroutine = coroutine,
}
package.preload, package.loaded = preload, loaded


function require( mod )
  if not loaded[ mod ] then
    local f = preload[ mod ]
    if f == nil then
      error( "module '"..mod..[[' not found:
       no field package.preload[']]..mod.."']", 1 )
    end
    local v = f( mod )
    if v ~= nil then
      loaded[ mod ] = v
    elseif loaded[ mod ] == nil then
      loaded[ mod ] = true
    end
  end
  return loaded[ mod ]
end

This should emulate enough of the package library to get you a working require that loads modules in the amalgamated file. Different amalgamation scripts might need different bits from package, though, so you probably will have to take a look at the generated Lua source code.

And in the specific case of Coat you might need to implement stubs for other Lua functions as well. E.g. I've seen that Coat uses the debug library ...

Upvotes: 6

Oleg V. Volkov
Oleg V. Volkov

Reputation: 22431

WoW environment doesn't have dofile or any other means to read external files at all. You need to explicitly mention all files that must be loaded in .toc file or .xml referenced from .toc.

You can then write your own implementation of require to maintain compatibility with your library, which would be quite trivial as it would only need to parse module name and retrieve it's content from modules.loaded table, but you'd still need to alter original source to make files register in that table and you'll need to manually arrange all files into correct order of loading.

Alternatively you can rearrange files into separate WoW-addons and use its own built-in Dependencies/OptionalDeps facilities or popular LibStub framework to handle loading order automatically.

Upvotes: 3

Related Questions