Page 1 of 1

Require path

Posted: Sun Sep 24, 2017 1:55 pm
by Davïd
Hello,

I have the following folder structure :

/classes
classes.lua
--/data
--/data.lua
--/components
--/components.lua
----/movement
----/movement.lua

you get the idea. And I wonder if there is a way to require file like this

require('classes.components.movement')

instead of :

require('classes.components.movement.movement')

Thanks for enlightements

Re: Require path

Posted: Sun Sep 24, 2017 2:13 pm
by grump
Sure, by moving movement.lua one level up into the components folder.

Re: Require path

Posted: Sun Sep 24, 2017 4:27 pm
by davisdude
Without messing with the structure, as grum suggested, you have a couple of options available:
  • You can also put a file title "init.lua" inside of each directory, such as movement, which looks something like this:

    Code: Select all

    -- classes/components/movement/init.lua
    -- Match the parent directory
    local path = (...):match( '(.-)[^%./]+$' )
    return path .. 'movement.lua'
    
    Then you could require the directory itself, which would require the specific file:

    Code: Select all

    -- main.lua
    require 'classes.components.movement'
    
    Though this is a bit of a hassle, since you need to create a new file for each class that you make.
  • Alternatively, you could try messing with the package.path variable, though it could have some hard-to-find consequences later on if you're not careful with naming your files:

    Code: Select all

    -- main.lua
    package.path = './classes/components/?/?.lua;' .. package.path
    require 'movement' 
    
  • If you really wanted to achieve the exact structure you described without creating a custom file for each directory you could mokeypatch, or overwrite the require function, which I would strongly advise against and is typically not recommended (though still doable if you're desperate enough):

    Code: Select all

    -- Wrap everything in a do-block to reduce pollution to the local scope
    do
    	-- Store the old require to be used later
    	local _require = require
    	
    	-- Store the items in the directory, to check if one of the names matches
    	local directory = 'classes/components/'
    	local fileNames = love.filesystem.getDirectoryItems( directory )
    	
    	-- Overwrite require globally
    	function require( path )
    		-- Check to see if the last part of the path matches one of the fileNames
    		-- Get the last part of the path
    		local fileName = path:match( '^.-([^%./]+)$' )
    		for _, name in ipairs( fileNames ) do
    			-- File matches; use special format
    			if fileName == name then
    				return _require( directory .. fileName .. '.' .. fileName )
    			end
    		end
    		
    		-- File does not match; use regular require
    		return _require( pathname )
    	end
    end
    
    require 'classes.components.movement'
    

Re: Require path

Posted: Mon Sep 25, 2017 6:12 pm
by Davïd
Thanks for answers. I changed structure like Grump suggested.

And I didn't know about init files. Thank you for such quality answer Davis.