You could customize the way Lua searches for modules using a custom searcher function, using the mechanisms outlined in the documentation of require
and package.loaders
.
The trick is to detect that the module can be found in a directory with the .myplugins
suffix and to keep track of the path of the bundles. Consider the following scripts.
-- <appdata>/plugins/foo.myplugin/foo.lua
local auxlib = require 'foo.auxlib'
local M = {}
function M.Foobnicator()
print "Called: Foobnicator!!"
auxlib.AuxFunction()
end
return M
-- <appdata>/plugins/foo.myplugin/auxlib.lua
local M = {}
function M.AuxFunction()
print "Called: AuxFunction!!"
end
return M
-- main.lua
package.path = package.path .. ";"
.. [[<appdata>/plugins/?.myplugin/?.lua]]
local bundles = {} -- holds bundle names and pathnames
local function custom_searcher( module_name )
if string.match( module_name, '%.' ) then
-- module name has a dot in it - it is a submodule,
-- let's check if it is inside a bundle
local main_module_name, subname =
string.match( module_name, '^([^.]-)%.(.+)' )
local main_path = bundles[ main_module_name ]
if main_path then -- OK, it's a submodule of a known bundle
local sub_fname = string.gsub( subname, '%.', '/' )
-- replace main module filename with that of submodule
local path = string.match( main_path, '^.*[/\\]' )
.. sub_fname .. '.lua'
return loadfile( path )
else -- not a bundle - give up the search
return
end
end
-- search for the module scanning package.path
for template in string.gmatch( package.path, '[^;]+' ) do
if string.match( template, '%.myplugin' ) then -- bundle?
local module_path =
string.gsub( template, '%?', module_name )
local fh = io.open( module_path ) -- file exists?
if fh then -- module found
fh:close()
bundles[ module_name ] = module_path
return loadfile( module_path )
end
end
end
end
-- sets the custom searcher as the first one so to take
-- precedence over default ones
table.insert( package.loaders, 1, custom_searcher )
local foo = require 'foo'
foo.Foobnicator()
Running main.lua
will produce the following output:
Called: Foobnicator!! Called: AuxFunction!!
I hope this will put you on the right track. Probably it doesn't cover every possibility and the error handling is not at all complete, but it should give you a good base to work on.