feat: add example scripts for argparse, bytes, dataset, html, markdown, uuid, wdantic, and web chat modules
Add comprehensive demo scripts showcasing the usage of multiple Wren modules including argument parsing, byte manipulation, in-memory dataset operations, HTML encoding/slugification, markdown-to-HTML conversion, UUID generation/validation, schema validation with wdantic, and a full web chat application with REST endpoints.
This commit is contained in:
@@ -0,0 +1,421 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- retoor <retoor@molodetz.nl> -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Async Programming - Wren-CLI Manual</title>
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<button class="mobile-menu-toggle">Menu</button>
|
||||
<div class="container">
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1><a href="../index.html">Wren-CLI</a></h1>
|
||||
<div class="version">v0.4.0</div>
|
||||
</div>
|
||||
<nav class="sidebar-nav">
|
||||
<div class="section">
|
||||
<span class="section-title">Getting Started</span>
|
||||
<ul>
|
||||
<li><a href="../getting-started/index.html">Overview</a></li>
|
||||
<li><a href="../getting-started/installation.html">Installation</a></li>
|
||||
<li><a href="../getting-started/first-script.html">First Script</a></li>
|
||||
<li><a href="../getting-started/repl.html">Using the REPL</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section-title">Language</span>
|
||||
<ul>
|
||||
<li><a href="../language/index.html">Syntax Overview</a></li>
|
||||
<li><a href="../language/classes.html">Classes</a></li>
|
||||
<li><a href="../language/methods.html">Methods</a></li>
|
||||
<li><a href="../language/control-flow.html">Control Flow</a></li>
|
||||
<li><a href="../language/fibers.html">Fibers</a></li>
|
||||
<li><a href="../language/modules.html">Modules</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section-title">API Reference</span>
|
||||
<ul>
|
||||
<li><a href="../api/index.html">Overview</a></li>
|
||||
<li><a href="../api/http.html">http</a></li>
|
||||
<li><a href="../api/websocket.html">websocket</a></li>
|
||||
<li><a href="../api/tls.html">tls</a></li>
|
||||
<li><a href="../api/net.html">net</a></li>
|
||||
<li><a href="../api/dns.html">dns</a></li>
|
||||
<li><a href="../api/json.html">json</a></li>
|
||||
<li><a href="../api/base64.html">base64</a></li>
|
||||
<li><a href="../api/regex.html">regex</a></li>
|
||||
<li><a href="../api/jinja.html">jinja</a></li>
|
||||
<li><a href="../api/crypto.html">crypto</a></li>
|
||||
<li><a href="../api/os.html">os</a></li>
|
||||
<li><a href="../api/env.html">env</a></li>
|
||||
<li><a href="../api/signal.html">signal</a></li>
|
||||
<li><a href="../api/subprocess.html">subprocess</a></li>
|
||||
<li><a href="../api/sqlite.html">sqlite</a></li>
|
||||
<li><a href="../api/datetime.html">datetime</a></li>
|
||||
<li><a href="../api/timer.html">timer</a></li>
|
||||
<li><a href="../api/io.html">io</a></li>
|
||||
<li><a href="../api/scheduler.html">scheduler</a></li>
|
||||
<li><a href="../api/math.html">math</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section-title">Tutorials</span>
|
||||
<ul>
|
||||
<li><a href="../tutorials/index.html">Tutorial List</a></li>
|
||||
<li><a href="../tutorials/http-client.html">HTTP Client</a></li>
|
||||
<li><a href="../tutorials/websocket-chat.html">WebSocket Chat</a></li>
|
||||
<li><a href="../tutorials/database-app.html">Database App</a></li>
|
||||
<li><a href="../tutorials/template-rendering.html">Template Rendering</a></li>
|
||||
<li><a href="../tutorials/cli-tool.html">CLI Tool</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section-title">How-To Guides</span>
|
||||
<ul>
|
||||
<li><a href="index.html">How-To List</a></li>
|
||||
<li><a href="http-requests.html">HTTP Requests</a></li>
|
||||
<li><a href="json-parsing.html">JSON Parsing</a></li>
|
||||
<li><a href="regex-patterns.html">Regex Patterns</a></li>
|
||||
<li><a href="file-operations.html">File Operations</a></li>
|
||||
<li><a href="async-operations.html" class="active">Async Operations</a></li>
|
||||
<li><a href="error-handling.html">Error Handling</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
<main class="content">
|
||||
<nav class="breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span class="separator">/</span>
|
||||
<a href="index.html">How-To Guides</a>
|
||||
<span class="separator">/</span>
|
||||
<span>Async Operations</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Async Programming</h1>
|
||||
|
||||
<p>Wren-CLI uses fibers for concurrent operations. Understanding fibers is key to writing efficient async code.</p>
|
||||
|
||||
<h2>Create a Fiber</h2>
|
||||
<pre><code>var fiber = Fiber.new {
|
||||
System.print("Hello from fiber!")
|
||||
}
|
||||
|
||||
fiber.call()</code></pre>
|
||||
|
||||
<h2>Fibers with Return Values</h2>
|
||||
<pre><code>var fiber = Fiber.new {
|
||||
return 42
|
||||
}
|
||||
|
||||
var result = fiber.call()
|
||||
System.print("Result: %(result)") // 42</code></pre>
|
||||
|
||||
<h2>Sleep/Delay</h2>
|
||||
<pre><code>import "timer" for Timer
|
||||
|
||||
System.print("Starting...")
|
||||
Timer.sleep(1000) // Wait 1 second
|
||||
System.print("Done!")</code></pre>
|
||||
|
||||
<h2>Sequential HTTP Requests</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var r1 = Http.get("https://api.example.com/1")
|
||||
var r2 = Http.get("https://api.example.com/2")
|
||||
var r3 = Http.get("https://api.example.com/3")
|
||||
|
||||
System.print(r1.json)
|
||||
System.print(r2.json)
|
||||
System.print(r3.json)</code></pre>
|
||||
|
||||
<h2>Parallel HTTP Requests</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var urls = [
|
||||
"https://api.example.com/1",
|
||||
"https://api.example.com/2",
|
||||
"https://api.example.com/3"
|
||||
]
|
||||
|
||||
var fibers = []
|
||||
for (url in urls) {
|
||||
fibers.add(Fiber.new { Http.get(url) })
|
||||
}
|
||||
|
||||
for (fiber in fibers) {
|
||||
fiber.call()
|
||||
}
|
||||
|
||||
for (fiber in fibers) {
|
||||
System.print(fiber.value)
|
||||
}</code></pre>
|
||||
|
||||
<h2>Run Task in Background</h2>
|
||||
<pre><code>import "timer" for Timer
|
||||
|
||||
var backgroundTask = Fiber.new {
|
||||
for (i in 1..5) {
|
||||
System.print("Background: %(i)")
|
||||
Timer.sleep(500)
|
||||
}
|
||||
}
|
||||
|
||||
backgroundTask.call()
|
||||
|
||||
System.print("Main thread continues...")
|
||||
Timer.sleep(3000)</code></pre>
|
||||
|
||||
<h2>Wait for Multiple Operations</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var fetchAll = Fn.new { |urls|
|
||||
var results = []
|
||||
var fibers = []
|
||||
|
||||
for (url in urls) {
|
||||
fibers.add(Fiber.new { Http.get(url) })
|
||||
}
|
||||
|
||||
for (fiber in fibers) {
|
||||
fiber.call()
|
||||
}
|
||||
|
||||
for (fiber in fibers) {
|
||||
results.add(fiber.value)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
var responses = fetchAll.call([
|
||||
"https://api.example.com/a",
|
||||
"https://api.example.com/b"
|
||||
])
|
||||
|
||||
for (r in responses) {
|
||||
System.print(r.statusCode)
|
||||
}</code></pre>
|
||||
|
||||
<h2>Timeout Pattern</h2>
|
||||
<pre><code>import "timer" for Timer
|
||||
import "datetime" for DateTime
|
||||
|
||||
var withTimeout = Fn.new { |operation, timeoutMs|
|
||||
var start = DateTime.now()
|
||||
var result = null
|
||||
var done = false
|
||||
|
||||
var workFiber = Fiber.new {
|
||||
result = operation.call()
|
||||
done = true
|
||||
}
|
||||
|
||||
workFiber.call()
|
||||
|
||||
while (!done) {
|
||||
var elapsed = (DateTime.now() - start).milliseconds
|
||||
if (elapsed >= timeoutMs) {
|
||||
Fiber.abort("Operation timed out")
|
||||
}
|
||||
Timer.sleep(10)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
var result = withTimeout.call(Fn.new {
|
||||
Timer.sleep(500)
|
||||
return "completed"
|
||||
}, 1000)
|
||||
|
||||
System.print(result)</code></pre>
|
||||
|
||||
<h2>Polling Loop</h2>
|
||||
<pre><code>import "timer" for Timer
|
||||
import "http" for Http
|
||||
|
||||
var pollUntilReady = Fn.new { |url, maxAttempts|
|
||||
var attempts = 0
|
||||
|
||||
while (attempts < maxAttempts) {
|
||||
attempts = attempts + 1
|
||||
System.print("Attempt %(attempts)...")
|
||||
|
||||
var response = Http.get(url)
|
||||
if (response.json["ready"]) {
|
||||
return response.json
|
||||
}
|
||||
|
||||
Timer.sleep(2000)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
var result = pollUntilReady.call("https://api.example.com/status", 10)
|
||||
if (result) {
|
||||
System.print("Ready: %(result)")
|
||||
} else {
|
||||
System.print("Timed out waiting for ready state")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Rate Limiting</h2>
|
||||
<pre><code>import "timer" for Timer
|
||||
import "http" for Http
|
||||
|
||||
var rateLimitedFetch = Fn.new { |urls, delayMs|
|
||||
var results = []
|
||||
|
||||
for (url in urls) {
|
||||
var response = Http.get(url)
|
||||
results.add(response)
|
||||
Timer.sleep(delayMs)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
var responses = rateLimitedFetch.call([
|
||||
"https://api.example.com/1",
|
||||
"https://api.example.com/2",
|
||||
"https://api.example.com/3"
|
||||
], 1000)
|
||||
|
||||
for (r in responses) {
|
||||
System.print(r.statusCode)
|
||||
}</code></pre>
|
||||
|
||||
<h2>Producer/Consumer Pattern</h2>
|
||||
<pre><code>import "timer" for Timer
|
||||
|
||||
var queue = []
|
||||
var running = true
|
||||
|
||||
var producer = Fiber.new {
|
||||
for (i in 1..10) {
|
||||
queue.add(i)
|
||||
System.print("Produced: %(i)")
|
||||
Timer.sleep(200)
|
||||
}
|
||||
running = false
|
||||
}
|
||||
|
||||
var consumer = Fiber.new {
|
||||
while (running || queue.count > 0) {
|
||||
if (queue.count > 0) {
|
||||
var item = queue.removeAt(0)
|
||||
System.print("Consumed: %(item)")
|
||||
}
|
||||
Timer.sleep(100)
|
||||
}
|
||||
}
|
||||
|
||||
producer.call()
|
||||
consumer.call()
|
||||
|
||||
System.print("Done!")</code></pre>
|
||||
|
||||
<h2>Retry with Exponential Backoff</h2>
|
||||
<pre><code>import "timer" for Timer
|
||||
import "http" for Http
|
||||
|
||||
var retryWithBackoff = Fn.new { |operation, maxRetries|
|
||||
var attempt = 0
|
||||
var delay = 1000
|
||||
|
||||
while (attempt < maxRetries) {
|
||||
var fiber = Fiber.new { operation.call() }
|
||||
var result = fiber.try()
|
||||
|
||||
if (!fiber.error) {
|
||||
return result
|
||||
}
|
||||
|
||||
attempt = attempt + 1
|
||||
System.print("Attempt %(attempt) failed, retrying in %(delay)ms...")
|
||||
Timer.sleep(delay)
|
||||
delay = delay * 2
|
||||
}
|
||||
|
||||
Fiber.abort("All %(maxRetries) attempts failed")
|
||||
}
|
||||
|
||||
var response = retryWithBackoff.call(Fn.new {
|
||||
return Http.get("https://api.example.com/data")
|
||||
}, 3)
|
||||
|
||||
System.print(response.json)</code></pre>
|
||||
|
||||
<h2>Concurrent WebSocket Handling</h2>
|
||||
<pre><code>import "websocket" for WebSocket, WebSocketMessage
|
||||
import "timer" for Timer
|
||||
|
||||
var ws = WebSocket.connect("ws://localhost:8080")
|
||||
|
||||
var receiver = Fiber.new {
|
||||
while (true) {
|
||||
var message = ws.receive()
|
||||
if (message == null) break
|
||||
if (message.opcode == WebSocketMessage.TEXT) {
|
||||
System.print("Received: %(message.payload)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sender = Fiber.new {
|
||||
for (i in 1..5) {
|
||||
ws.send("Message %(i)")
|
||||
Timer.sleep(1000)
|
||||
}
|
||||
ws.close()
|
||||
}
|
||||
|
||||
receiver.call()
|
||||
sender.call()</code></pre>
|
||||
|
||||
<h2>Graceful Shutdown</h2>
|
||||
<pre><code>import "signal" for Signal
|
||||
import "timer" for Timer
|
||||
|
||||
var running = true
|
||||
|
||||
Signal.handle("SIGINT", Fn.new {
|
||||
System.print("\nShutting down gracefully...")
|
||||
running = false
|
||||
})
|
||||
|
||||
System.print("Press Ctrl+C to stop")
|
||||
|
||||
while (running) {
|
||||
System.print("Working...")
|
||||
Timer.sleep(1000)
|
||||
}
|
||||
|
||||
System.print("Cleanup complete, exiting.")</code></pre>
|
||||
|
||||
<div class="admonition note">
|
||||
<div class="admonition-title">Note</div>
|
||||
<p>Wren fibers are cooperative, not preemptive. A fiber runs until it explicitly yields, calls an async operation, or completes. Long-running computations should periodically yield to allow other fibers to run.</p>
|
||||
</div>
|
||||
|
||||
<div class="admonition tip">
|
||||
<div class="admonition-title">See Also</div>
|
||||
<p>For more on fibers, see the <a href="../language/fibers.html">Fibers language guide</a> and the <a href="../api/scheduler.html">Scheduler module reference</a>.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="file-operations.html" class="prev">File Operations</a>
|
||||
<a href="error-handling.html" class="next">Error Handling</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user