25. Modul dan require — Solusi PR

Setiap soal punya folder tersendiri di bawah exercises/25/homework/solutions/. Untuk menjalankannya:

cd exercises/25/homework/solutions/01-greet-module
lua main.lua

Soal 1 — Modul greet

Soal. Lengkapi modul greet.lua yang mengekspos fungsi hello dan bye.

Cara memikirkannya. Pola standar: buat M, tambahkan fungsi-fungsinya, kembalikan M. Keduanya sederhana — masing-masing cukup satu print.

Solusi lengkap. greet.lua:

local M = {}

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

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

return M

main.lua:

local greet = require("greet")

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

Kesalahan umum.

  • Lupa menulis return M di akhir. require akan mengembalikan true, bukan tabelnya, dan greet.hello akan gagal dengan error attempt to index a boolean value.
  • Menjalankan dari direktori yang salah. Masuk dulu ke foldernya dengan cd.

Soal 2 — Pembantu matematika

Soal. Sebuah modul dengan fungsi double dan triple.

Cara memikirkannya. Bentuknya sama seperti soal 1, tapi menggunakan operasi matematika, bukan print. M.double menerima sebuah nilai dan mengembalikan nilai baru — yang mencetak hasilnya adalah si pemanggil.

Solusi lengkap. math_helpers.lua:

local M = {}

function M.double(x)
    return x * 2
end

function M.triple(x)
    return x * 3
end

return M

main.lua:

local mh = require("math_helpers")

print(mh.double(7))    -- 14
print(mh.triple(7))    -- 21
print(mh.double(mh.triple(5)))   -- 30

Kesalahan umum.

  • Meletakkan print di dalam modul. Dengan mengembalikan nilai, si pemanggil bebas memutuskan apa yang mau dilakukan dengan nilainya.

Soal 3 — Counter

Soal. Sebuah modul dengan fungsi increment, get, dan reset. Penghitung internal harus tetap tersimpan di antara pemanggilan.

Cara memikirkannya. Sebuah variabel local di bagian atas file (di luar fungsi mana pun) akan hidup selama modul itu ada — yang berkat cache require, berarti sepanjang program berjalan. Ketiga fungsi yang diekspos membaca dan mengubah variabel yang sama.

Solusi lengkap. counter.lua:

local M = {}

local count = 0

function M.increment()
    count = count + 1
end

function M.get()
    return count
end

function M.reset()
    count = 0
end

return M

main.lua:

local counter = require("counter")

counter.increment()
counter.increment()
counter.increment()
print(counter.get())     -- 3

counter.reset()
print(counter.get())     -- 0

Kesalahan umum.

  • Mendeklarasikan count di dalam M.increment. Setiap pemanggilan akan mereset nilainya ke 0, lalu menaikkannya ke 1. State yang persisten harus hidup di luar fungsi.
  • Meletakkan count pada M (yaitu M.count). Cara itu memang bisa bekerja, tapi membuat file mana pun bisa menimpa count secara langsung. Sebuah modul seharusnya hanya mengekspos bagian yang memang perlu diakses dari luar.

Tantangan — Utilitas string

Soal. Sebuah modul dengan tiga fungsi string buatanmu sendiri.

Cara memikirkannya. Pilih tiga fungsi. Contoh ini menunjukkan shout, echo, dan reverse_words. Fungsi ketiga memecah string berdasarkan spasi dengan menelusuri karakter per karakter; kalau terasa terlalu rumit, ganti dengan sesuatu yang lebih sederhana, seperti M.exclaim(s) -> s .. "!".

Solusi lengkap. string_utils.lua:

local M = {}

function M.shout(s)
    return string.upper(s) .. "!"
end

function M.echo(s, n)
    local parts = {}
    for i = 1, n do
        parts[i] = s
    end
    return table.concat(parts, " ")
end

function M.reverse_words(s)
    local words = {}
    for word in string.gmatch(s, "%S+") do
        table.insert(words, 1, word)
    end
    return table.concat(words, " ")
end

return M

main.lua:

local su = require("string_utils")

print(su.shout("hello"))             -- HELLO!
print(su.echo("hi", 4))              -- hi hi hi hi
print(su.reverse_words("one two three four"))  -- four three two one

string.gmatch adalah fungsi bawaan yang menelusuri setiap kecocokan sebuah pola dalam string. %S+ berarti satu atau lebih karakter yang bukan spasi — dengan kata lain, sebuah kata. table.insert(..., 1, word) meletakkan setiap kata baru di posisi 1, menggeser kata-kata sebelumnya, sehingga daftar akhirnya menjadi terbalik.

Kesalahan umum.

  • Ragu menggunakan string.gmatch karena belum punya bagiannya sendiri. Setiap fungsi bawaan sudah tersedia begitu Lua dijalankan.

Selesai?

Bagian 5 dinyatakan selesai setelah keempat program PR berhasil dijalankan. Mini-proyek Bagian 5 — sebuah Text Adventure — menggabungkan fungsi, tabel, dan modul menjadi sebuah dunia permainan kecil.