25. Modul dan require

Semua script yang sudah kamu tulis sejauh ini berada dalam satu file. Program sungguhan akan berkembang melampaui itu. Lua membagi program ke beberapa file menggunakan modul: sebuah modul adalah file Lua yang mengekspos beberapa fungsi terkait untuk digunakan oleh file lain.

Modul hanyalah file yang mengembalikan tabel

Konvensinya sederhana:

-- file: greet.lua
local M = {}

function M.hello(name)
    print("Hello, " .. name .. "!")
end

function M.bye(name)
    print("Goodbye, " .. name .. ".")
end

return M

Tiga hal yang perlu diperhatikan:

  • local M = {} membuat tabel kosong bernama M (nama apa pun bisa dipakai, tapi M adalah konvensinya).
  • function M.hello(name) ... end menambahkan sebuah fungsi di bawah kunci hello — sintaks dictionary dari bab 23 dalam bentuk lain.
  • return M di bagian akhir adalah cara modul mengekspos tabelnya kepada siapa pun yang memuatnya.

File ini tidak melakukan pekerjaan lain saat dimuat. Tidak ada yang dicetak, tidak ada yang dijalankan. File ini hanya mendefinisikan fungsi-fungsi dan mengembalikan sebuah tabel ke pemanggil.

Menggunakan modul dengan require

File lain memuatnya dengan require:

-- file: main.lua
local greet = require("greet")

greet.hello("Keiko")
greet.bye("Keiko")

require("greet") melakukan tiga hal:

  1. Mencari file bernama greet.lua di Lua search path.
  2. Menjalankannya (hanya pada pertama kali — lihat kotak di bawah).
  3. Mengembalikan apa pun yang dikembalikan oleh file tersebut.

Jadi local greet = require("greet") memberikan kamu tabel milik modul. Dari sana kamu bisa memanggil greet.hello, greet.bye, dan seterusnya.

require menyimpan cache hasilnya. Jika dua file sama-sama melakukan require("greet"), Lua memuat greet.lua sekali saja dan memberikan tabel yang sama ke keduanya. Memanggil require("greet") sepuluh kali pun tetap memuatnya sekali. Ini bagus — artinya modul murah untuk di-require dari mana saja.

Di mana Lua mencarinya

Secara bawaan, Lua mencari di direktori kerja saat ini dan beberapa path sistem. Layout paling sederhana — dan satu-satunya yang kamu butuhkan sekarang — adalah meletakkan main.lua dan greet.lua di folder yang sama, lalu cd ke folder itu sebelum menjalankan main.lua:

cd exercises/25/examples
lua main.lua

Jika kamu tetap di root repo dan mencoba lua exercises/25/examples/main.lua, require("greet") mungkin gagal menemukan greet.lua, karena direktori saat ini adalah root repo, bukan folder contoh.

Di Roblox, require bekerja berbeda — ia memuat ModuleScript dari data tree game, bukan file di disk. Bentuk modul (local M = {} ... return M) tetap identik.

Lokal vs global di dalam modul

Variabel dan fungsi yang dideklarasikan dengan local di dalam file modul bersifat privat untuk file itu — berguna untuk fungsi-fungsi pembantu yang tidak ingin diekspos oleh modul:

-- 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 M

clamp bersifat local dan tidak ada di M, sehingga file lain tidak bisa memanggil math_helpers.clamp — hanya fungsi-fungsi milik modul sendiri yang bisa. Itulah cara membangun permukaan publik yang bersih dan kecil.

PR

PR Bagian 5 menggunakan dua file per soal: sebuah file modul dan main.lua yang menggunakannya. Setiap soal berada di sub-foldernya sendiri agar kedua file berada bersama. Buka terminal, cd ke folder itu, lalu jalankan lua main.lua.

Soal 1 — Modul greet

Folder: exercises/25/homework/01-greet-module/.

Lengkapi greet.lua agar mengekspos M.hello(name) dan M.bye(name). File main.lua sudah disediakan dan sudah memanggil kedua fungsi tersebut.

Soal 2 — Math helpers

Folder: exercises/25/homework/02-math-helpers/.

Buat modul math_helpers.lua dengan setidaknya dua fungsi:

  • M.double(x) mengembalikan x * 2.
  • M.triple(x) mengembalikan x * 3.

main.lua memanggil keduanya dan mencetak hasilnya.

Soal 3 — Counter

Folder: exercises/25/homework/03-counter/.

Buat modul counter.lua yang mengekspos tiga fungsi:

  • M.increment() — menambah counter sebesar 1.
  • M.get() — mengembalikan nilai saat ini.
  • M.reset() — mengatur counter kembali ke 0.

Counter itu sendiri adalah variabel local di dalam modul. Nilainya harus bertahan antar pemanggilan (ingat kembali diskusi scope di akhir bab 21).

Tantangan — String utilities

Folder: exercises/25/homework/04-string-utils/.

Buat modul string_utils.lua dengan setidaknya tiga fungsi buatanmu sendiri. Saran:

  • M.shout(s) mengembalikan s dalam huruf kapital semua dengan ! di akhir.
  • M.echo(s, n) mengembalikan s yang diulang n kali dengan spasi di antara.
  • M.reverse_words(s) mengembalikan kata-kata dalam s dalam urutan terbalik.

Yang terakhir cukup menantang — kamu perlu menelusuri string dan mengumpulkan kata-kata. Jika itu terlalu sulit, ganti dengan fungsi lain apa pun buatanmu.

Mentok atau sudah selesai? Buka halaman solusi PR.