Help with a recursive function, like the windows path system

I am currently trying to make my own version of roblox’s require. However i cannot figure out how to make a recursive function that is efficient.

I am trying to get to a specific path via a recursive function. An example of this function would be: get(“folder1/folder2/module”). All of these folders are located inside of the main ‘get’ module and i would like some help. Here is my code so far and a picture of the structure:

image

local function FindPath(path, curDir)
	curDir = curDir or script
	local finalDir = nil
	
	for _, v in pairs(curDir:GetChildren()) do
		if v.Name == path[#path] and v:IsA("ModuleScript") then
			return require(v)
		end
		finalDir = v
	end
	return FindPath(path, finalDir)
end

return function(path: string)
	if path == "all" then
		local modules = {}
		for i, module in pairs(script:GetDescendants()) do
			if module:IsA("ModuleScript") then
				modules[i] = require(module)
			end
		end
		return modules
	else
		path = string.split(path, "/")
		return FindPath(path)
	end
end

Here is an example of how i intend to use it:

local util = get("sys/interact/interactUtils")
local mouseUtil = get("util/mouse")

You probably shouldn’t use a recursive function here. A loop will work just fine. Try this:

-- Requires the module from the given path
function Require(path, dir) -- dir is optional, defaults to script
   local hierarchy = string.split(path, "/")
   dir = dir or script

   for _, v in ipairs(hierarchy) do
      if dir:FindFirstChild(v) then
         dir = dir[v]
      else
         error("Could not find "..path)
      end
   end

   return require(dir)
end

If you want to require a set of modules you can try this:

-- Requires the module(s) from the given path
function Require(path, dir) -- dir is optional, defaults to script
   local hierarchy = string.split(path, "/")
   dir = dir or script

   for _, v in ipairs(hierarchy) do
      if dir:FindFirstChild(v) then
         dir = dir[v]
      elseif v == "*" then
         local modules = {}
         for _, descendant in ipairs(dir:GetDescendants()) do
            if descendant:IsA("ModuleScript") then
               modules[descendant.Name] = require(descendant)
            end
         end
         return modules
      else
         error("Could not find "..path)
      end
   end

   return require(dir)
end

-- Use example
local util = Require("sys/interact/interactUtils")
local otherUtils = Require("util/*") -- Requires and returns all module descendants of 'util'

local mouseUtil = otherUtils.mouse

Using ‘path/subpath/ModuleName’ would return a single required module, or you could use ‘path/subpath/etc/*’ to get a set of module scripts within a directory including its subdirectory chain. Or you could just use “*” to get all modules in the input directory and the table returned stores each required module by its name.

4 Likes

Can you not find nested ModuleScripts using :GetDescendants()?

local function get(foo)
    for k, v in pairs(path:GetDescendants()) do
        if v:IsA(class) and v.Name == "name" then
            return v
        end
    end
end

this is exactly what i was looking for, thankyou

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.