Files
wren/manual/language/modules.html
T
retoor 5a4054ec66 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.
2026-01-24 22:40:22 +00:00

398 lines
16 KiB
HTML

<!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>Modules - 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="index.html">Syntax Overview</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="methods.html">Methods</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="fibers.html">Fibers</a></li>
<li><a href="modules.html" class="active">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">Templates</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="../howto/index.html">How-To List</a></li>
<li><a href="../howto/http-requests.html">HTTP Requests</a></li>
<li><a href="../howto/json-parsing.html">JSON Parsing</a></li>
<li><a href="../howto/regex-patterns.html">Regex Patterns</a></li>
<li><a href="../howto/file-operations.html">File Operations</a></li>
<li><a href="../howto/async-operations.html">Async Operations</a></li>
<li><a href="../howto/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">Language</a>
<span class="separator">/</span>
<span>Modules</span>
</nav>
<article>
<h1>Modules</h1>
<p>Modules organize code into separate, reusable files. Wren-CLI provides built-in modules and supports user-defined modules.</p>
<h2>Importing</h2>
<p>Use <code>import</code> to load a module and access its classes:</p>
<pre><code>import "json" for Json
var data = Json.parse('{"name": "Wren"}')
System.print(data["name"])</code></pre>
<h3>Multiple Imports</h3>
<p>Import multiple classes from one module:</p>
<pre><code>import "io" for File, Directory, Stdin</code></pre>
<h3>Import All</h3>
<p>Some modules export many classes. Import what you need:</p>
<pre><code>import "os" for Process, Platform</code></pre>
<h2>Built-in Modules</h2>
<p>Wren-CLI provides these modules:</p>
<table>
<tr>
<th>Module</th>
<th>Description</th>
<th>Main Classes</th>
</tr>
<tr>
<td><a href="../api/http.html">http</a></td>
<td>HTTP client</td>
<td>Http, HttpResponse, Url</td>
</tr>
<tr>
<td><a href="../api/websocket.html">websocket</a></td>
<td>WebSocket client/server</td>
<td>WebSocket, WebSocketServer</td>
</tr>
<tr>
<td><a href="../api/tls.html">tls</a></td>
<td>TLS/SSL sockets</td>
<td>TlsSocket</td>
</tr>
<tr>
<td><a href="../api/net.html">net</a></td>
<td>TCP networking</td>
<td>Socket, Server</td>
</tr>
<tr>
<td><a href="../api/dns.html">dns</a></td>
<td>DNS resolution</td>
<td>Dns</td>
</tr>
<tr>
<td><a href="../api/json.html">json</a></td>
<td>JSON parsing</td>
<td>Json</td>
</tr>
<tr>
<td><a href="../api/base64.html">base64</a></td>
<td>Base64 encoding</td>
<td>Base64</td>
</tr>
<tr>
<td><a href="../api/regex.html">regex</a></td>
<td>Regular expressions</td>
<td>Regex, Match</td>
</tr>
<tr>
<td><a href="../api/jinja.html">jinja</a></td>
<td>Template engine</td>
<td>Environment, Template</td>
</tr>
<tr>
<td><a href="../api/crypto.html">crypto</a></td>
<td>Cryptography</td>
<td>Hash</td>
</tr>
<tr>
<td><a href="../api/os.html">os</a></td>
<td>OS information</td>
<td>Process, Platform</td>
</tr>
<tr>
<td><a href="../api/env.html">env</a></td>
<td>Environment variables</td>
<td>Env</td>
</tr>
<tr>
<td><a href="../api/signal.html">signal</a></td>
<td>Unix signals</td>
<td>Signal</td>
</tr>
<tr>
<td><a href="../api/subprocess.html">subprocess</a></td>
<td>Run processes</td>
<td>Subprocess</td>
</tr>
<tr>
<td><a href="../api/sqlite.html">sqlite</a></td>
<td>SQLite database</td>
<td>Sqlite</td>
</tr>
<tr>
<td><a href="../api/datetime.html">datetime</a></td>
<td>Date/time handling</td>
<td>DateTime, Duration</td>
</tr>
<tr>
<td><a href="../api/timer.html">timer</a></td>
<td>Timers and delays</td>
<td>Timer</td>
</tr>
<tr>
<td><a href="../api/io.html">io</a></td>
<td>File I/O</td>
<td>File, Directory, Stdin</td>
</tr>
<tr>
<td><a href="../api/scheduler.html">scheduler</a></td>
<td>Async scheduling</td>
<td>Scheduler</td>
</tr>
<tr>
<td><a href="../api/math.html">math</a></td>
<td>Math functions</td>
<td>Math</td>
</tr>
</table>
<h2>User Modules</h2>
<p>Create your own modules by putting code in <code>.wren</code> files.</p>
<h3>Creating a Module</h3>
<p>Create <code>utils.wren</code>:</p>
<pre><code>class StringUtils {
static reverse(s) {
var result = ""
for (i in (s.count - 1)..0) {
result = result + s[i]
}
return result
}
static capitalize(s) {
if (s.count == 0) return s
return s[0].toString.toUpperCase + s[1..-1]
}
}
class MathUtils {
static clamp(value, min, max) {
if (value &lt; min) return min
if (value > max) return max
return value
}
}</code></pre>
<h3>Using a Module</h3>
<p>Import with a relative path:</p>
<pre><code>import "./utils" for StringUtils, MathUtils
System.print(StringUtils.reverse("hello")) // olleh
System.print(StringUtils.capitalize("world")) // World
System.print(MathUtils.clamp(15, 0, 10)) // 10</code></pre>
<h2>Module Resolution</h2>
<h3>Built-in Modules</h3>
<p>Names without paths are built-in modules:</p>
<pre><code>import "json" for Json // Built-in
import "http" for Http // Built-in</code></pre>
<h3>Relative Paths</h3>
<p>Paths starting with <code>./</code> or <code>../</code> are relative to the current file:</p>
<pre><code>import "./helpers" for Helper // Same directory
import "../utils/string" for StringUtil // Parent directory</code></pre>
<h3>Absolute Paths</h3>
<p>Paths starting with <code>/</code> are absolute:</p>
<pre><code>import "/home/user/libs/mylib" for MyClass</code></pre>
<h2>Module Structure</h2>
<p>A typical project structure:</p>
<pre><code>project/
├── main.wren
├── lib/
│ ├── http_client.wren
│ ├── database.wren
│ └── templates.wren
└── tests/
└── test_http.wren</code></pre>
<p>In <code>main.wren</code>:</p>
<pre><code>import "./lib/http_client" for HttpClient
import "./lib/database" for Database
import "./lib/templates" for TemplateEngine
var client = HttpClient.new()
var db = Database.new("data.db")
var tmpl = TemplateEngine.new()</code></pre>
<h2>Module Top-Level Code</h2>
<p>Code outside classes runs when the module is first imported:</p>
<pre><code>// config.wren
System.print("Config module loading...")
class Config {
static port { 8080 }
static host { "localhost" }
}
System.print("Config ready")</code></pre>
<pre><code>// main.wren
System.print("Before import")
import "./config" for Config
System.print("After import")
System.print("Port: %(Config.port)")
// Output:
// Before import
// Config module loading...
// Config ready
// After import
// Port: 8080</code></pre>
<h2>Module Variables</h2>
<p>Top-level variables are module-private by default:</p>
<pre><code>// counter.wren
var _count = 0 // Private to module
class Counter {
static increment() { _count = _count + 1 }
static count { _count }
}</code></pre>
<pre><code>// main.wren
import "./counter" for Counter
Counter.increment()
Counter.increment()
System.print(Counter.count) // 2
// _count is not accessible here</code></pre>
<h2>Circular Imports</h2>
<p>Wren handles circular imports by completing partial modules:</p>
<pre><code>// a.wren
import "./b" for B
class A {
static greet() { "Hello from A" }
static callB() { B.greet() }
}
// b.wren
import "./a" for A
class B {
static greet() { "Hello from B" }
static callA() { A.greet() }
}</code></pre>
<p>This works because class definitions are hoisted.</p>
<div class="admonition warning">
<div class="admonition-title">Warning</div>
<p>Avoid calling imported classes in top-level code during circular imports, as they may not be fully initialized.</p>
</div>
<h2>Re-exporting</h2>
<p>Create a facade module that re-exports from multiple modules:</p>
<pre><code>// lib/index.wren
import "./http_client" for HttpClient
import "./database" for Database
import "./templates" for TemplateEngine
class Lib {
static httpClient { HttpClient }
static database { Database }
static templates { TemplateEngine }
}</code></pre>
<pre><code>// main.wren
import "./lib/index" for Lib
var client = Lib.httpClient.new()</code></pre>
</article>
<footer class="page-footer">
<a href="fibers.html" class="prev">Fibers</a>
<a href="../api/index.html" class="next">API Reference</a>
</footer>
</main>
</div>
<script src="../js/main.js"></script>
</body>
</html>