lua - 如何设置搜索路径允许lua插件作为包

标签 lua luabind module-search-path

tl;dr: 我想使用自定义目录名称模式创建 lua 包,但搜索路径有问题。

问题

我有一个应用程序,我希望允许用户为其编写插件,遵循与 Lightroom 类似的模型:

  • 一组默认插件存储在 <app data>/plugins/<name>.myplugin
  • <name>.myplugin是一个目录包,可能包含一组脚本、二进制文件或其他资源
  • 插件可以通过不同的脚本将许多不同的功能导出到应用
  • 导出函数的名称列于 info.lua 中。应用程序读取的文件

我正在解决的问题是如何最好地将插件包装为包(模块+子模块)或常规脚本。我设想插件可能包含第三方模块:

Foo.myplugin/
    info.lua - returns a table with plugin name, version info, list of exported functions, etc
    Foo.lua - defines the main functions exported by this plugin, which calls other scripts:
    UsefulFunctions.lua - used by Foo.lua
    3rdparty/3rdparty.lua - 3rd party module

如果我设置包搜索路径,package.path包括

<appdata>/?.myplugin/?.lua

然后我可以使用 Foo=require 'Foo' 加载包。但是,我无法弄清楚如何加载子模块。如果Foo.lua来电 UsefulFunctions=require 'UsefulFunctions'那么这个加载失败,因为 lua 的搜索路径试图寻找 UsefulFunctions.myplugin/UsefulFunctions.lua 。我无法使用 require 'Foo.UsefulFunctions' 加载它出于类似的原因,要么。

一些选项:

  • 一种解决方法是将每个插件的路径显式添加到包路径中,但如果两个插件各自包含同名的子模块,这会导致问题。
  • 另一种选择是编写插件以使用常规 lua 脚本而不是提供模块,但这仍然意味着必须在每个插件内设置搜索路径。
  • 后备选项可能是丢失 .myplugin后缀可以简化包搜索路径。
  • 修补 Lua 以明确支持此类搜索路径

有什么方法可以提供我需要的功能吗?

我目前使用的是 Lua 5.1。我知道 5.2 对包搜索路径有更多控制,但我认为目前无法选择更新它。我也在使用 luabind,尽管我认为它与此无关。

最佳答案

您可以使用自定义搜索器功能自定义 Lua 搜索模块的方式,使用 documentation of require 中概述的机制。和 package.loaders .

诀窍是检测是否可以在带有 .myplugins 后缀的目录中找到该模块,并跟踪 bundle 的路径。考虑以下脚本。

-- <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()

运行main.lua将产生以下输出:

Called: Foobnicator!!
Called: AuxFunction!!

我希望这能让您走上正轨。也许它并没有涵盖所有可能性,并且错误处理根本不完整,但它应该为您提供良好的工作基础。

关于lua - 如何设置搜索路径允许lua插件作为包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19664730/

相关文章:

list - 在 Lua 列表中搜索项目

c# - Redis Lua 脚本返回表并解析对象

redis - 如何使用纯Redis以原子方式删除与模式匹配的数百万个键?

c++ - 使用 luabind 将类指针返回到 lua

pointers - Lua 如何在 C++ 中将 void* 指针传递给 lua && 将其传递回 C++

python - 为什么有模块搜索路径而不是输入目录名+输入文件名?

metadata - -I 有什么区别。和 Perl6 中的 -Ilib?

c++ - Lua C API 不适用于指针

c++ - LuaBind:如何将类的特定实例绑定(bind)到 Lua?

python - 搜索路径是否比 sys.path 中的多?