25. Modules and require
Every script you have written so far has lived in one file. Real programs grow past that. Lua splits programs across files using modules: a module is a Lua file that exposes a few related functions for other files to use.
A module is just a file that returns a table
The convention is short:
-- file: greet.lua
local M = {}
function M.hello(name)
print("Hello, " .. name .. "!")
end
function M.bye(name)
print("Goodbye, " .. name .. ".")
end
return MThree things to notice:
local M = {}creates an empty table calledM(any name works, butMis the convention).function M.hello(name) ... endadds a function under the keyhello— the dictionary syntax from chapter 23 in another shape.return Mat the end is how the module exposes its table to whoever loads it.
The file does no other work when loaded. Nothing prints, nothing runs. It just defines functions and hands a table back to the caller.
Using a module with
require
Another file loads it with require:
-- file: main.lua
local greet = require("greet")
greet.hello("Keiko")
greet.bye("Keiko")require("greet") does three things:
- Finds a file called
greet.luaon the Lua search path. - Runs it (only the first time — see the box below).
- Returns whatever the file returned.
So local greet = require("greet") gives you the module's
table. From it you call greet.hello,
greet.bye, etc.
require caches its result. If two files
both require("greet"), Lua loads greet.lua
once and hands both the same table. Calling
require("greet") ten times still loads it once. This is
good — it means modules are cheap to require from anywhere.
Where Lua looks
Out of the box, Lua looks in the current working directory and a few
system paths. The simplest layout — and the only one you need right now
— is to put main.lua and greet.lua in the
same folder, then cd into it before
running main.lua:
cd exercises/25/examples
lua main.lua
If you stay at the repo root and try
lua exercises/25/examples/main.lua,
require("greet") may fail to find greet.lua,
because the current directory is the repo root, not the example
folder.
In Roblox, require works differently — it loads a
ModuleScript from the game's data tree instead of a file on
disk. The shape of the module
(local M = {} ... return M) is identical.
Local vs global inside a module
Variables and functions declared with local inside a
module file are private to that file — handy for helper
functions the module does not want to expose:
-- file: math_helpers.lua
local M = {}
local function clamp(x, lo, hi)
if x < lo then return lo end
if x > hi then return hi end
return x
end
function M.double(x)
return clamp(x * 2, -100, 100)
end
return Mclamp is local and not on M,
so other files cannot call math_helpers.clamp — only the
module's own functions can. That is how you build a clean, small public
surface.
Homework
The Part 5 homework uses two files per problem: a
module file and a main.lua that uses it. Each problem lives
in its own sub-folder so the two files sit together. Open a terminal,
cd into that folder, then run
lua main.lua.
Problem 1 — Greet module
Folder: exercises/25/homework/01-greet-module/.
Finish greet.lua so it exposes
M.hello(name) and M.bye(name). The
main.lua file is provided and already calls both
functions.
Problem 2 — Math helpers
Folder: exercises/25/homework/02-math-helpers/.
Build a math_helpers.lua module with at least two
functions:
M.double(x)returnsx * 2.M.triple(x)returnsx * 3.
main.lua calls both and prints the results.
Problem 3 — Counter
Folder: exercises/25/homework/03-counter/.
Build a counter.lua module that exposes three
functions:
M.increment()— increases the counter by 1.M.get()— returns the current value.M.reset()— sets the counter back to 0.
The counter itself is a local variable inside the
module. It must persist across calls (think back to the scope discussion
at the end of chapter 21).
Challenge — String utilities
Folder: exercises/25/homework/04-string-utils/.
Build a string_utils.lua module with at least three
functions of your own. Suggestions:
M.shout(s)returnssin upper case with!appended.M.echo(s, n)returnssrepeatedntimes with spaces between.M.reverse_words(s)returns the words ofsin reverse order.
The last one is a stretch — you will need to walk the string and collect words. If that is too much, swap it for anything else of your own.
Stuck or finished? Open the homework solutions page.