Lua - Custom Module Loader



Lua custom module loading mechanism provides a greater control over how Lua finds and loads a module. require function is flexible and allows us to extend its behavior by using custom module loader.

By default, a module is loaded from a predefined set of path/pattern or from current directory. Using custom loader we can insert our own custom logic in between this process, to load a module from a custom location, handle different file type or even use network based module files.

package.loaders table

Lua maintains a global table package.loaders. This table maintains the entries of functions which Lua calls in order when a module is loaded using require import. Each function is a loader which takes module name, searches and loads the module.

Default Loader Functions

Following are the default loader functions used by Lua package.loaders table.

  • A loader function to search preloaded modules in path defined by package.preload

  • A loader function to search lua files in path defined by package.path

  • A loader function to search C libraries in path defined by package.cpath

  • A loader function to act as a fallback loader to return an error message as no relevant module found.

Creating a Custom Loader

In order to implement a custom loader, we can define a function which follows input and output format of package.loaders table.

Example - Loading a Module from Custom Directory

In this example, we'll be loading a module from custom_modules folder present in current directory.

Let's define a module file stringutils.lua in custom_modules directory in current folder as described below −

./custom_modules/stringutils.lua

local utils = {}

-- function to reverse a string
function utils.reverse(s)
   return s:reverse()
end

-- function to get string in uppercase
function utils.uppercase(s)
   return s:upper()
end

-- function to get string in lowercase
function utils.lowercase(s)
   return s:lower()
end

-- function to check a substring
function utils.contains(s, sub)
   return s:find(sub, 1, true) ~= nil
end

return utils

Now, in order to access module from custom_module directory, say, moduletutorial.lua, you need to use the following code segment.

moduletutorial.lua

-- we're adding custom loader in the beginning of package.loaders table.
table.insert(package.loaders, 2, function(module_name) 
   local filename = "./custom_modules/" .. module_name .. ".lua"
   local f, err = loadfile(filename) -- load the module
   if f then
      -- Execute the loaded module
      return f
   else
      -- return nil with error message
      return nil, "Couldn't load module '" .. module_name .. "' from '" .. filename .. "': " .. err
   end
end)
-- using require on 'custom_modules' directory
local custom_module = require("stringutils") 
print(custom_module.uppercase("tutorialspoint"))

Output

IWhen we run the above program, we will get the following output−

TUTORIALSPOINT

Explanation

stringutils.lua

  • We've created an empty table utils as a module defined few functions on strings and returned the table as a module.

  • This file is created in custom_modules directory under current directory.

moduletutorial.lua

  • table.insert(package.loaders, 2, function(module_name) − adds a custom loader function in the beginning of package.loader table.

  • local filename = "./custom_modules/" .. module_name .. ".lua" − is used to get the Lua file name using the module name.

  • local f, err = loadfile(filename) − load the module.

  • If module is found, it is returned otherwise nil is returned with an error message.

  • local custom_module = require("stringutils") loads the module from custom_modules directory and then a function is called to print a result.

Advertisements