min
min

Reputation: 1098

lua - Using two same name function from different lua lib

I have two different lib written by lua, but with same function name.

How can I choose one of them without modify the lib source?

require ('A') --A lib
require ('B') --B lib
test() -- function from B

If I want test function from A, how can I do?

Here is some way I tried.

  1. LuaJ loading two functions with the same name from two different LuaScripts

    I found this, but I don't want modify the lib source code.

  2. Save the function as different name, like this:

    require ('A') --A lib
    _G.testA = test
    require ('B') --B lib
    _G.testB = test
    
    testA() -- function from A
    testB() -- function from B
    

    But if someday a new function name testA() or testB() it break again.

    And I still need to change all exist test() to testA() or testB().

    Is there any better way?

Upvotes: 1

Views: 1781

Answers (2)

iridian
iridian

Reputation: 709

The code you have described

require ('A') --A lib
_G.testA = test
require ('B') --B lib
_G.testB = test

testA() -- function from A
testB() -- function from B

Is definitely one way to resolve your issue.

To avoid future issues you could put new functions inside a map

-- Example library.lua

-- Old code not in map
function my_old_func(params)
    -- do some stuff
end

-- New code goes down here
local mylibrary = {}
function mylibrary:my_awesome_func(params)
    my_old_func(params)
end

Upvotes: 0

siffiejoe
siffiejoe

Reputation: 4271

This is exactly the reason why Lua modules shouldn't set global variables, but instead export all its functions/variables in a table that gets returned via require.

However, if your two modules are Lua modules, you can set a custom environment for each so that the global variables that the modules define end up in separate tables:

#!/usr/bin/lua

-- fallback implementation of package.searchpath for Lua 5.1
local searchpath = package.searchpath
-- not necessary if you have Lua 5.2+:
if not searchpath then
  local delim = package.config:match( "^(.-)\n" ):gsub( "%%", "%%%%" )

  function searchpath( name, path )
    local pname = name:gsub( "%.", delim ):gsub( "%%", "%%%%" )
    local msg = {}
    for subpath in path:gmatch( "[^;]+" ) do
      local fpath = subpath:gsub( "%?", pname )
      local f = io.open( fpath, "r" )
      if f then
        f:close()
        return fpath
      end
      msg[ #msg+1 ] = "\n\tnofile '"..fpath.."'"
    end
    return nil, table.concat( msg )
  end
end


-- table for storing the environments for each module
local environments = {}


-- clone of the standard Lua searcher which sets a custom environment
-- for the loaded chunk and stores it in the environments table.
local function my_lua_searcher( modname )
  local fpath, msg = searchpath( modname, package.path )
  if not fpath then
    return msg
  end
  local env = setmetatable( {}, { __index = _G } )
  env._G = env
  environments[ modname ] = env
  local f = assert( loadfile( fpath, nil, env ) )
  if setfenv then -- for Lua 5.1
    setfenv( f, env )
  end
  return f, fpath
end


-- replace the Lua searcher (at index 2)
local searchers = package.searchers or package.loaders
-- if someone added to package.searchers, we have no way of knowing
-- which function is the Lua searcher we want to replace:
assert( #searchers == 4, "package.searchers has been modified" )
searchers[ 2 ] = my_lua_searcher


-- test it:
require( "A" )
require( "B" )
environments[ "A" ].test()
environments[ "B" ].test()

Upvotes: 3

Related Questions