-
Notifications
You must be signed in to change notification settings - Fork 11
/
index.html
393 lines (302 loc) · 10.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
<div id="search_drop" data-root="$root" data-index="$root/reference.json"></div>
<section>
<h1>What is it?</h1>
$markdown{[[
Lapis is a framework for building web applications in [Lua](https://lua.org) (or [MoonScript](https://moonscript.org)) that primarily targets [OpenResty](https://openresty.org), a high performance web platform that runs on a customized version of [Nginx](https://nginx.org). Lapis can also be used in other server environments, being compatible with any modern version of Lua.
]]}
<div class="chat_banner">
<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
<p>
Want to talk Lapis? <a href="https://discord.gg/Y75ZXrD">Join our Discord</a>
</p>
</div>
$dual_code{
moon = [[
lapis = require "lapis"
class extends lapis.Application
"/": =>
"Hello world!"
]],
lua = [[
local lapis = require "lapis"
local app = lapis.Application()
app:match("/", function(self)
return "Hello world!"
end)
return app
]]}
</section>
<section>
<h1>How does it work?</h1>
$markdown{[[
With OpenResty, Lua is run directly inside of the Nginx worker using LuaJIT, giving you the
smallest barrier between the webserver and your code. Have a look at [Web Framework
Benchmarks](http://www.techempower.com/benchmarks) just to see how OpenResty
stacks up against other platforms.
Utilizing the power of [Lua
coroutines](https://leafo.net/posts/itchio-and-coroutines.html), you can write
clean code that looks synchronous but can achieve high throughput by
automatically running asynchronously without blocking. Networking operations
like database queries and HTTP requests will automatically yield to allow for
handling concurrent requests, all without all that callback spaghetti seen in
other asynchronous platforms. It's fast, easy to read, and easy to write.
]]}
</section>
<section>
<h1>What does it come with?</h1>
$markdown{[[
Lapis includes [URL routing][8], [HTML Templating][1], [CSRF Protection][2] and [Session][3]
support, [PostgreSQL/MySQL/SQLite backed models][4], [schema generation][5] and
[migrations][6] in addition to a [collection of useful functions][7] needed
when developing a website.
[1]: $root/reference/html_generation.html
[2]: $root/reference/utilities.html#csrf-protection
[3]: $root/reference/actions.html#request-object/session
[4]: $root/reference/models.html
[5]: $root/reference/database.html#database-schemas
[6]: $root/reference/database.html#database-migrations
[7]: $root/reference/utilities.html
[8]: $root/reference/actions.html#routes-and-url-patterns
]]}
$dual_code{
moon = [[
lapis = require "lapis"
class extends lapis.Application
-- Define a basic pattern that matches /
"/": =>
profile_url = @url_for "profile", name: "leafo"
-- Use HTML builder syntax helper to quickly and safely write markup
@html ->
h2 "Welcome!"
text "Go to my "
a href: profile_url, "profile"
-- Define a named route pattern with a variable called name
[profile: "/:name"]: =>
@html ->
div class: "profile", ->
text "Welcome to the profile of ", @params.name
]],
lua = [[
local lapis = require "lapis"
local app = lapis.Application()
-- Define a basic pattern that matches /
app:match("/", function(self)
local profile_url = self:url_for("profile", {name = "leafo"})
-- Use HTML builder syntax helper to quickly and safely write markup
return self:html(function()
h2("Welcome!")
text("Go to my ")
a({href = profile_url}, "profile")
end)
end)
-- Define a named route pattern with a variable called name
app:match("profile", "/:name", function(self)
return self:html(function()
div({class = "profile"},
"Welcome to the profile of " .. self.params.name)
end)
end)
return app
]]}
<h2>Models</h2>
$markdown{[[
Get a powerful abstraction layer over your database tables just by
sub-classing [`Model`]($root/reference/models.html):
]]}
$dual_code{
moon = [[
import Model from require "lapis.db.model"
-- Create a model, automatically backed by the table `users`
class Users extends Model
-- fetch some rows from the table
elderly_users = Users\select "where age > ? limit 5", 10
random_user = Users\find 1233 -- find by primary key
lee = Users\find name: "Lee", email: "[email protected]"
-- create a new row and edit it
user = Users\create {
name: "Leaf"
email: "[email protected]"
age: 6
}
user\update age: 10
user\delete!
]],
lua = [[
local Model = require("lapis.db.model").Model
-- Create a model, backed by the table `users`
local Users = Model:extend("users")
-- fetch some rows from the table
local elderly_users = Users:select("where age > ? limit 5", 10)
local random_user = Users:find(1233) -- find by primary key
local lee = Users:find({
name = "Lee",
email = "[email protected]"
})
-- create a new row and edit it
local user = Users:create({
name = "Leaf",
email = "[email protected]",
age = 6
})
user:update({ age = 10 })
user:delete()
]]}
<h2>Templates</h2>
$markdown{[[
Write your templates either in [etlua](https://github.com/leafo/etlua) or in
pure Lua/MoonScript.
The `Widget` base class allows you to organize your templates as modules,
enabling you to use inheritance and mixins to mix and match methods combined
with the HTML builder syntax that lets you express HTML with the full power of
the language you're already using.
The HTML builder syntax makes you immune to cross site scripting attacks from
user-provided input by ensuring all written content is escaped correctly.
]]}
$dual_code{
moon = [[
import Widget from require "lapis.html"
class Index extends Widget
content: =>
h1 class: "header", "Hello"
@user_panel!
div class: "body", ->
text "Welcome to my site!"
user_panel: =>
return unless @current_user
div class: "user_panel", "Welcome back " .. @current_user.name
]],
etlua = [[
<!-- views/index.etlua -->
<h1 class="header"><%= "Hello" %></h1>
<% if current_user then %>
<div class="user_panel">
Welcome back <%= current_user.name %>
</div>
<% end %>
<div class="body">
Welcome to my site
</div>
]] }
</section>
<section>
<h1>Full Example</h1>
<p>Using all the provided tools we can quickly and logically construct high
performance and low memory web applications. Here's a more complicated example
complete with forms, CSRF protection, and various database queries.</p>
$dual_code{
moon = [[
lapis = require "lapis"
import Model from require "lapis.db.model"
import respond_to, capture_errors from require "lapis.application"
csrf = require "lapis.csrf"
class Users extends Model
class extends lapis.Application
-- Execute code before every action
@before_filter =>
@csrf_token = csrf.generate_token @
[list_users: "/users"]: =>
users = Users\select! -- `select` all the users
-- Render HTML inline for simplicity
@html ->
ul ->
for user in *users
li ->
a href: @url_for("user", user.id), user.name
[user: "/profile/:id"]: =>
user = Users\find id: @params.id
return status: 404 unless user
@html -> h2 user.name
-- Respond to different HTTP actions to do the right thing
[new_user: "/user/new"]: respond_to {
POST: capture_errors =>
csrf.assert_token @
Users\create name: @params.username
redirect_to: @url_for "list_users"
GET: =>
@html ->
form method: "POST", action: @url_for("new_user"), ->
input type: "hidden",
name: "csrf_token", value: @csrf_token
input type: "text", name: "username"
}
]],
lua = [[
local lapis = require "lapis"
local Model = require("lapis.db.model").Model
local capture_errors = require("lapis.application").capture_errors
local csrf = require "lapis.csrf"
local Users = Model:extend("users")
local app = lapis.Application()
app:before_filter(function(self)
self.csrf_token = csrf.generate_token(self)
end)
app:get("list_users", "/users", function(self)
self.users = Users:select() -- `select` all users
return { render = true }
end)
app:get("user", "/profile/:id", function(self)
local user = Users:find({ id = self.params.id })
if not user then
return { status = 404 }
end
return { render = true }
end)
app:post("new_user", "/user/new", capture_errors(function(self)
csrf.assert_token(self)
Users:create({
name = assert_error(self.params.username, "Missing username")
})
return { redirect_to = self:url_for("list_users") }
end))
app:get("new_user", "/user/new", function(self)
return { render = true }
end)
return app
]]}
</section>
<section>
<h1>Where can I learn more?</h1>
$markdown{[[
The [Reference Manual]($root/reference.html) is both a complete guide and a tutorial to using Lapis.
The source of Lapis can be [found on Github](https://github.com/leafo/lapis)
and issues can be reported on the [issues
tracker](https://github.com/leafo/lapis/issues).
[LuaRocks.org](https://luarocks.org) is an open source application written in
Lapis. It is the public host for all Lua Rocks and the [source can be found on
GitHub](https://github.com/luarocks/luarocks-site).
]]}
</section>
<section>
<h1>Anything else I should know?</h1>
$markdown{[[
You can use most existing Lua libraries with Lapis with no problems.
Here are some libraries you might find useful:
* [`lapis-eswidget`](https://github.com/leafo/lapis-eswidget) -- Base widget class for aggregating front-end assets with esbuild
* [`lapis-console`](https://github.com/leafo/lapis-console) -- Interactive MoonScript console for Lapis that runs inside of your browser
* [`lapis-exceptions`](https://github.com/leafo/lapis-exceptions) -- Exception tracking and reporting
* [`lapis-bayes`](https://github.com/leafo/lapis-bayes) -- General purpose Bayes classification for Spam, Fraud, etc.
* [`web_sanitize`](https://github.com/leafo/web_sanitize) -- HTML sanitization
* [`tableshape`](https://github.com/leafo/tableshape) -- Robus input validation and verification
* [`magick`](https://github.com/leafo/magick) -- ImageMagick bindings
* [`cloud_storage`](https://github.com/leafo/cloud_storage) -- Support for Google Cloud Storage
]]}
</section>
<section>
<h1>About</h1>
$markdown{[[
Lapis would not be possible without the following projects:
* [Lua](http://lua.org)
* [LPeg](http://www.inf.puc-rio.br/~roberto/lpeg/)
* [OpenResty](http://openresty.org)
Lapis is licensed under the [MIT license](http://opensource.org/licenses/MIT).
Lapis is written by [@moonscript](http://twitter.com/moonscript).
]]}
</section>
<div class="has_buttons bottom_buttons">
<a href="$root/reference.html" class="button">Reference Manual</a>
·
<a href="https://github.com/leafo/lapis" class="button">Source on GitHub</a>
</div>
<div class="top_row">
<a href="#" class="top_link">↑ Top</a>
</div>