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:
2026-01-25 01:47:47 +00:00
parent 5a4054ec66
commit 74ef5cbc11
74 changed files with 7749 additions and 292 deletions
+27
View File
@@ -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: /
+36
View File
@@ -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
+39
View File
@@ -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
+42
View File
@@ -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
+34
View File
@@ -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
+58
View File
@@ -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