feat: add merge_all_wren utility, strutil demo, and 7 new API manual pages
Add WrenFileReader class in apps/merge_all_wren.wren for recursive .wren file discovery and content printing. Introduce example/strutil_demo.wren demonstrating case conversion, hex encoding, SHA256 hashing, string repetition, padding, HTML/JSON escaping, and URL encoding/decoding. Create manual/api pages for argparse, dataset, html, markdown, uuid, wdantic, and web modules. Update manual/api/index.html sidebar and module count from 21 to 28, adding links and cards for the new modules.
This commit is contained in:
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
import "web" for Client
|
||||
|
||||
var parsed1 = Client.parseUrl_("http://example.com/path")
|
||||
System.print(parsed1["scheme"]) // expect: http
|
||||
System.print(parsed1["host"]) // expect: example.com
|
||||
System.print(parsed1["port"]) // expect: 80
|
||||
System.print(parsed1["path"]) // expect: /path
|
||||
|
||||
var parsed2 = Client.parseUrl_("https://example.com/path")
|
||||
System.print(parsed2["scheme"]) // expect: https
|
||||
System.print(parsed2["port"]) // expect: 443
|
||||
|
||||
var parsed3 = Client.parseUrl_("http://example.com:8080/api/v1")
|
||||
System.print(parsed3["host"]) // expect: example.com
|
||||
System.print(parsed3["port"]) // expect: 8080
|
||||
System.print(parsed3["path"]) // expect: /api/v1
|
||||
|
||||
var parsed4 = Client.parseUrl_("https://api.example.com")
|
||||
System.print(parsed4["host"]) // expect: api.example.com
|
||||
System.print(parsed4["path"]) // expect: /
|
||||
|
||||
var parsed5 = Client.parseUrl_("http://localhost:3000/")
|
||||
System.print(parsed5["host"]) // expect: localhost
|
||||
System.print(parsed5["port"]) // expect: 3000
|
||||
System.print(parsed5["path"]) // expect: /
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
import "web" for Request
|
||||
|
||||
var headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "text/html",
|
||||
"Cookie": "session=abc123; user=alice"
|
||||
}
|
||||
|
||||
var req = Request.new_("POST", "/api/users", {"page": "1", "limit": "10"}, headers, "{\"name\":\"Alice\"}", {"id": "42"}, null)
|
||||
|
||||
System.print(req.method) // expect: POST
|
||||
System.print(req.path) // expect: /api/users
|
||||
System.print(req.query["page"]) // expect: 1
|
||||
System.print(req.query["limit"]) // expect: 10
|
||||
System.print(req.params["id"]) // expect: 42
|
||||
System.print(req.body) // expect: {"name":"Alice"}
|
||||
|
||||
System.print(req.header("Content-Type")) // expect: application/json
|
||||
System.print(req.header("content-type")) // expect: application/json
|
||||
System.print(req.header("ACCEPT")) // expect: text/html
|
||||
System.print(req.header("X-Missing") == null) // expect: true
|
||||
|
||||
var json = req.json
|
||||
System.print(json["name"]) // expect: Alice
|
||||
|
||||
var cookies = req.cookies
|
||||
System.print(cookies["session"]) // expect: abc123
|
||||
System.print(cookies["user"]) // expect: alice
|
||||
|
||||
var formBody = "username=bob&password=secret"
|
||||
var formReq = Request.new_("POST", "/login", {}, {"Content-Type": "application/x-www-form-urlencoded"}, formBody, {}, null)
|
||||
var form = formReq.form
|
||||
System.print(form["username"]) // expect: bob
|
||||
System.print(form["password"]) // expect: secret
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
import "web" for Response
|
||||
|
||||
var r1 = Response.redirect("/dashboard", 301)
|
||||
System.print(r1.status) // expect: 301
|
||||
System.print(r1.headers["Location"]) // expect: /dashboard
|
||||
|
||||
var r2 = Response.new()
|
||||
r2.status = 404
|
||||
r2.body = "Not Found"
|
||||
System.print(r2.status) // expect: 404
|
||||
System.print(r2.body) // expect: Not Found
|
||||
|
||||
var r3 = Response.new()
|
||||
r3.header("X-Custom", "value1")
|
||||
r3.header("X-Another", "value2")
|
||||
System.print(r3.headers["X-Custom"]) // expect: value1
|
||||
System.print(r3.headers["X-Another"]) // expect: value2
|
||||
|
||||
var r4 = Response.new()
|
||||
r4.cookie("session", "abc123")
|
||||
r4.body = "test"
|
||||
var built = r4.build()
|
||||
System.print(built.contains("Set-Cookie: session=abc123")) // expect: true
|
||||
|
||||
var r5 = Response.new()
|
||||
r5.cookie("auth", "token", {"path": "/", "httpOnly": true, "maxAge": 3600})
|
||||
r5.body = "test"
|
||||
var built2 = r5.build()
|
||||
System.print(built2.contains("Path=/")) // expect: true
|
||||
System.print(built2.contains("HttpOnly")) // expect: true
|
||||
System.print(built2.contains("Max-Age=3600")) // expect: true
|
||||
|
||||
var r6 = Response.text("Hello World")
|
||||
var httpResponse = r6.build()
|
||||
System.print(httpResponse.contains("HTTP/1.1 200 OK")) // expect: true
|
||||
System.print(httpResponse.contains("Content-Length:")) // expect: true
|
||||
System.print(httpResponse.contains("Hello World")) // expect: true
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
import "web" for Router
|
||||
|
||||
var router = Router.new()
|
||||
|
||||
router.get("/api/v1/*", Fn.new { |r| "wildcard" })
|
||||
router.put("/users/:id", Fn.new { |r| "put user" })
|
||||
router.delete("/users/:id", Fn.new { |r| "delete user" })
|
||||
router.patch("/users/:id", Fn.new { |r| "patch user" })
|
||||
router.post("/users", Fn.new { |r| "create user" })
|
||||
|
||||
var m1 = router.match("GET", "/api/v1/anything")
|
||||
System.print(m1 != null) // expect: true
|
||||
|
||||
var m2 = router.match("GET", "/api/v1/nested/path")
|
||||
System.print(m2 != null) // expect: true
|
||||
|
||||
var m3 = router.match("PUT", "/users/456")
|
||||
System.print(m3 != null) // expect: true
|
||||
System.print(m3["params"]["id"]) // expect: 456
|
||||
|
||||
var m4 = router.match("DELETE", "/users/789")
|
||||
System.print(m4 != null) // expect: true
|
||||
System.print(m4["params"]["id"]) // expect: 789
|
||||
|
||||
var m5 = router.match("PATCH", "/users/101")
|
||||
System.print(m5 != null) // expect: true
|
||||
|
||||
var m6 = router.match("POST", "/users")
|
||||
System.print(m6 != null) // expect: true
|
||||
|
||||
var m7 = router.match("OPTIONS", "/users")
|
||||
System.print(m7 == null) // expect: true
|
||||
|
||||
var router2 = Router.new()
|
||||
router2.get("/posts/:postId/comments/:commentId", Fn.new { |r| "comment" })
|
||||
|
||||
var m8 = router2.match("GET", "/posts/10/comments/20")
|
||||
System.print(m8 != null) // expect: true
|
||||
System.print(m8["params"]["postId"]) // expect: 10
|
||||
System.print(m8["params"]["commentId"]) // expect: 20
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
import "web" for Session, SessionStore
|
||||
|
||||
var store = SessionStore.new()
|
||||
var session = store.create()
|
||||
|
||||
session["name"] = "Alice"
|
||||
session["age"] = 30
|
||||
session["active"] = true
|
||||
|
||||
System.print(session["name"]) // expect: Alice
|
||||
System.print(session["age"]) // expect: 30
|
||||
System.print(session["active"]) // expect: true
|
||||
System.print(session["nonexistent"] == null) // expect: true
|
||||
|
||||
System.print(session.isModified) // expect: true
|
||||
|
||||
session.remove("age")
|
||||
System.print(session["age"] == null) // expect: true
|
||||
|
||||
store.save(session)
|
||||
|
||||
var data = session.data
|
||||
System.print(data.containsKey("name")) // expect: true
|
||||
System.print(data.containsKey("age")) // expect: false
|
||||
System.print(data["active"]) // expect: true
|
||||
|
||||
var session2 = store.create()
|
||||
var session3 = store.create()
|
||||
System.print(session.id != session2.id) // expect: true
|
||||
System.print(session2.id != session3.id) // expect: true
|
||||
System.print(session.id.count) // expect: 36
|
||||
System.print(session2.id.count) // expect: 36
|
||||
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
|
||||
import "web" for View, Response, Request
|
||||
|
||||
class TestView is View {
|
||||
construct new() {}
|
||||
|
||||
get(request) {
|
||||
return Response.json({"method": "GET"})
|
||||
}
|
||||
|
||||
post(request) {
|
||||
return Response.json({"method": "POST"})
|
||||
}
|
||||
|
||||
put(request) {
|
||||
return Response.json({"method": "PUT"})
|
||||
}
|
||||
|
||||
delete(request) {
|
||||
return Response.json({"method": "DELETE"})
|
||||
}
|
||||
}
|
||||
|
||||
class GetOnlyView is View {
|
||||
construct new() {}
|
||||
|
||||
get(request) {
|
||||
return Response.text("GET only")
|
||||
}
|
||||
}
|
||||
|
||||
var mockGet = Request.new_("GET", "/test", {}, {}, "", {}, null)
|
||||
var mockPost = Request.new_("POST", "/test", {}, {}, "", {}, null)
|
||||
var mockPut = Request.new_("PUT", "/test", {}, {}, "", {}, null)
|
||||
var mockDelete = Request.new_("DELETE", "/test", {}, {}, "", {}, null)
|
||||
var mockPatch = Request.new_("PATCH", "/test", {}, {}, "", {}, null)
|
||||
|
||||
var view = TestView.new()
|
||||
|
||||
var r1 = view.dispatch(mockGet)
|
||||
System.print(r1.body.contains("GET")) // expect: true
|
||||
|
||||
var r2 = view.dispatch(mockPost)
|
||||
System.print(r2.body.contains("POST")) // expect: true
|
||||
|
||||
var r3 = view.dispatch(mockPut)
|
||||
System.print(r3.body.contains("PUT")) // expect: true
|
||||
|
||||
var r4 = view.dispatch(mockDelete)
|
||||
System.print(r4.body.contains("DELETE")) // expect: true
|
||||
|
||||
var getOnlyView = GetOnlyView.new()
|
||||
var r5 = getOnlyView.dispatch(mockGet)
|
||||
System.print(r5.body) // expect: GET only
|
||||
|
||||
var r6 = getOnlyView.dispatch(mockPost)
|
||||
System.print(r6.status) // expect: 405
|
||||
Reference in New Issue
Block a user