Web development with
Lua Programming
Language
Introducing Sailor, an MVC
web framework in Lua

Etiene Dalcol
@etiene_d
@etiene_dCoding Serbia 2015
@etiene_d
@etiene_dCoding Serbia 2015
Sailor!

sailorproject.org
@etiene_dCoding Serbia 2015
Lua Ladies

lualadies.org
@etiene_dCoding Serbia 2015
Google Summer of Code
LabLua
@etiene_dCoding Serbia 2015
Lua overview
The state of web dev
Sailor

@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
Advantages
Powerful.
@etiene_dCoding Serbia 2015
Advantages
Simple.Powerful.
@etiene_dCoding Serbia 2015
_G
_VERSION
assert
collectgarbage
dofile
error
getmetatable
ipairs
load
loadfile
next
pairs
pcall
print
rawequal
rawget
rawlen
rawset
require
select
setmetatable
tonumber
tostring
type
xpcall
bit32.arshift
bit32.band
bit32.bnot
bit32.bor
bit32.btest
bit32.bxor
bit32.extract
bit32.lrotate
bit32.lshift
bit32.replace
bit32.rrotate
bit32.rshift
coroutine.create
coroutine.resume
coroutine.running
coroutine.status
coroutine.wrap
coroutine.yield
debug.debug
debug.getuservalue
debug.gethook
debug.getinfo
debug.getlocal
debug.getmetatable
debug.getregistry
debug.getupvalue
debug.setuservalue
debug.sethook
debug.setlocal
debug.setmetatable
debug.setupvalue
debug.traceback
debug.upvalueid
debug.upvaluejoin
io.close
io.flush
io.input
io.lines
io.open
io.output
io.popen
io.read
io.stderr
io.stdin
io.stdout
io.tmpfile
io.type
io.write
file:close
file:flush
file:lines
file:read
file:seek
file:setvbuf
file:write
math.abs
math.acos
math.asin
math.atan
math.atan2
math.ceil
math.cos
math.cosh
math.deg
math.exp
math.floor
math.fmod
math.frexp
math.huge
math.ldexp
math.log
math.max
math.min
math.modf
math.pi
math.pow
math.rad
math.random
math.randomseed
math.sin
math.sinh
math.sqrt
math.tan
math.tanh
os.clock
os.date
os.difftime
os.execute
os.exit
os.getenv
os.remove
os.rename
os.setlocale
os.time
os.tmpname
package
package.config
package.cpath
package.loaded
package.loadlib
package.path
package.preload
package.searchers
package.searchpath
string.byte
string.char
string.dump
string.find
string.format
string.gmatch
string.gsub
string.len
string.lower
string.match
string.rep
string.reverse
string.sub
string.upper
table.concat
table.insert
table.pack
table.remove
table.sort
table.unpack
@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
Advantages
Fast.Simple.Powerful.
@etiene_dCoding Serbia 2015
http://www.humbedooh.com/presentations/ACNA%20-%20mod_lua.odp Introducing mod_lua by Daniel Gruno
@etiene_dCoding Serbia 2015
Better Reasons
• It looks cool
(I heard you could make games with it)
@etiene_dCoding Serbia 2015
Better Reasons
• It looks cool
(I heard you could make games with it)
• It’s made in my home country
(In my university to be more precise)
@etiene_dCoding Serbia 2015
• It looks cool
(I heard you could make games with it)
• It’s made in my home country
(In my university to be more precise)
• It’s easy to learn
Better Reasons
@etiene_dCoding Serbia 2015
-- Cipher module
--[[ Based on algorithms/caesar_cipher.lua
by Roland Yonaba ]]
local cipher = {}
local function ascii_base(s)
return s:lower() == s and ('a'):byte() or ('A'):byte()
end
function cipher.caesar( str, key )
return str:gsub('%a', function(s)
local base = ascii_base(s)
return string.char(((s:byte() - base + key) % 26) + base)
end)
end
return cipher
One slide crash course: cipher module
@etiene_dCoding Serbia 2015
-- Cipher module
--[[ Based on algorithms/caesar_cipher.lua
by Roland Yonaba ]]
local cipher = {}
local function ascii_base(s)
return s:lower() == s and ('a'):byte() or ('A'):byte()
end
function cipher.caesar( str, key )
return str:gsub('%a', function(s)
local base = ascii_base(s)
return string.char(((s:byte() - base + key) % 26) + base)
end)
end
return cipher
One slide crash course: cipher module
@etiene_dCoding Serbia 2015
-- Cipher module
--[[ Based on algorithms/caesar_cipher.lua
by Roland Yonaba ]]
local cipher = {}
local function ascii_base(s)
return s:lower() == s and ('a'):byte() or ('A'):byte()
end
function cipher.caesar( str, key )
return str:gsub('%a', function(s)
local base = ascii_base(s)
return string.char(((s:byte() - base + key) % 26) + base)
end)
end
return cipher
One slide crash course: cipher module
@etiene_dCoding Serbia 2015
-- Cipher module
--[[ Based on algorithms/caesar_cipher.lua
by Roland Yonaba ]]
local cipher = {}
local function ascii_base(s)
return s:lower() == s and ('a'):byte() or ('A'):byte()
end
function cipher.caesar( str, key )
return str:gsub('%a', function(s)
local base = ascii_base(s)
return string.char(((s:byte() - base + key) % 26) + base)
end)
end
return cipher
One slide crash course: cipher module
@etiene_dCoding Serbia 2015
-- Cipher module
--[[ Based on algorithms/caesar_cipher.lua
by Roland Yonaba ]]
local cipher = {}
local function ascii_base(s)
return s:lower() == s and ('a'):byte() or ('A'):byte()
end
function cipher.caesar( str, key )
return str:gsub('%a', function(s)
local base = ascii_base(s)
return string.char(((s:byte() - base + key) % 26) + base)
end)
end
return cipher
One slide crash course: cipher module
@etiene_dCoding Serbia 2015
-- Cipher module
--[[ Based on algorithms/caesar_cipher.lua
by Roland Yonaba ]]
local cipher = {}
local function ascii_base(s)
return s:lower() == s and ('a'):byte() or ('A'):byte()
end
function cipher.caesar( str, key )
return str:gsub('%a', function(s)
local base = ascii_base(s)
return string.char(((s:byte() - base + key) % 26) + base)
end)
end
return cipher
One slide crash course: cipher module
@etiene_dCoding Serbia 2015
-- Cipher module
--[[ Based on algorithms/caesar_cipher.lua
by Roland Yonaba ]]
local cipher = {}
local function ascii_base(s)
return s:lower() == s and ('a'):byte() or ('A'):byte()
end
function cipher.caesar( str, key )
return str:gsub('%a', function(s)
local base = ascii_base(s)
return string.char(((s:byte() - base + key) % 26) + base)
end)
end
return cipher
One slide crash course: cipher module
@etiene_dCoding Serbia 2015
?
?
Learning Lua
?
? ?
@etiene_dCoding Serbia 2015
Lua on the web
• Early stage
• cgilua ~ 1995
• Kepler Project ~ 2003
@etiene_dCoding Serbia 2015
“ I have myself developed Web sites with pure C++, Java, C#, PHP, and Python.
The easiest way to go was definitely Python. If the libraries existed, Lua would be
not quite as easy to use as Python, but probably quite a bit more efficient; I think it
would become my first choice... if the libraries existed.” Michael Gogins
“ Recently there was some discussion about mod_lua on the Apache developers
mailing list. I mentioned there that I feel Lua could replace PHP as the number one
web scripting language if mod_lua were stable (i.e. not still in beta) and it were
implemented well (not making some of PHP's mistakes such as putting everything
in the global scope with no consistent naming or parameter schemes). I've wanted
to use Lua for all the things I currently use PHP for ever since I discovered it.” Rena
@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
9423
words
http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/
@etiene_dCoding Serbia 2015
9423
words
http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/
@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
Why?
@etiene_dCoding Serbia 2015
Why?
http://blog.codinghorror.com/php-sucks-but-it-doesnt-matter/
@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
Why isn’t Lua
more popular?
@etiene_dCoding Serbia 2015
Servers
• Apache: mod_lua
• Nginx: OpenResty
@etiene_dCoding Serbia 2015
Servers
• Apache: mod_lua
• Nginx: OpenResty







@etiene_dCoding Serbia 2015
Servers
• Apache: mod_lua
• Nginx: OpenResty
• Xavante
• Others: Lighttpd, Lwan, Pegasus, Mongoose
@etiene_dCoding Serbia 2015
Frameworks
Orbit (2007)
Least known
No significant updates since 2010
MVC
@etiene_dCoding Serbia 2015
Frameworks
Orbit (2007)
Least known
No significant updates since 2010
MVC
Luvit (2011)
Most popular
Intense development
node.js port 2-4x faster
Needs a better documentation
@etiene_dCoding Serbia 2015
Frameworks
Lapis (2012)
Intense development
Moonscript and Lua
Very well documented
Templater
OpenResty only
Not MVC
@etiene_dCoding Serbia 2015
Frameworks
Lapis (2012)
Intense development
Moonscript and Lua
Very well documented
Templater
OpenResty only
Not MVC
Others
Complicated, abandoned, poorly documented, license
issues or I never heard about it...
@etiene_dCoding Serbia 2015
Sailor!
@etiene_dCoding Serbia 2015
Sailor!
@etiene_dCoding Serbia 2015
Sailor!
0.1
(Venus)
@etiene_dCoding Serbia 2015
Sailor!
0.1
(Venus)
0.2
(Mars)
@etiene_dCoding Serbia 2015
What exactly is
Sailor?
• It’s an MVC web framework
• Completely written in Lua
• Compatible with Apache (mod_lua), Nginx (OpenResty),
Xavante, Mongoose, Lighttpd and Lwan
• Compatible with Linux, Windows and Mac
• Compatible with different databases
• MIT License
• Pre alpha v0.4 (Chibi)
• 0.5 (Pluto) will be released soon!
@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
What (else) is cool about
Sailor?
• Routing and friendly URLs
• Session, cookies, include, redirect…
• Lua Pages parsing
• Mail sending
• Simple Object Relational-Mapping
• Validation (valua)
• Basic login and authentication modules
• Form generation
• Themes (Bootstrap integration out of the box)
• App generator (Linux and Mac only)
• Model and CRUD generator
• Automated tests
@etiene_dCoding Serbia 2015
• Routing and friendly URLs
• Session, cookies, include, redirect…
• Lua Pages parsing
• Mail sending
• Simple Object Relational-Mapping
• Validation (valua)
• Basic login and authentication modules
• Form generation
• Themes (Bootstrap integration out of the box)
• App generator (Linux and Mac only)
• Model and CRUD generator
• Automated tests
• Lua at client
What (else) is cool about
Sailor?
@etiene_dCoding Serbia 2015
Not so great things
• It’s still in early development
• Things are changing fast
• It lacks features
• Documentation
@etiene_dCoding Serbia 2015
How to get Sailor!
$ luarocks install sailor

$ sailor create ‘My App’ /var/www

$ cd /var/www/my_app

$ lua start-server.lua
@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
$ luarocks install luasql-mysql
How to get Sailor!
$ luarocks install sailor

$ sailor create ‘My App’ /var/www

$ cd /var/www/my_app

$ lua start-server.lua
@etiene_dCoding Serbia 2015
/conf
/controllers
/models
/pub
/runtime
/tests
/themes
/views
App structure
@etiene_dCoding Serbia 2015
/conf
/controllers
/models
/pub
/runtime
/tests
/themes
/views
App structure
Lua files

Stuff! 

JS libraries, images…

Temp files
Lua Pages
@etiene_dCoding Serbia 2015
Example!
-- /controllers/site.lua

local site = {}



function site.index(page)

local msg = “Hello World”

page:render(‘index’, { msg = msg } )

end

function site.notindex(page)

page.theme = nil

page:write(“I’m different!”)

end



return site
@etiene_dCoding Serbia 2015
<!-- /views/site/index.lp —>





<p> 

A message from the server:

<?lua page:print(msg) ?>

<br/>

The message again:

<%= msg %> <!-- syntactic sugar: same thing as above —>

</p>

Example!
@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
<?lua@server -- Code here runs on the server ?>

<?lua -- Same as above ?>

<?lua@client -- Runs at the client ?>

<?lua@both -- Runs at the server and the client ?>



<?lua@both

another_msg = “Another message”

?>

<?lua page:print(another_msg) ?>

<?lua@client

js.window.alert(another_msg)-- Sailor v0.4

-- window:alert(another_msg) 

-- ^ Sailor v0.5

?>
Example!
@etiene_dCoding Serbia 2015
@etiene_dCoding Serbia 2015
local user = {}

local v = require “valua” -- validation module



user.attributes = {

{ id = “safe” },

{ name = v:new().not_empty().len(6,50) }

}

user.db = {

key = ‘id’,

table = ‘users’

}

user.relations = {

posts = { -- u.posts

relation = “HAS_MANY”, model = “post”, attribute = “author_id”

}

}

return user
Example!
@etiene_dCoding Serbia 2015
local user = {}

local v = require “valua” -- validation module



user.attributes = {

{ id = “safe” },

{ name = v:new().not_empty().len(6,50) }

}

user.db = {

key = ‘id’,

table = ‘users’

}

user.relations = {

posts = { -- u.posts

relation = “HAS_MANY”, model = “post”, attribute = “author_id”

}

}

return user
Example!
@etiene_dCoding Serbia 2015
-- /controllers/site.lua
local site = {}

function site.index(page)
local User = sailor.model(‘user’)
local u = User:new()
u.name = ‘Arnold’
local msg
if u:save() then
msg = ‘Success’
else
msg = table.unpack(u.errors)
end
local users = User:find_all()
page:render(‘index’, { msg = msg, users = users } )
end 

return site
Example!
sailorproject.org
github.com/Etiene/sailor
dalcol@etiene.net
@etiene_d
sailorproject.org
github.com/Etiene/sailor
dalcol@etiene.net
@etiene_d
sailorproject.org
github.com/Etiene/sailor
dalcol@etiene.net
@etiene_d
Thank you!
sailorproject.org
github.com/Etiene/sailor
dalcol@etiene.net
@etiene_d

Web development with Lua: Introducing Sailor an MVC web framework @ CodingSerbia 2015