Lua emulating the require function - lua

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?

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 ...

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.

Related

Migrate Vim/Vimscript for asynchronously running external editors to Lua/Neovim

In my Vim's configuration file init.vim I am using code, that sets a default viewer for practically any kind of file suffix. Here I will demonstrate only an example for .md files:
let g:netrw_browsex_viewer="-"
function! NFH_md(f)
call asyncrun#run("", "cwd", "typora " . a:f)
endfunction
First paragraph makes sure to choose the function based on suffix of the file ("URI under cursor"). Second paragraph shows a function whose name i.e. NFH_md implies that this is the function opened when .md file is in the "URI under the cursor". Inside this function there is an call that opens an external program typora asynchronously so that I am still able to continue using Vim.
If you want to know more use :help netrw_browsex_viewer.
I tried porting the mentioned Vim script to Neovim & Lua but I only managed to port first line:
vim.g.netrw_browsex_viewer="-"
For I don't know, how to properly port the second paragraph. This is why for now I just use Vimscript source code like this:
vim.api.nvim_exec(
[[
function! NFH_md(f)
call asyncrun#run("", "cwd", "marktext " . a:f)
endfunction
]],
false
)
But I would love to translate all the code to Lua - Could anyone help a bit to translate this remaining Vimscript code to Lua?

Reading text file in Lua using Luacom and ADODB: error

I am constructing a general purpose function to read a text file, which may be Ascii, UTF-8 or UTF-16. (The encoding is known when the function is invoked). The file name may contain UTF8 characters, so the standard lua io functions are not a solution. I have no control over the Lua implementation (5.3) or the binary modules available in the environment.
My current code is:
require "luacom"
local function readTextFile(sPath, bUnicode, iBits)
local fso = luacom.CreateObject("Scripting.FileSystemObject")
if not fso:FileExists(sPath) then return false, "" end --check the file exists
local so = luacom.CreateObject("ADODB.Stream")
--so.CharSet defaults to Unicode aka utf-16
--so.Type defaults to text
so.Mode = 1 --adModeRead
if not bUnicode then
so.CharSet = "ascii"
elseif iBits == 8 then
so.CharSet = "utf-8"
end
so:Open()
so:LoadFromFile(sPath)
local contents = so:ReadText()
so:Close()
return true, contents
end
--test Unicode(utf-16) files
local file = "D:\\OneDrive\\Desktop\\utf16.txt" --this exists
local booOK, factsetcontents = readTextFile(file, true, 16)
When executed I get the error: COM exception:(d:\my\lua\luacom-master\src\library\tluacom.cpp,382):Operation is not allowed in this context on line 19 [local stream = so:LoadFromFile(sPath)]
I've pored over the ADO documentation and am obviously missing something that is staring me in the face! Is what I'm trying to do impossible?
ETA: If I comment out the line so.Mode = 1, this works. Which is great, but I don't understand why, which meaans I may end up making the same mistake unwittingly, whatever that mistake is!
I don't know about AdoDB Stream.Mode and why the function failed. But I think it's rather tricky to use a ADODB COM object on Windows to read ASCII/UTF8/UNICODE encoded files.
You can instead :
use standard Lua io.open function in binary mode and use manual decoding of the bytes content
use a binary module to do all the work
use a specific Lua implementation for Windows that can read/write those kind of encoded files natively, like LuaRT

Lua Nested Require Path

I'm writing a tool to parse lua plugins created by other users. The only guarentee about the plugin is that it has a data.lua file in a known directory. Inside there users are free to do anything they wish. This particular plugin using require to load a file and that file loads another file. Both are relative paths but the second is relative to the location of the first file.
data.lua
foo/bar.lua
foo/baz.lua
data.lua:
require("foo.bar")
foo/bar.lua:
require("baz")
When I try to execute data.lua I get an error when foo/bar.lua tries to require "baz". None of the paths it tries are ./foo/.
Any idea how I can fix this? I could find any documentation specifically about this case, it seemed like I need to hard code /foo/ into the path but I don't know it ahead of time. This seems like something that should be automatic is there a setting I'm missing or am I running the wrong version of lua? I'm using NLua 4.0
Thanks
I tested this script using node-lua and it fixes the issue for me!
https://gist.github.com/hoelzro/1299679
Relavent code:
local oldrequire = require
function require(modname)
local regular_loader = package.loaders[2]
local loader = function(inner)
if string.match(modname, '(.*)%.') then
return regular_loader(string.match(modname, '(.*)%.') .. '.' .. inner)
end
end
table.insert(package.loaders, 1, loader)
local retval = oldrequire(modname)
table.remove(package.loaders, 1)
return retval
end
To get this to work with Lua 5.2 change all uses of package.loaders to package.searchers.
Also if you want to override the global require function you need this snippet as well:
_G.require = require
You can alter the search behavior of require by changing the package.path variable.
Resources on package.path:
https://www.lua.org/manual/5.3/manual.html#pdf-package.path
http://lua-users.org/wiki/PackagePath
Example adding foo folder to search locations:
package.path = package.path .. ';./foo/?.lua'
the ? character will be where the string passed to require is placed.
Alternatively you can add a default file to load, to the package.path:
package.path = package.path .. ';./nested_require.lua'
Then define the behavior you would like within this file. You can use the global variable _REQUIREDNAME to reference the value passed to the require function.
The documentation for this method can be found here at the bottom of the page: https://www.lua.org/pil/8.1.html

Minifying import paths for modules in webpack

I've got a TypeScript project that uses Webpack successfully to yield ES6, which is run through babel-minify to tree-shake it and produce a significantly smaller bundle output file.
This file appears to contain all the logic from my own program as well as the logic for each of the pieces of the imported libraries I'm using (e.g. rxjs, lodash, etc.)
However, I'm looking through the generated file and it appears that at the top we've got some webpack logic, then a map of the path of the original import to a function that implements it, and well, really a lot of that all the way down, with various portions pointing to dependencies and their path strings.
Now, given that everything is self-contained within this webpack bundle (no other chunks), the inclusion of all the source file names seems to take up a lot of space needlessly.
For example, I'm looking at one section in here for lodash's isBoolean script:
"./node_modules/lodash/isBoolean.js": function(e, t, o) {
var r = o("./node_modules/lodash/_baseGetTag.js"),
s = o("./node_modules/lodash/isObjectLike.js");
e.exports = function(e) {
return !0 === e || !1 === e || s(e) && "[object Boolean]" == r(e)
}
},
Now, it seems like there are a lot of characters being taken up to describe the source file. Since there's no actual dependency at this time on the source file, why can't each key just be replaced with a shorter string identifier throughout, as in the following example:
"a": function(e, t, o) {
var r = o("b"),
s = o("c");
e.exports = function(e) {
return !0 === e || !1 === e || s(e) && "[object Boolean]" == r(e)
}
},
where "a", "b", and "c" are all representative of each place where the original string values occur throughout the entire bundle. This shouldn't impact all strings, but rather just the import file path strings.
There appears to be someone asking a similar question at Webpack compress path names who didn't really get a satisfactory answer, in my opinion.
Is there some option or plugin I can use that could mangle the module path names?
Figured it out after reading through Webpack's source code and figuring out how it actually assembles the whole thing.
I had the NamedModulesPlugin in my config (likely an artifact from one of the various quickstarts out there) and this plugin inserts all the module paths into the output.
Commenting that out (or just removing it) from the config removes it entirely from the output (no mangling necessary).

Require LUA files using a standard relative path approach - problems with: attempt to call global 'myfunc' (a nil value)

I need to call a LUA function, defined in another my .lua file; from another. So, what I want is the classic C/C++ include approach.
I tried with the following:
(file funcs.lua)
function myfunc(arg1, arg2)
..dosomething
end
and
(file main.lua)
package.path = package.path .. ";/path/to/libs/?.lua"
require "funcs"
myfunc(1, 2)
The require works good, but at execution I get this error:
attempt to call global 'myfunc' (a nil value)
How come?
Thanks in advance,
Thank you all for the comments; I'm running LUA under OpenResty/Nginx.
I solved by exporting directly the function(s), I don't know if this is the preferred method, but I noticed that is used by lots of newer LUA modules.
For example, I changed the code as follows:
file (funcs.lua)
local A = {}
function A.myfunc(arg1, arg2)
..dosomething
end
return A
(file main.lua)
package.path = package.path .. ";/path/to/libs/?.lua"
funcs = require "funcs"
funcs.myfunc(1, 2)
This works good and it's nice to have every function to be manually exported, in a sort of OOP-style.

Resources