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>
|
||||
@@ -0,0 +1,478 @@
|
||||
<!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>Error Handling - 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">Async Operations</a></li>
|
||||
<li><a href="error-handling.html" class="active">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>Error Handling</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Error Handling</h1>
|
||||
|
||||
<p>Wren uses fibers for error handling. The <code>fiber.try()</code> method catches errors without crashing your program.</p>
|
||||
|
||||
<h2>Basic Try/Catch Pattern</h2>
|
||||
<pre><code>var fiber = Fiber.new {
|
||||
Fiber.abort("Something went wrong!")
|
||||
}
|
||||
|
||||
var result = fiber.try()
|
||||
|
||||
if (fiber.error) {
|
||||
System.print("Error: %(fiber.error)")
|
||||
} else {
|
||||
System.print("Result: %(result)")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Throw an Error</h2>
|
||||
<pre><code>Fiber.abort("This is an error message")</code></pre>
|
||||
|
||||
<h2>Catch Specific Error Types</h2>
|
||||
<pre><code>var fiber = Fiber.new {
|
||||
var x = null
|
||||
return x.count // Error: null has no method 'count'
|
||||
}
|
||||
|
||||
var result = fiber.try()
|
||||
|
||||
if (fiber.error) {
|
||||
if (fiber.error.contains("null")) {
|
||||
System.print("Null reference error")
|
||||
} else {
|
||||
System.print("Other error: %(fiber.error)")
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<h2>Safe File Read</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
var safeRead = Fn.new { |path|
|
||||
var fiber = Fiber.new { File.read(path) }
|
||||
var content = fiber.try()
|
||||
|
||||
if (fiber.error) {
|
||||
return null
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
var content = safeRead.call("config.txt")
|
||||
if (content) {
|
||||
System.print(content)
|
||||
} else {
|
||||
System.print("Could not read file")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Safe JSON Parse</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var safeParse = Fn.new { |jsonStr|
|
||||
var fiber = Fiber.new { Json.parse(jsonStr) }
|
||||
var data = fiber.try()
|
||||
|
||||
if (fiber.error) {
|
||||
System.print("Invalid JSON: %(fiber.error)")
|
||||
return null
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
var data = safeParse.call('{"valid": true}') // Works
|
||||
var bad = safeParse.call('not json') // Returns null</code></pre>
|
||||
|
||||
<h2>Safe HTTP Request</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var safeFetch = Fn.new { |url|
|
||||
var fiber = Fiber.new { Http.get(url) }
|
||||
var response = fiber.try()
|
||||
|
||||
if (fiber.error) {
|
||||
return {"error": fiber.error, "ok": false}
|
||||
}
|
||||
|
||||
if (response.statusCode >= 400) {
|
||||
return {"error": "HTTP %(response.statusCode)", "ok": false}
|
||||
}
|
||||
|
||||
return {"data": response.json, "ok": true}
|
||||
}
|
||||
|
||||
var result = safeFetch.call("https://api.example.com/data")
|
||||
if (result["ok"]) {
|
||||
System.print(result["data"])
|
||||
} else {
|
||||
System.print("Error: %(result["error"])")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Input Validation</h2>
|
||||
<pre><code>var validateEmail = Fn.new { |email|
|
||||
if (email == null) {
|
||||
Fiber.abort("Email is required")
|
||||
}
|
||||
if (!email.contains("@")) {
|
||||
Fiber.abort("Invalid email format")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var validate = Fn.new { |email|
|
||||
var fiber = Fiber.new { validateEmail.call(email) }
|
||||
fiber.try()
|
||||
return fiber.error
|
||||
}
|
||||
|
||||
System.print(validate.call(null)) // Email is required
|
||||
System.print(validate.call("invalid")) // Invalid email format
|
||||
System.print(validate.call("a@b.com")) // null (no error)</code></pre>
|
||||
|
||||
<h2>Result Type Pattern</h2>
|
||||
<pre><code>class Result {
|
||||
construct ok(value) {
|
||||
_value = value
|
||||
_error = null
|
||||
}
|
||||
|
||||
construct error(message) {
|
||||
_value = null
|
||||
_error = message
|
||||
}
|
||||
|
||||
isOk { _error == null }
|
||||
isError { _error != null }
|
||||
value { _value }
|
||||
error { _error }
|
||||
|
||||
unwrap {
|
||||
if (isError) Fiber.abort(_error)
|
||||
return _value
|
||||
}
|
||||
|
||||
unwrapOr(default) { isOk ? _value : default }
|
||||
}
|
||||
|
||||
var divide = Fn.new { |a, b|
|
||||
if (b == 0) {
|
||||
return Result.error("Division by zero")
|
||||
}
|
||||
return Result.ok(a / b)
|
||||
}
|
||||
|
||||
var result = divide.call(10, 2)
|
||||
if (result.isOk) {
|
||||
System.print("Result: %(result.value)")
|
||||
}
|
||||
|
||||
var bad = divide.call(10, 0)
|
||||
if (bad.isError) {
|
||||
System.print("Error: %(bad.error)")
|
||||
}
|
||||
|
||||
System.print(divide.call(10, 5).unwrapOr(0)) // 2
|
||||
System.print(divide.call(10, 0).unwrapOr(0)) // 0</code></pre>
|
||||
|
||||
<h2>Assert Function</h2>
|
||||
<pre><code>var assert = Fn.new { |condition, message|
|
||||
if (!condition) {
|
||||
Fiber.abort("Assertion failed: %(message)")
|
||||
}
|
||||
}
|
||||
|
||||
var processUser = Fn.new { |user|
|
||||
assert.call(user != null, "User is required")
|
||||
assert.call(user["name"] != null, "User name is required")
|
||||
assert.call(user["age"] >= 0, "Age must be non-negative")
|
||||
|
||||
System.print("Processing %(user["name"])...")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Multiple Error Sources</h2>
|
||||
<pre><code>import "http" for Http
|
||||
import "json" for Json
|
||||
|
||||
var fetchAndParse = Fn.new { |url|
|
||||
var httpFiber = Fiber.new { Http.get(url) }
|
||||
var response = httpFiber.try()
|
||||
|
||||
if (httpFiber.error) {
|
||||
return {"error": "Network error: %(httpFiber.error)"}
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return {"error": "HTTP error: %(response.statusCode)"}
|
||||
}
|
||||
|
||||
var jsonFiber = Fiber.new { Json.parse(response.body) }
|
||||
var data = jsonFiber.try()
|
||||
|
||||
if (jsonFiber.error) {
|
||||
return {"error": "Parse error: %(jsonFiber.error)"}
|
||||
}
|
||||
|
||||
return {"data": data}
|
||||
}
|
||||
|
||||
var result = fetchAndParse.call("https://api.example.com/data")
|
||||
if (result.containsKey("error")) {
|
||||
System.print(result["error"])
|
||||
} else {
|
||||
System.print(result["data"])
|
||||
}</code></pre>
|
||||
|
||||
<h2>Error Logging</h2>
|
||||
<pre><code>import "datetime" for DateTime
|
||||
import "io" for File
|
||||
|
||||
class Logger {
|
||||
construct new(logFile) {
|
||||
_logFile = logFile
|
||||
}
|
||||
|
||||
log(level, message) {
|
||||
var timestamp = DateTime.now().toString
|
||||
var entry = "[%(timestamp)] [%(level)] %(message)\n"
|
||||
|
||||
var existing = ""
|
||||
var fiber = Fiber.new { File.read(_logFile) }
|
||||
existing = fiber.try() || ""
|
||||
|
||||
File.write(_logFile, existing + entry)
|
||||
|
||||
if (level == "ERROR") {
|
||||
System.print("ERROR: %(message)")
|
||||
}
|
||||
}
|
||||
|
||||
error(message) { log("ERROR", message) }
|
||||
warn(message) { log("WARN", message) }
|
||||
info(message) { log("INFO", message) }
|
||||
}
|
||||
|
||||
var logger = Logger.new("app.log")
|
||||
|
||||
var safeDivide = Fn.new { |a, b|
|
||||
if (b == 0) {
|
||||
logger.error("Division by zero: %(a) / %(b)")
|
||||
return null
|
||||
}
|
||||
return a / b
|
||||
}
|
||||
|
||||
var result = safeDivide.call(10, 0)</code></pre>
|
||||
|
||||
<h2>Cleanup with Finally Pattern</h2>
|
||||
<pre><code>import "sqlite" for Sqlite
|
||||
|
||||
var withDatabase = Fn.new { |dbPath, operation|
|
||||
var db = Sqlite.open(dbPath)
|
||||
var result = null
|
||||
var error = null
|
||||
|
||||
var fiber = Fiber.new { operation.call(db) }
|
||||
result = fiber.try()
|
||||
error = fiber.error
|
||||
|
||||
db.close()
|
||||
|
||||
if (error) {
|
||||
Fiber.abort(error)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
var users = withDatabase.call("app.db", Fn.new { |db|
|
||||
return db.execute("SELECT * FROM users")
|
||||
})
|
||||
|
||||
System.print(users)</code></pre>
|
||||
|
||||
<h2>Custom Error Class</h2>
|
||||
<pre><code>class AppError {
|
||||
construct new(code, message) {
|
||||
_code = code
|
||||
_message = message
|
||||
}
|
||||
|
||||
code { _code }
|
||||
message { _message }
|
||||
toString { "[%(code)] %(message)" }
|
||||
|
||||
static notFound(resource) {
|
||||
return AppError.new("NOT_FOUND", "%(resource) not found")
|
||||
}
|
||||
|
||||
static validation(field, reason) {
|
||||
return AppError.new("VALIDATION", "%(field): %(reason)")
|
||||
}
|
||||
|
||||
static unauthorized() {
|
||||
return AppError.new("UNAUTHORIZED", "Authentication required")
|
||||
}
|
||||
}
|
||||
|
||||
var findUser = Fn.new { |id|
|
||||
if (id == null) {
|
||||
Fiber.abort(AppError.validation("id", "is required").toString)
|
||||
}
|
||||
|
||||
var user = null
|
||||
|
||||
if (user == null) {
|
||||
Fiber.abort(AppError.notFound("User %(id)").toString)
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
var fiber = Fiber.new { findUser.call(null) }
|
||||
fiber.try()
|
||||
System.print(fiber.error) // [VALIDATION] id: is required</code></pre>
|
||||
|
||||
<h2>Retry on Error</h2>
|
||||
<pre><code>import "timer" for Timer
|
||||
|
||||
var retry = Fn.new { |operation, maxAttempts, delayMs|
|
||||
var lastError = null
|
||||
|
||||
for (i in 1..maxAttempts) {
|
||||
var fiber = Fiber.new { operation.call() }
|
||||
var result = fiber.try()
|
||||
|
||||
if (!fiber.error) {
|
||||
return result
|
||||
}
|
||||
|
||||
lastError = fiber.error
|
||||
System.print("Attempt %(i) failed: %(lastError)")
|
||||
|
||||
if (i < maxAttempts) {
|
||||
Timer.sleep(delayMs)
|
||||
}
|
||||
}
|
||||
|
||||
Fiber.abort("All %(maxAttempts) attempts failed. Last error: %(lastError)")
|
||||
}
|
||||
|
||||
var result = retry.call(Fn.new {
|
||||
return "success"
|
||||
}, 3, 1000)</code></pre>
|
||||
|
||||
<div class="admonition tip">
|
||||
<div class="admonition-title">Best Practices</div>
|
||||
<ul>
|
||||
<li>Always wrap external calls (HTTP, file I/O) in fibers</li>
|
||||
<li>Provide meaningful error messages</li>
|
||||
<li>Log errors for debugging</li>
|
||||
<li>Fail fast on programming errors, recover from user errors</li>
|
||||
<li>Clean up resources (close files, connections) even on error</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="admonition note">
|
||||
<div class="admonition-title">See Also</div>
|
||||
<p>For more on fibers, see the <a href="../language/fibers.html">Fibers language guide</a>.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="async-operations.html" class="prev">Async Operations</a>
|
||||
<a href="../index.html" class="next">Home</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,406 @@
|
||||
<!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>File Operations - 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" class="active">File Operations</a></li>
|
||||
<li><a href="async-operations.html">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>File Operations</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>File Operations</h1>
|
||||
|
||||
<h2>Read Entire File</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
var content = File.read("document.txt")
|
||||
System.print(content)</code></pre>
|
||||
|
||||
<h2>Write to File</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
File.write("output.txt", "Hello, World!")
|
||||
System.print("File written!")</code></pre>
|
||||
|
||||
<h2>Append to File</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
var existing = File.exists("log.txt") ? File.read("log.txt") : ""
|
||||
File.write("log.txt", existing + "New line\n")</code></pre>
|
||||
|
||||
<h2>Check if File Exists</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
if (File.exists("config.txt")) {
|
||||
System.print("Config found")
|
||||
var content = File.read("config.txt")
|
||||
} else {
|
||||
System.print("Config not found, using defaults")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Get File Size</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
var size = File.size("data.bin")
|
||||
System.print("File size: %(size) bytes")</code></pre>
|
||||
|
||||
<h2>Copy File</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
File.copy("source.txt", "destination.txt")
|
||||
System.print("File copied!")</code></pre>
|
||||
|
||||
<h2>Rename/Move File</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
File.rename("old_name.txt", "new_name.txt")
|
||||
System.print("File renamed!")
|
||||
|
||||
File.rename("file.txt", "subdir/file.txt")
|
||||
System.print("File moved!")</code></pre>
|
||||
|
||||
<h2>Delete File</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
if (File.exists("temp.txt")) {
|
||||
File.delete("temp.txt")
|
||||
System.print("File deleted!")
|
||||
}</code></pre>
|
||||
|
||||
<h2>List Directory Contents</h2>
|
||||
<pre><code>import "io" for Directory
|
||||
|
||||
var files = Directory.list(".")
|
||||
|
||||
for (file in files) {
|
||||
System.print(file)
|
||||
}</code></pre>
|
||||
|
||||
<h2>Check if Directory Exists</h2>
|
||||
<pre><code>import "io" for Directory
|
||||
|
||||
if (Directory.exists("data")) {
|
||||
System.print("Directory found")
|
||||
} else {
|
||||
System.print("Directory not found")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Create Directory</h2>
|
||||
<pre><code>import "io" for Directory
|
||||
|
||||
if (!Directory.exists("output")) {
|
||||
Directory.create("output")
|
||||
System.print("Directory created!")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Delete Empty Directory</h2>
|
||||
<pre><code>import "io" for Directory
|
||||
|
||||
Directory.delete("empty_folder")
|
||||
System.print("Directory deleted!")</code></pre>
|
||||
|
||||
<h2>Read File Line by Line</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
var content = File.read("data.txt")
|
||||
var lines = content.split("\n")
|
||||
|
||||
for (line in lines) {
|
||||
if (line.count > 0) {
|
||||
System.print(line)
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<h2>Process Files in Directory</h2>
|
||||
<pre><code>import "io" for File, Directory
|
||||
|
||||
var files = Directory.list("./data")
|
||||
|
||||
for (filename in files) {
|
||||
if (filename.endsWith(".txt")) {
|
||||
var path = "./data/%(filename)"
|
||||
var content = File.read(path)
|
||||
System.print("%(filename): %(content.count) chars")
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<h2>Recursive Directory Listing</h2>
|
||||
<pre><code>import "io" for File, Directory
|
||||
|
||||
var listRecursive = Fn.new { |path, indent|
|
||||
var items = Directory.list(path)
|
||||
|
||||
for (item in items) {
|
||||
var fullPath = "%(path)/%(item)"
|
||||
System.print("%(indent)%(item)")
|
||||
|
||||
if (Directory.exists(fullPath)) {
|
||||
listRecursive.call(fullPath, indent + " ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listRecursive.call(".", "")</code></pre>
|
||||
|
||||
<h2>Find Files by Extension</h2>
|
||||
<pre><code>import "io" for File, Directory
|
||||
|
||||
var findByExtension = Fn.new { |path, ext|
|
||||
var results = []
|
||||
var items = Directory.list(path)
|
||||
|
||||
for (item in items) {
|
||||
var fullPath = "%(path)/%(item)"
|
||||
|
||||
if (Directory.exists(fullPath)) {
|
||||
var subResults = findByExtension.call(fullPath, ext)
|
||||
for (r in subResults) results.add(r)
|
||||
} else if (item.endsWith(ext)) {
|
||||
results.add(fullPath)
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
var wrenFiles = findByExtension.call(".", ".wren")
|
||||
for (file in wrenFiles) {
|
||||
System.print(file)
|
||||
}</code></pre>
|
||||
|
||||
<h2>Read JSON Configuration</h2>
|
||||
<pre><code>import "io" for File
|
||||
import "json" for Json
|
||||
|
||||
var loadConfig = Fn.new { |path, defaults|
|
||||
if (!File.exists(path)) {
|
||||
return defaults
|
||||
}
|
||||
|
||||
var content = File.read(path)
|
||||
var config = Json.parse(content)
|
||||
|
||||
for (key in defaults.keys) {
|
||||
if (!config.containsKey(key)) {
|
||||
config[key] = defaults[key]
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
var config = loadConfig.call("config.json", {
|
||||
"port": 8080,
|
||||
"debug": false
|
||||
})
|
||||
|
||||
System.print("Port: %(config["port"])")</code></pre>
|
||||
|
||||
<h2>Save JSON Configuration</h2>
|
||||
<pre><code>import "io" for File
|
||||
import "json" for Json
|
||||
|
||||
var config = {
|
||||
"database": "app.db",
|
||||
"port": 8080,
|
||||
"debug": true
|
||||
}
|
||||
|
||||
File.write("config.json", Json.stringify(config, 2))
|
||||
System.print("Configuration saved!")</code></pre>
|
||||
|
||||
<h2>Create Backup Copy</h2>
|
||||
<pre><code>import "io" for File
|
||||
import "datetime" for DateTime
|
||||
|
||||
var backup = Fn.new { |path|
|
||||
if (!File.exists(path)) {
|
||||
System.print("File not found: %(path)")
|
||||
return null
|
||||
}
|
||||
|
||||
var timestamp = DateTime.now().format("\%Y\%m\%d_\%H\%M\%S")
|
||||
var backupPath = "%(path).%(timestamp).bak"
|
||||
|
||||
File.copy(path, backupPath)
|
||||
System.print("Backup created: %(backupPath)")
|
||||
|
||||
return backupPath
|
||||
}
|
||||
|
||||
backup.call("important.txt")</code></pre>
|
||||
|
||||
<h2>Read User Input</h2>
|
||||
<pre><code>import "io" for Stdin
|
||||
|
||||
System.write("Enter your name: ")
|
||||
var name = Stdin.readLine()
|
||||
|
||||
System.print("Hello, %(name)!")</code></pre>
|
||||
|
||||
<h2>Interactive Menu</h2>
|
||||
<pre><code>import "io" for Stdin
|
||||
|
||||
System.print("Select an option:")
|
||||
System.print("1. Option A")
|
||||
System.print("2. Option B")
|
||||
System.print("3. Exit")
|
||||
|
||||
System.write("Choice: ")
|
||||
var choice = Stdin.readLine()
|
||||
|
||||
if (choice == "1") {
|
||||
System.print("You selected Option A")
|
||||
} else if (choice == "2") {
|
||||
System.print("You selected Option B")
|
||||
} else if (choice == "3") {
|
||||
System.print("Goodbye!")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Safe File Operations with Error Handling</h2>
|
||||
<pre><code>import "io" for File
|
||||
|
||||
var safeRead = Fn.new { |path|
|
||||
var fiber = Fiber.new { File.read(path) }
|
||||
var result = fiber.try()
|
||||
|
||||
if (fiber.error) {
|
||||
System.print("Error reading %(path): %(fiber.error)")
|
||||
return null
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
var content = safeRead.call("maybe_exists.txt")
|
||||
if (content) {
|
||||
System.print("Content: %(content)")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Calculate Directory Size</h2>
|
||||
<pre><code>import "io" for File, Directory
|
||||
|
||||
var dirSize = Fn.new { |path|
|
||||
var total = 0
|
||||
var items = Directory.list(path)
|
||||
|
||||
for (item in items) {
|
||||
var fullPath = "%(path)/%(item)"
|
||||
|
||||
if (Directory.exists(fullPath)) {
|
||||
total = total + dirSize.call(fullPath)
|
||||
} else if (File.exists(fullPath)) {
|
||||
total = total + File.size(fullPath)
|
||||
}
|
||||
}
|
||||
|
||||
return total
|
||||
}
|
||||
|
||||
var size = dirSize.call(".")
|
||||
System.print("Total size: %(size) bytes")</code></pre>
|
||||
|
||||
<div class="admonition tip">
|
||||
<div class="admonition-title">See Also</div>
|
||||
<p>For full API documentation, see the <a href="../api/io.html">IO module reference</a>.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="regex-patterns.html" class="prev">Regex Patterns</a>
|
||||
<a href="async-operations.html" class="next">Async Operations</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,334 @@
|
||||
<!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>Making HTTP Requests - 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" class="active">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">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>HTTP Requests</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Making HTTP Requests</h1>
|
||||
|
||||
<h2>Basic GET Request</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var response = Http.get("https://api.example.com/data")
|
||||
System.print(response.body)</code></pre>
|
||||
|
||||
<h2>GET Request with JSON Response</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var response = Http.get("https://jsonplaceholder.typicode.com/posts/1")
|
||||
var data = response.json
|
||||
|
||||
System.print("Title: %(data["title"])")</code></pre>
|
||||
|
||||
<h2>GET Request with Headers</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var response = Http.get("https://api.example.com/data", {
|
||||
"Accept": "application/json",
|
||||
"User-Agent": "Wren-CLI/1.0"
|
||||
})
|
||||
|
||||
System.print(response.body)</code></pre>
|
||||
|
||||
<h2>POST Request with JSON Body</h2>
|
||||
<pre><code>import "http" for Http
|
||||
import "json" for Json
|
||||
|
||||
var data = {
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com"
|
||||
}
|
||||
|
||||
var response = Http.post(
|
||||
"https://api.example.com/users",
|
||||
Json.stringify(data),
|
||||
{"Content-Type": "application/json"}
|
||||
)
|
||||
|
||||
System.print("Status: %(response.statusCode)")
|
||||
System.print("Created: %(response.json)")</code></pre>
|
||||
|
||||
<h2>PUT Request</h2>
|
||||
<pre><code>import "http" for Http
|
||||
import "json" for Json
|
||||
|
||||
var data = {
|
||||
"id": 1,
|
||||
"name": "Jane Doe",
|
||||
"email": "jane@example.com"
|
||||
}
|
||||
|
||||
var response = Http.put(
|
||||
"https://api.example.com/users/1",
|
||||
Json.stringify(data),
|
||||
{"Content-Type": "application/json"}
|
||||
)
|
||||
|
||||
System.print("Updated: %(response.statusCode == 200)")</code></pre>
|
||||
|
||||
<h2>DELETE Request</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var response = Http.delete("https://api.example.com/users/1")
|
||||
System.print("Deleted: %(response.statusCode == 204)")</code></pre>
|
||||
|
||||
<h2>PATCH Request</h2>
|
||||
<pre><code>import "http" for Http
|
||||
import "json" for Json
|
||||
|
||||
var response = Http.patch(
|
||||
"https://api.example.com/users/1",
|
||||
Json.stringify({"email": "newemail@example.com"}),
|
||||
{"Content-Type": "application/json"}
|
||||
)
|
||||
|
||||
System.print("Patched: %(response.statusCode)")</code></pre>
|
||||
|
||||
<h2>Bearer Token Authentication</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var token = "your-api-token"
|
||||
|
||||
var response = Http.get("https://api.example.com/protected", {
|
||||
"Authorization": "Bearer %(token)"
|
||||
})
|
||||
|
||||
System.print(response.json)</code></pre>
|
||||
|
||||
<h2>Basic Authentication</h2>
|
||||
<pre><code>import "http" for Http
|
||||
import "base64" for Base64
|
||||
|
||||
var username = "user"
|
||||
var password = "pass"
|
||||
var credentials = Base64.encode("%(username):%(password)")
|
||||
|
||||
var response = Http.get("https://api.example.com/protected", {
|
||||
"Authorization": "Basic %(credentials)"
|
||||
})
|
||||
|
||||
System.print(response.body)</code></pre>
|
||||
|
||||
<h2>API Key Authentication</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var response = Http.get("https://api.example.com/data", {
|
||||
"X-API-Key": "your-api-key"
|
||||
})
|
||||
|
||||
System.print(response.body)</code></pre>
|
||||
|
||||
<h2>Check Response Status</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var response = Http.get("https://api.example.com/data")
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
System.print("Success: %(response.json)")
|
||||
} else if (response.statusCode == 404) {
|
||||
System.print("Not found")
|
||||
} else if (response.statusCode >= 500) {
|
||||
System.print("Server error: %(response.statusCode)")
|
||||
} else {
|
||||
System.print("Error: %(response.statusCode)")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Access Response Headers</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var response = Http.get("https://api.example.com/data")
|
||||
|
||||
System.print("Content-Type: %(response.headers["content-type"])")
|
||||
System.print("All headers: %(response.headers)")</code></pre>
|
||||
|
||||
<h2>URL Query Parameters</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var response = Http.get("https://api.example.com/search?q=wren&limit=10")
|
||||
|
||||
System.print(response.json)</code></pre>
|
||||
|
||||
<h2>Form URL Encoded POST</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var body = "username=john&password=secret"
|
||||
|
||||
var response = Http.post(
|
||||
"https://api.example.com/login",
|
||||
body,
|
||||
{"Content-Type": "application/x-www-form-urlencoded"}
|
||||
)
|
||||
|
||||
System.print(response.json)</code></pre>
|
||||
|
||||
<h2>Download File</h2>
|
||||
<pre><code>import "http" for Http
|
||||
import "io" for File
|
||||
|
||||
var response = Http.get("https://example.com/file.txt")
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
File.write("downloaded.txt", response.body)
|
||||
System.print("File downloaded!")
|
||||
}</code></pre>
|
||||
|
||||
<h2>HTTPS Request</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var response = Http.get("https://secure.example.com/api")
|
||||
System.print(response.body)</code></pre>
|
||||
|
||||
<h2>Error Handling</h2>
|
||||
<pre><code>import "http" for Http
|
||||
|
||||
var fiber = Fiber.new {
|
||||
return Http.get("https://api.example.com/data")
|
||||
}
|
||||
|
||||
var response = fiber.try()
|
||||
|
||||
if (fiber.error) {
|
||||
System.print("Request failed: %(fiber.error)")
|
||||
} else if (response.statusCode >= 400) {
|
||||
System.print("HTTP error: %(response.statusCode)")
|
||||
} else {
|
||||
System.print("Success: %(response.json)")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Retry on Failure</h2>
|
||||
<pre><code>import "http" for Http
|
||||
import "timer" for Timer
|
||||
|
||||
var fetchWithRetry = Fn.new { |url, maxRetries|
|
||||
var attempt = 0
|
||||
while (attempt < maxRetries) {
|
||||
var fiber = Fiber.new { Http.get(url) }
|
||||
var response = fiber.try()
|
||||
|
||||
if (!fiber.error && response.statusCode == 200) {
|
||||
return response
|
||||
}
|
||||
|
||||
attempt = attempt + 1
|
||||
if (attempt < maxRetries) {
|
||||
Timer.sleep(1000 * attempt)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
var response = fetchWithRetry.call("https://api.example.com/data", 3)
|
||||
if (response) {
|
||||
System.print(response.json)
|
||||
} else {
|
||||
System.print("Failed after 3 retries")
|
||||
}</code></pre>
|
||||
|
||||
<div class="admonition tip">
|
||||
<div class="admonition-title">See Also</div>
|
||||
<p>For a complete API client example, see the <a href="../tutorials/http-client.html">HTTP Client Tutorial</a>. For full API documentation, see the <a href="../api/http.html">HTTP module reference</a>.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="index.html" class="prev">How-To List</a>
|
||||
<a href="json-parsing.html" class="next">JSON Parsing</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,208 @@
|
||||
<!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>How-To Guides - 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" class="active">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">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>
|
||||
<span>How-To Guides</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>How-To Guides</h1>
|
||||
|
||||
<p>Quick, focused guides that show you how to accomplish specific tasks. Each guide provides working code examples you can copy and adapt for your projects.</p>
|
||||
|
||||
<div class="card-grid">
|
||||
<div class="card">
|
||||
<h3><a href="http-requests.html">Making HTTP Requests</a></h3>
|
||||
<p>GET, POST, PUT, DELETE requests with headers, authentication, and error handling.</p>
|
||||
<div class="card-meta">
|
||||
<span class="tag">http</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3><a href="json-parsing.html">Working with JSON</a></h3>
|
||||
<p>Parse JSON strings, access nested data, create JSON output, and handle errors.</p>
|
||||
<div class="card-meta">
|
||||
<span class="tag">json</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3><a href="regex-patterns.html">Using Regular Expressions</a></h3>
|
||||
<p>Match, search, replace, and split text with regex patterns.</p>
|
||||
<div class="card-meta">
|
||||
<span class="tag">regex</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3><a href="file-operations.html">File Operations</a></h3>
|
||||
<p>Read, write, copy, and delete files. Work with directories and paths.</p>
|
||||
<div class="card-meta">
|
||||
<span class="tag">io</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3><a href="async-operations.html">Async Programming</a></h3>
|
||||
<p>Use fibers for concurrent operations, parallel requests, and timeouts.</p>
|
||||
<div class="card-meta">
|
||||
<span class="tag">fibers</span>
|
||||
<span class="tag">scheduler</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3><a href="error-handling.html">Error Handling</a></h3>
|
||||
<p>Catch errors with fibers, validate input, and handle edge cases gracefully.</p>
|
||||
<div class="card-meta">
|
||||
<span class="tag">fibers</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>How-To vs Tutorials</h2>
|
||||
|
||||
<p><strong>Tutorials</strong> are learning-oriented. They walk you through building complete applications step by step, introducing concepts gradually.</p>
|
||||
|
||||
<p><strong>How-To Guides</strong> are goal-oriented. They assume you know the basics and need to accomplish a specific task quickly. Each guide focuses on one topic with copy-paste examples.</p>
|
||||
|
||||
<h2>Quick Reference</h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Task</th>
|
||||
<th>Guide</th>
|
||||
<th>Key Functions</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Fetch data from API</td>
|
||||
<td><a href="http-requests.html">HTTP Requests</a></td>
|
||||
<td><code>Http.get()</code>, <code>response.json</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Parse JSON string</td>
|
||||
<td><a href="json-parsing.html">JSON Parsing</a></td>
|
||||
<td><code>Json.parse()</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Validate email format</td>
|
||||
<td><a href="regex-patterns.html">Regex Patterns</a></td>
|
||||
<td><code>Regex.new().test()</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Read file contents</td>
|
||||
<td><a href="file-operations.html">File Operations</a></td>
|
||||
<td><code>File.read()</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Run tasks in parallel</td>
|
||||
<td><a href="async-operations.html">Async Operations</a></td>
|
||||
<td><code>Fiber.new { }</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Handle runtime errors</td>
|
||||
<td><a href="error-handling.html">Error Handling</a></td>
|
||||
<td><code>fiber.try()</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="../tutorials/cli-tool.html" class="prev">CLI Tool</a>
|
||||
<a href="http-requests.html" class="next">HTTP Requests</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,343 @@
|
||||
<!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>Working with JSON - 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" class="active">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">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>JSON Parsing</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Working with JSON</h1>
|
||||
|
||||
<h2>Parse JSON String</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var jsonStr = '{"name": "Alice", "age": 30}'
|
||||
var data = Json.parse(jsonStr)
|
||||
|
||||
System.print(data["name"]) // Alice
|
||||
System.print(data["age"]) // 30</code></pre>
|
||||
|
||||
<h2>Parse JSON Array</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var jsonStr = '[1, 2, 3, "four", true, null]'
|
||||
var items = Json.parse(jsonStr)
|
||||
|
||||
for (item in items) {
|
||||
System.print(item)
|
||||
}</code></pre>
|
||||
|
||||
<h2>Access Nested Objects</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var jsonStr = '{"user": {"name": "Bob", "address": {"city": "NYC"}}}'
|
||||
var data = Json.parse(jsonStr)
|
||||
|
||||
System.print(data["user"]["name"]) // Bob
|
||||
System.print(data["user"]["address"]["city"]) // NYC</code></pre>
|
||||
|
||||
<h2>Convert Wren Object to JSON</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var data = {
|
||||
"name": "Charlie",
|
||||
"age": 25,
|
||||
"active": true
|
||||
}
|
||||
|
||||
var jsonStr = Json.stringify(data)
|
||||
System.print(jsonStr) // {"name":"Charlie","age":25,"active":true}</code></pre>
|
||||
|
||||
<h2>Pretty Print JSON</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var data = {
|
||||
"users": [
|
||||
{"name": "Alice", "age": 30},
|
||||
{"name": "Bob", "age": 25}
|
||||
]
|
||||
}
|
||||
|
||||
var pretty = Json.stringify(data, 2)
|
||||
System.print(pretty)</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
<pre><code>{
|
||||
"users": [
|
||||
{
|
||||
"name": "Alice",
|
||||
"age": 30
|
||||
},
|
||||
{
|
||||
"name": "Bob",
|
||||
"age": 25
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
|
||||
<h2>Check if Key Exists</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var data = Json.parse('{"name": "Alice"}')
|
||||
|
||||
if (data.containsKey("name")) {
|
||||
System.print("Name: %(data["name"])")
|
||||
}
|
||||
|
||||
if (!data.containsKey("age")) {
|
||||
System.print("Age not specified")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Provide Default Values</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var data = Json.parse('{"name": "Alice"}')
|
||||
|
||||
var name = data["name"]
|
||||
var age = data.containsKey("age") ? data["age"] : 0
|
||||
var city = data.containsKey("city") ? data["city"] : "Unknown"
|
||||
|
||||
System.print("%(name), %(age), %(city)")</code></pre>
|
||||
|
||||
<h2>Iterate Over Object Keys</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var data = Json.parse('{"a": 1, "b": 2, "c": 3}')
|
||||
|
||||
for (key in data.keys) {
|
||||
System.print("%(key): %(data[key])")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Iterate Over Array</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var users = Json.parse('[{"name": "Alice"}, {"name": "Bob"}]')
|
||||
|
||||
for (i in 0...users.count) {
|
||||
System.print("%(i + 1). %(users[i]["name"])")
|
||||
}</code></pre>
|
||||
|
||||
<h2>Modify JSON Data</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var data = Json.parse('{"name": "Alice", "age": 30}')
|
||||
|
||||
data["age"] = 31
|
||||
data["email"] = "alice@example.com"
|
||||
data.remove("name")
|
||||
|
||||
System.print(Json.stringify(data))</code></pre>
|
||||
|
||||
<h2>Parse JSON from File</h2>
|
||||
<pre><code>import "json" for Json
|
||||
import "io" for File
|
||||
|
||||
var content = File.read("config.json")
|
||||
var config = Json.parse(content)
|
||||
|
||||
System.print(config["setting"])</code></pre>
|
||||
|
||||
<h2>Write JSON to File</h2>
|
||||
<pre><code>import "json" for Json
|
||||
import "io" for File
|
||||
|
||||
var data = {
|
||||
"database": "myapp.db",
|
||||
"port": 8080,
|
||||
"debug": true
|
||||
}
|
||||
|
||||
File.write("config.json", Json.stringify(data, 2))</code></pre>
|
||||
|
||||
<h2>Handle Parse Errors</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var jsonStr = "invalid json {"
|
||||
|
||||
var fiber = Fiber.new { Json.parse(jsonStr) }
|
||||
var result = fiber.try()
|
||||
|
||||
if (fiber.error) {
|
||||
System.print("Parse error: %(fiber.error)")
|
||||
} else {
|
||||
System.print(result)
|
||||
}</code></pre>
|
||||
|
||||
<h2>Work with Null Values</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var data = Json.parse('{"name": "Alice", "address": null}')
|
||||
|
||||
if (data["address"] == null) {
|
||||
System.print("No address provided")
|
||||
}
|
||||
|
||||
var output = {"value": null}
|
||||
System.print(Json.stringify(output)) // {"value":null}</code></pre>
|
||||
|
||||
<h2>Build JSON Array Dynamically</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var users = []
|
||||
|
||||
users.add({"name": "Alice", "role": "admin"})
|
||||
users.add({"name": "Bob", "role": "user"})
|
||||
users.add({"name": "Charlie", "role": "user"})
|
||||
|
||||
System.print(Json.stringify(users, 2))</code></pre>
|
||||
|
||||
<h2>Filter JSON Array</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var users = Json.parse('[
|
||||
{"name": "Alice", "age": 30},
|
||||
{"name": "Bob", "age": 17},
|
||||
{"name": "Charlie", "age": 25}
|
||||
]')
|
||||
|
||||
var adults = []
|
||||
for (user in users) {
|
||||
if (user["age"] >= 18) {
|
||||
adults.add(user)
|
||||
}
|
||||
}
|
||||
|
||||
System.print("Adults: %(Json.stringify(adults))")</code></pre>
|
||||
|
||||
<h2>Transform JSON Data</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var users = Json.parse('[
|
||||
{"firstName": "Alice", "lastName": "Smith"},
|
||||
{"firstName": "Bob", "lastName": "Jones"}
|
||||
]')
|
||||
|
||||
var names = []
|
||||
for (user in users) {
|
||||
names.add("%(user["firstName"]) %(user["lastName"])")
|
||||
}
|
||||
|
||||
System.print(names.join(", "))</code></pre>
|
||||
|
||||
<h2>Merge JSON Objects</h2>
|
||||
<pre><code>import "json" for Json
|
||||
|
||||
var defaults = {"theme": "light", "language": "en", "timeout": 30}
|
||||
var userPrefs = {"theme": "dark"}
|
||||
|
||||
var config = {}
|
||||
for (key in defaults.keys) {
|
||||
config[key] = defaults[key]
|
||||
}
|
||||
for (key in userPrefs.keys) {
|
||||
config[key] = userPrefs[key]
|
||||
}
|
||||
|
||||
System.print(Json.stringify(config, 2))</code></pre>
|
||||
|
||||
<div class="admonition tip">
|
||||
<div class="admonition-title">See Also</div>
|
||||
<p>For full API documentation, see the <a href="../api/json.html">JSON module reference</a>.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="http-requests.html" class="prev">HTTP Requests</a>
|
||||
<a href="regex-patterns.html" class="next">Regex Patterns</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,337 @@
|
||||
<!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>Using Regular Expressions - 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" class="active">Regex Patterns</a></li>
|
||||
<li><a href="file-operations.html">File Operations</a></li>
|
||||
<li><a href="async-operations.html">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>Regex Patterns</span>
|
||||
</nav>
|
||||
|
||||
<article>
|
||||
<h1>Using Regular Expressions</h1>
|
||||
|
||||
<h2>Test if String Matches Pattern</h2>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var pattern = Regex.new("^hello")
|
||||
|
||||
System.print(pattern.test("hello world")) // true
|
||||
System.print(pattern.test("say hello")) // false</code></pre>
|
||||
|
||||
<h2>Find First Match</h2>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var pattern = Regex.new("\\d+")
|
||||
var match = pattern.match("Order 12345 shipped")
|
||||
|
||||
if (match) {
|
||||
System.print(match.text) // 12345
|
||||
System.print(match.start) // 6
|
||||
System.print(match.end) // 11
|
||||
}</code></pre>
|
||||
|
||||
<h2>Find All Matches</h2>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var pattern = Regex.new("\\d+")
|
||||
var matches = pattern.matchAll("Items: 10, 20, 30")
|
||||
|
||||
for (match in matches) {
|
||||
System.print(match.text)
|
||||
}
|
||||
// 10
|
||||
// 20
|
||||
// 30</code></pre>
|
||||
|
||||
<h2>Capture Groups</h2>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var pattern = Regex.new("(\\w+)@(\\w+\\.\\w+)")
|
||||
var match = pattern.match("Contact: alice@example.com")
|
||||
|
||||
if (match) {
|
||||
System.print(match.group(0)) // alice@example.com
|
||||
System.print(match.group(1)) // alice
|
||||
System.print(match.group(2)) // example.com
|
||||
}</code></pre>
|
||||
|
||||
<h2>Replace Matches</h2>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var pattern = Regex.new("\\bcat\\b")
|
||||
var result = pattern.replace("The cat sat on the cat mat", "dog")
|
||||
|
||||
System.print(result) // The dog sat on the dog mat</code></pre>
|
||||
|
||||
<h2>Replace with Callback</h2>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var pattern = Regex.new("\\d+")
|
||||
var result = pattern.replace("a1b2c3", Fn.new { |match|
|
||||
return "[%(match.text)]"
|
||||
})
|
||||
|
||||
System.print(result) // a[1]b[2]c[3]</code></pre>
|
||||
|
||||
<h2>Split String</h2>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var pattern = Regex.new("[,;\\s]+")
|
||||
var parts = pattern.split("apple, banana; cherry date")
|
||||
|
||||
for (part in parts) {
|
||||
System.print(part)
|
||||
}
|
||||
// apple
|
||||
// banana
|
||||
// cherry
|
||||
// date</code></pre>
|
||||
|
||||
<h2>Case Insensitive Matching</h2>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var pattern = Regex.new("hello", "i")
|
||||
|
||||
System.print(pattern.test("Hello World")) // true
|
||||
System.print(pattern.test("HELLO")) // true</code></pre>
|
||||
|
||||
<h2>Multiline Matching</h2>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var text = "Line 1\nLine 2\nLine 3"
|
||||
var pattern = Regex.new("^Line", "m")
|
||||
|
||||
var matches = pattern.matchAll(text)
|
||||
System.print(matches.count) // 3</code></pre>
|
||||
|
||||
<h2>Common Patterns</h2>
|
||||
|
||||
<h3>Validate Email</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var emailPattern = Regex.new("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")
|
||||
|
||||
System.print(emailPattern.test("user@example.com")) // true
|
||||
System.print(emailPattern.test("invalid-email")) // false</code></pre>
|
||||
|
||||
<h3>Validate URL</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var urlPattern = Regex.new("^https?://[a-zA-Z0-9.-]+(/.*)?$")
|
||||
|
||||
System.print(urlPattern.test("https://example.com")) // true
|
||||
System.print(urlPattern.test("http://example.com/path")) // true
|
||||
System.print(urlPattern.test("ftp://invalid")) // false</code></pre>
|
||||
|
||||
<h3>Validate Phone Number</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var phonePattern = Regex.new("^\\+?\\d{1,3}[-.\\s]?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}$")
|
||||
|
||||
System.print(phonePattern.test("+1-555-123-4567")) // true
|
||||
System.print(phonePattern.test("(555) 123-4567")) // true</code></pre>
|
||||
|
||||
<h3>Extract Numbers</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var numberPattern = Regex.new("-?\\d+\\.?\\d*")
|
||||
var text = "Temperature: -5.5 to 32.0 degrees"
|
||||
|
||||
var matches = numberPattern.matchAll(text)
|
||||
for (match in matches) {
|
||||
System.print(match.text)
|
||||
}
|
||||
// -5.5
|
||||
// 32.0</code></pre>
|
||||
|
||||
<h3>Extract Hashtags</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var hashtagPattern = Regex.new("#\\w+")
|
||||
var text = "Check out #wren and #programming!"
|
||||
|
||||
var matches = hashtagPattern.matchAll(text)
|
||||
for (match in matches) {
|
||||
System.print(match.text)
|
||||
}
|
||||
// #wren
|
||||
// #programming</code></pre>
|
||||
|
||||
<h3>Remove HTML Tags</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var tagPattern = Regex.new("<[^>]+>")
|
||||
var html = "<p>Hello <b>World</b>!</p>"
|
||||
|
||||
var text = tagPattern.replace(html, "")
|
||||
System.print(text) // Hello World!</code></pre>
|
||||
|
||||
<h3>Validate Password Strength</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var hasUpper = Regex.new("[A-Z]")
|
||||
var hasLower = Regex.new("[a-z]")
|
||||
var hasDigit = Regex.new("\\d")
|
||||
var hasSpecial = Regex.new("[!@#$%^&*]")
|
||||
var minLength = 8
|
||||
|
||||
var validatePassword = Fn.new { |password|
|
||||
if (password.count < minLength) return false
|
||||
if (!hasUpper.test(password)) return false
|
||||
if (!hasLower.test(password)) return false
|
||||
if (!hasDigit.test(password)) return false
|
||||
if (!hasSpecial.test(password)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
System.print(validatePassword.call("Weak")) // false
|
||||
System.print(validatePassword.call("Strong@Pass1")) // true</code></pre>
|
||||
|
||||
<h3>Parse Log Lines</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var logPattern = Regex.new("\\[(\\d{4}-\\d{2}-\\d{2})\\]\\s+(\\w+):\\s+(.+)")
|
||||
|
||||
var line = "[2024-01-15] ERROR: Connection failed"
|
||||
var match = logPattern.match(line)
|
||||
|
||||
if (match) {
|
||||
System.print("Date: %(match.group(1))") // 2024-01-15
|
||||
System.print("Level: %(match.group(2))") // ERROR
|
||||
System.print("Message: %(match.group(3))") // Connection failed
|
||||
}</code></pre>
|
||||
|
||||
<h3>Validate IP Address</h3>
|
||||
<pre><code>import "regex" for Regex
|
||||
|
||||
var ipPattern = Regex.new("^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$")
|
||||
|
||||
System.print(ipPattern.test("192.168.1.1")) // true
|
||||
System.print(ipPattern.test("256.1.1.1")) // false
|
||||
System.print(ipPattern.test("10.0.0.255")) // true</code></pre>
|
||||
|
||||
<h2>Pattern Syntax Quick Reference</h2>
|
||||
|
||||
<table>
|
||||
<tr><th>Pattern</th><th>Description</th></tr>
|
||||
<tr><td><code>.</code></td><td>Any character except newline</td></tr>
|
||||
<tr><td><code>\\d</code></td><td>Digit (0-9)</td></tr>
|
||||
<tr><td><code>\\w</code></td><td>Word character (a-z, A-Z, 0-9, _)</td></tr>
|
||||
<tr><td><code>\\s</code></td><td>Whitespace</td></tr>
|
||||
<tr><td><code>^</code></td><td>Start of string/line</td></tr>
|
||||
<tr><td><code>$</code></td><td>End of string/line</td></tr>
|
||||
<tr><td><code>*</code></td><td>Zero or more</td></tr>
|
||||
<tr><td><code>+</code></td><td>One or more</td></tr>
|
||||
<tr><td><code>?</code></td><td>Zero or one</td></tr>
|
||||
<tr><td><code>{n,m}</code></td><td>Between n and m times</td></tr>
|
||||
<tr><td><code>[abc]</code></td><td>Character class</td></tr>
|
||||
<tr><td><code>[^abc]</code></td><td>Negated character class</td></tr>
|
||||
<tr><td><code>(group)</code></td><td>Capture group</td></tr>
|
||||
<tr><td><code>a|b</code></td><td>Alternation (a or b)</td></tr>
|
||||
<tr><td><code>\\b</code></td><td>Word boundary</td></tr>
|
||||
</table>
|
||||
|
||||
<div class="admonition tip">
|
||||
<div class="admonition-title">See Also</div>
|
||||
<p>For full API documentation, see the <a href="../api/regex.html">Regex module reference</a>.</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<footer class="page-footer">
|
||||
<a href="json-parsing.html" class="prev">JSON Parsing</a>
|
||||
<a href="file-operations.html" class="next">File Operations</a>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
<script src="../js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user