Lua on Ubuntu18.04

最近工作上需要在 Redis 上面寫 Script,Redis 從 2.6.0 版之後包了 Lua interpreter 進去開始支援用 Lua 語言寫 Script,
所以花一些時間去熟悉久仰的 Lua 語言

筆記一下在 Ubuntu 18.04 上手 Lua 的過程。

Install

apt

Ubuntu 18.04 可以安裝到最新的 Lua 版本是 Lua 5.3

1
2
3
4
~$ sudo apt install lua5.3
~$ lua5.3
Lua 5.3.3 Copyright (C) 1994-2016 Lua.org, PUC-Rio
>

不過要注意的是 Redis 中的 EVAL 版本是 5.1[1]

Building from source

1
2
3
4
5
6
7
8
~$ sudo apt install libreadline-dev
~$ git clone https://github.com/lua/lua
~$ cd ./lua
~$ make all
~$ mv ./lua ./lua /usr/local/bin
~$ lua
Lua 5.4.0 Copyright (C) 1994-2019 Lua.org, PUC-Rio
>

Example: Hello, world!

Interactive Mode

1
2
3
4
5
6
~$ lua
lua
Lua 5.4.0 Copyright (C) 1994-2019 Lua.org, PUC-Rio
> print("Hello, world!")
Hello, world!
>

helloworld.lua

1
~$ vim helloworld.lua
1
2
3
4
5
6
function helloWorld(name)
assert(type(name) == "string", "name expects a string")
return string.format("Hello, %s!", name)
end

print(helloWorld("world"))
1
2
~$ lua helloworld.lua
Hello, world!

Unit Test

要在 Lua 寫 Unit Test 的話,根據 Unit Testing - lua-users wiki 的範例是使用 bluebird75/luaunit

安裝 luaunit module 以 Lua 5.4 為例

1
2
3
4
~$ lua -v | awk '{print $2}'
5.4.0
~$ sudo mkdir -p /usr/local/share/lua/5.4/luaunit/
~$ sudo curl -o /usr/local/share/lua/5.4/luaunit/init.lua https://raw.githubusercontent.com/bluebird75/luaunit/master/luaunit.lua

安裝 luaunit module 以 5.3 為例

1
2
3
4
lua5.3 -v | awk '{print $2}'
5.3.3
~$ sudo mkdir -p /usr/share/lua/5.3
~$ sudo curl -o /usr/share/lua/5.3/luaunit.lua https://raw.githubusercontent.com/bluebird75/luaunit/master/luaunit.lua

Example: helloWorld module

helloworld.lua

1
2
3
4
5
6
7
8
module = {}

function module.helloWorld(name)
assert(type(name) == "string", "name expects a string")
return string.format("Hello, %s!", name)
end

return module

test_helloworld.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
luaUnit = require("luaunit")
testModule = require("helloworld")

function testHelloWorld()
local ret = testModule.helloWorld("world")
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, world!")

ret = testModule.helloWorld("ming")
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, ming!")

ret = testModule.helloWorld(integer)
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, ming!")
end

os.exit(luaUnit.LuaUnit.run())

Run LuaUnit

1
2
3
4
5
6
~$ lua test_helloworld.lua -v
Started on Mon Jul 8 15:06:09 2019
testHelloWorld ... Ok
=========================================================
Ran 1 tests in 0.000 seconds, 1 success, 0 failures
OK

Error Handling

helloworld.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module = {}

local function helloWorld(name)
-- assert(type(name) == "string", {message="name expects a string"})
if type(name) ~= "string" then
error({message="name expects a string"})
end

return string.format("Hello, %s!", name)
end

function module.HelloWorld(name)
-- Error Handling
-- Reference: https://blog.golang.org/error-handling-and-go
local success, result = pcall(helloWorld, name)
if not success then
return "", result.message
end

return result, nil
end

return module

test_helloworld.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
luaUnit = require("luaunit")
testModule = require("helloworld")

function testHelloWorld()
local ret, err = testModule.HelloWorld("world")
luaUnit.assertNil(err)
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, world!")

ret, err = testModule.HelloWorld("ming")
luaUnit.assertNil(err)
luaUnit.assertEquals(type(ret), "string")
luaUnit.assertEquals(ret, "Hello, ming!")
end

function testHelloWorldWrongCase()
local ret, err = testModule.HelloWorld(123)
luaUnit.assertNotNil(err)
luaUnit.assertEquals(ret, "")
luaUnit.assertEquals(err, "name expects a string")
end

os.exit(luaUnit.LuaUnit.run())
1
2
3
4
5
6
7
~$ lua test_helloworld.lua -v  
Started on Mon Jul 8 15:42:30 2019
testHelloWorld ... Ok
testHelloWorldWrongCase ... Ok
=========================================================
Ran 2 tests in 0.000 seconds, 2 successes, 0 failures
OK

備註

  1. “EVAL is a Lua 5.1 script.” redis.io

Reference & Resource