This commit is contained in:
2026-01-24 23:40:22 +01:00
parent 1a0f7f51a1
commit 8c1a721c4c
105 changed files with 23275 additions and 94 deletions
+421
View File
@@ -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>
+478
View File
@@ -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>
+406
View File
@@ -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>
+334
View File
@@ -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>
+208
View File
@@ -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>
+343
View File
@@ -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>
+337
View File
@@ -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>