Refactor the entire running scripts & writing scripts sections

This commit is contained in:
Filip Tibell 2023-07-23 15:45:28 +02:00
parent a09bbfd363
commit c611bb3274
No known key found for this signature in database
15 changed files with 771 additions and 323 deletions

View file

@ -38,6 +38,6 @@ when installing here.
Congratulations! You've installed Lune and are now ready to write your first script. Congratulations! You've installed Lune and are now ready to write your first script.
- If you want to write standalone scripts, head over to the - If you want to write standalone scripts, head over to the
[Writing Scripts](./1-writing-scripts.md) page. [Introduction](./2-introduction/1-hello-lune.md) section.
- If you want to write Lune scripts specifically for Roblox, check out the - If you want to write Lune scripts specifically for Roblox, check out the
[Roblox](../roblox/1-introduction.md) section. [Roblox](../roblox/1-introduction.md) section.

View file

@ -0,0 +1,24 @@
<!-- markdownlint-disable MD033 -->
<!-- markdownlint-disable MD026 -->
# Hello, Lune!
Congratulations! Lune is now set up and you are ready to start writing scripts 🎉
If you've already written some kind of Lua (or Luau) script before, the examples provided in the
overview below should make you feel right at home. They are organized in order of least complex to
most complex, and you don't really have to read them all to understand how Lune works, though it may
help you out. Good luck!
## Overview
- `1` [Hello, Lune!](./1-hello-lune.md) (you are here)
- `2` [Built-in Libraries](./2-built-in-libraries.md)
- `3` [Standard I/O](./3-standard-io.mdx)
- `4` [Script Arguments](./4-script-arguments.md)
- `5` [Network Requests](./5-network-requests.mdx)
- `6` [Files & Directories](./6-files-and-directories.mdx)
- `7` [Environment Variables](./7-environment-variables.md)
- `8` [Modules](./8-modules.mdx)
- `9` [Task Scheduler](./9-task-scheduler.mdx)
- `10` [Spawning Processes](./10-spawning-processes.md)

View file

@ -0,0 +1,48 @@
# Spawning Processes
Whenever Lune does not have the API you need as part of its built-in libraries, or when you want to
use a program that already exists but interact with it from within Lune, you can use
[`process.spawn`](../../api-reference/process.md#spawn).
## Example
This example calls out to the native "ping" program found in many operating systems, and parses its
output into something more usable to us.
This may look scary with lots of weird symbols, but, it's just some Lua-style pattern matching to
parse the lines of "min/avg/max/stddev = W/X/Y/Z ms" that the ping program gives back to us.
```lua copy
print("Sending 4 pings to google 🌏")
local result = process.spawn("ping", {
"google.com",
"-c 4",
})
if result.ok then
assert(#result.stdout > 0, "Result output was empty")
local min, avg, max, stddev = string.match(
result.stdout,
"min/avg/max/stddev = ([%d%.]+)/([%d%.]+)/([%d%.]+)/([%d%.]+) ms"
)
print(string.format("Minimum ping time: %.3fms", tonumber(min)))
print(string.format("Maximum ping time: %.3fms", tonumber(max)))
print(string.format("Average ping time: %.3fms", tonumber(avg)))
print(string.format("Standard deviation: %.3fms", tonumber(stddev)))
else
print("Failed to send ping to google!")
print(result.stderr)
process.exit(result.code)
end
```
Note that if the result of the subprocess was non-zero, meaning it errored and `ok` was set to
`false`, we will also propagate the exit code of that subprocess using
[`process.exit`](../../api-reference/process.md#exit). This will ensure that if our subprocess
fails, our script will do the same, and let the user know with a proper exit code.
## Conclusion
This is the last page of the introduction book, for more specific usage and a full overview of all
of the APIs that Lune provides, please check out the API Reference section in the sidebar. Enjoy! 🚀

View file

@ -0,0 +1,27 @@
# Built-in Libraries
Lune contains a large set of built-in libraries, much like Luau itself. These libraries include, but
are not limited to, these libraries and their common use cases:
- The [`fs`](../../api-reference/fs.md) library for manipulating files
- The [`net`](../../api-reference/net.md) library for making HTTP requests
- The [`process`](../../api-reference/process.md) library for executing external programs and
processes
This is just a small subset of what is available in Lune, but for now, what is important is that
these libraries must be imported using a special kind of `require` statement:
```lua copy
local fs = require("@lune/fs")
local net = require("@lune/net")
local process = require("@lune/process")
```
As you can see above, unlike Luau's standard libraries such as
[`math`](https://luau-lang.org/library#math-library),
[`table`](https://luau-lang.org/library#table-library),
[`string`](https://luau-lang.org/library#string-library), and others, Lune's built-in libraries are
not available as global variables and importing them before using them is required (pun intended).
The next few sections will contain examples of how to run scripts, more specific usage of Lune's
built-in libraries, and what they are most commonly used for.

View file

@ -0,0 +1,92 @@
# Standard I/O
One of Lune's most useful libraries for writing scripts is the standard I/O library, also known as
`stdio`, which will be the first one we introduce here. The pages following this one will introduce
several others.
## Prompting for User Input
The easiest way to get started and being productive using Lune is to prompt the person running your
script for some text input, which you can do using the [`stdio`](../../api-reference/stdio.md)
library. Let's make a script called `hello.luau`:
```lua copy filename="hello.luau"
local stdio = require("@lune/stdio")
local name = stdio.prompt("text", "Hello there! What's your name?")
print("Hello, " .. name .. "!")
```
Now you can place this script in your current directory, and run it using Lune:
```sh copy filename="Bash"
lune hello
```
You can also prompt for more than just text. Let's extend the above script and ask the person
running the script if that was really their name:
```lua copy filename="hello.luau"
local confirmed = stdio.prompt("confirm", "Is that really your name?")
if confirmed then
print("Nice to meet you, " .. name .. "!")
print("Have a great day!")
else
print("You lied to me! Goodbye 😡")
end
```
There are more options for prompting for user input than what we covered in this example, but these
two basic prompting methods should cover most of your use cases and get you started with making
interactive scripts.
Next, head on over to the following section on [Script Arguments](./4-script-arguments.md) or check
out the bonus game below!
<details>
<summary>Bonus</summary>
## Guessing Game
Here's a tiny game you can play versus the computer, using nothing but Lune's
[`stdio`](../../api-reference/stdio.md) library and Luau's `math` library. This is a bit longer of a
script, but don't worry, it is still only using the same functions as the script above, albeit this
time together with a `while ... do` loop and a couple `if ... then` statements:
```lua copy filename="guessing-game.luau"
local stdio = require("@lune/stdio")
print("")
print("Let's play a game! Whoever guesses the correct number between 1 and 10 first will win.")
print("")
local answer = tostring(math.random(1, 10))
local guess = stdio.prompt("text", "Input a number between 1 and 10")
while guess ~= answer do
print("Incorrect! Computer's turn...")
local computer = tostring(math.random(1, 10))
print("The computer guessed", computer)
if computer == answer then
break
end
print("Incorrect! Your turn...")
guess = stdio.prompt("text", "Input a number between 1 and 10")
end
print("")
print(if guess == answer then "You won the game! 🎉" else "The computer won the game! 😭")
print("")
```
Just like before, you can place this script in your current directory, and run it using Lune:
```sh copy filename="Bash"
lune guessing-game
```
</details>

View file

@ -0,0 +1,40 @@
# Script Arguments
Arguments can be passed to Lune scripts directly from the command line when running them:
```sh copy filename="Bash"
lune script-name arg1 arg2 "argument three"
```
These arguments will then be available in your script using the
[process](../../api-reference/process.md) built-in library, more specifically in
[`process.args`](../../api-reference/process.md#args):
```lua copy
local process = require("@lune/process")
print(process.args)
--> { "arg1", "arg2", "argument three" }
```
---
Arguments in [`process.args`](../../api-reference/process.md#args) will always be a table that is a
contiguous array, and are guaranteed to not change during runtime. A useful pattern here could be to
check for arguments given, and if there are none, prompt the user for input:
```lua copy
local process = require("@lune/process")
local stdio = require("@lune/stdio")
if #process.args > 3 then
error("Too many arguments!")
elseif #process.args > 0 then
print("Got arguments:")
print(process.args)
else
print("Got no arguments ☹️")
local prompted = stdio.prompt("Please enter some text:")
print("Got prompted text:", prompted)
end
```

View file

@ -0,0 +1,127 @@
# Network Requests
One of Lune's most useful libraries is the networking library, also known as `net`. This library
lets you access the internet and make HTTP requests to different websites, servers, and external
APIs.
## Sending HTTP Requests
Sending HTTP requests is the most basic function of the [`net`](../../api-reference/net.md) library.
Let's make a script called `googler.luau`:
```lua copy filename="googler.luau"
local net = require("@lune/net")
local response = net.request("https://google.com")
if response.ok then
print(
"Google responded with status code",
response.statusCode,
"and response message",
response.statusMessage,
"!"
)
else
print("Google is down!! What?!?")
end
```
Now you can place this script in your current directory, and run it using Lune:
```sh copy filename="Bash"
lune googler
```
## Sending JSON Requests
[JSON](https://www.json.org/json-en.html), or JavaScript Object Notation, is the most common format
for sending data over the network. Lune includes APIs for serializing & deserializing JSON, also
known as stringifying & parsing, in the `net` library. Let's use the free testing web API at
[`https://jsonplaceholder.typicode.com/`](https://jsonplaceholder.typicode.com/) and send + receive
some JSON data:
```lua copy filename="json-api.luau"
print("Sending PATCH request to web API")
local apiResponse = net.request({
url = "https://jsonplaceholder.typicode.com/posts/1",
method = "PATCH",
headers = {
["Content-Type"] = "application/json",
},
body = net.jsonEncode({
title = "foo",
body = "bar",
}),
})
if not apiResponse.ok then
error(
string.format(
"%s\n%d (%s)\n%s",
"Failed to send network request!",
apiResponse.statusCode,
apiResponse.statusMessage,
apiResponse.body
)
)
end
type ResponseType = {
id: number,
title: string,
body: string,
userId: number,
}
local responseTable: ResponseType = net.jsonDecode(apiResponse.body)
assert(responseTable.title == "foo", "Invalid json response")
assert(responseTable.body == "bar", "Invalid json response")
print("Got valid JSON response with post title set to 'foo' and post body set to 'bar'")
print("Full response:", responseTable)
```
Running the above script Lune should now send a request to the placeholder API, verify that the
response was correct, and print it out:
```sh copy filename="Bash"
lune json-api
```
---
<details>
<summary>Bonus</summary>
## Network Server
Lune can not only perform network requests, it can also open a server on a given port and serve
requests on it. Here's a small example:
```lua copy filename="network-server.luau"
local net = require("@lune/net")
local counter = 0
net.serve(8080, function()
counter += 1
return {
status = 200,
body = "Hello! This is response #" .. tostring(counter),
}
end)
print("Listening on port 8080 🚀")
```
Just like before, you can place this script in your current directory, and run it using Lune:
```sh copy filename="Bash"
lune network-server
```
Now, when you visit [`http://localhost:8080/`](http://localhost:8080/) you should see the response
text above and the counter increasing each time you visit the page.
</details>

View file

@ -0,0 +1,129 @@
import { FileTree, Tabs, Tab } from 'nextra/components'
# Files & Directories
Lune has a built-in library for interacting with the filesystem, [`fs`](../../api-reference/fs.md).
This library will let you read, write, move, copy files & directories, and more.
## Example File Tree
Let's use this directory & file tree structure for our examples:
<FileTree>
<FileTree.Folder name="-" defaultOpen>
<FileTree.File name="files.luau" />
<FileTree.File name="dirs.luau" />
<FileTree.File name="hello-world.json" />
<FileTree.Folder name="files" defaultOpen>
<FileTree.File name="coolstuff.toml" />
<FileTree.File name="super.secret.txt" />
</FileTree.Folder>
</FileTree.Folder>
</FileTree>
<details>
<summary>Show file contents</summary>
<Tabs items={['hello-world.json', 'files/coolstuff.toml', 'files/super.secret.txt']}>
<Tab>
```json copy filename="hello-world.json"
{
"Hello": "World"
}
```
</Tab>
<Tab>
```toml copy filename="coolstuff.toml"
[you]
cool = true
awesome = "yep"
```
</Tab>
<Tab>
```txt copy filename="super.secret.txt"
Hey you're not supposed to be in here!
```
</Tab>
</Tabs>
</details>
## Files
Reading and writing files using the `fs` library is very simple and *only* involves strings:
```lua copy filename="files.luau"
local fs = require("@lune/fs")
--> Print out the contents of all of the files
print(fs.readFile("hello-world.json"))
print(fs.readFile("files/coolstuff.toml"))
print(fs.readFile("files/super.secret.txt"))
--> Create a new file in our "files" directory
fs.writeFile("files/My Favorite Numbers.txt", "2 4 6 8 0 😃")
--> Write to one of our files, overwriting any previous contents
fs.writeFile("files/super.secret.txt", "Super secret message")
--> Remove the new file we created in our "files" directory
fs.removeFile("files/My Favorite Numbers.txt")
```
Note that the filesystem library deals with *raw* strings for file contents, and does not
differentiate between if the contents of the file are using binary, utf-8, or some other encoding.
It is up to you to know how your files are structured and handle them appropriately.
## Directories
Reading and creating directories has a very similar API, but slightly different parameters and return values:
```lua copy filename="dirs.luau"
local fs = require("@lune/fs")
--[[
Print out the entries found in our directory.
The "." here means the current directory.
This will output:
* 📄 files.luau
* 📄 dirs.luau
* 📄 hello-world.json
* 📁 files
]]
for _, entry in fs.readDir(".") do
if fs.isDir(entry) then
print("📁 " .. entry)
elseif fs.isFile(entry) then
print("📄 " .. entry)
end
end
--> Create a new directory next to the above entries
fs.writeDir("myCoolDir")
--> Create a new directory in our "files" directory
fs.writeDir("files/myCoolSecondDir")
--> Remove the entire files directory
fs.removeDir("files")
```
In the above example:
- `fs.readDir` returns a table (array) of strings, with file and directory names
- `fs.writeDir` takes only the directory name (path) to create a directory at
- `fs.removeDir` removes the directory ***and everything inside it***, use with caution
## Resulting File Tree
This is what our directory & file tree structure would look like after running the above examples:
<FileTree>
<FileTree.Folder name="-" defaultOpen>
<FileTree.File name="files.luau" />
<FileTree.File name="dirs.luau" />
<FileTree.File name="hello-world.json" />
<FileTree.Folder name="myCoolDir" />
</FileTree.Folder>
</FileTree>

View file

@ -0,0 +1,35 @@
# Environment Variables
Environment variables, just like script arguments, are available using the
[process](../../api-reference/process.md) built-in library, more specifically in
[`process.env`](../../api-reference/process.md#env):
```lua copy
local process = require("@lune/process")
assert(process.env.PATH ~= nil, "Missing PATH")
assert(process.env.PWD ~= nil, "Missing PWD")
process.env.MY_VAR = "Hello, env!"
print(process.env.MY_VAR)
--> Hello, env!
```
Unlike [`process.args`](../../api-reference/process.md#args), environment variables can be read from
and written to freely, and can be done at any point during runtime.
You can also iterate over all of the known environment variables using Luau's generalized iteration.
Here is an example snippet that prints a checkmark if an environment variable has some contents and
is not empty, and a red cross otherwise:
```lua copy
local process = require("@lune/process")
for key, value in process.env do
local box = if value ~= "" then "✅" else "❌"
print(string.format("[%s] %s", box, key))
end
```
Note that using `pairs` or `ipairs` will _not_ work here, only generalized iteration.

View file

@ -0,0 +1,83 @@
import { FileTree, Tabs, Tab, Callout } from 'nextra/components'
# Modules
At this point you know how the most important built-in libraries in Lune work and how to use them,
and your code is probably getting longer and more difficult to read. Splitting your code into
multiple files can help you stay organized.
Modularizing your code and splitting it across several files in Lune is different from other
versions of Lua and Luau, and more similar to how things work in other languages such as JavaScript.
## Example File Tree
Let's use this directory & file tree structure for our examples:
<FileTree>
<FileTree.Folder name="-" defaultOpen>
<FileTree.File name="main.luau" />
<FileTree.File name="sibling.luau" />
<FileTree.Folder name="modules" defaultOpen>
<FileTree.File name="init.luau" />
<FileTree.File name="module.luau" />
</FileTree.Folder>
</FileTree.Folder>
</FileTree>
<Tabs items={['main', 'sibling', 'modules/init', 'modules/module']}>
<Tab>
```lua copy filename="main.luau"
local sibling = require("sibling")
local modules = require("modules")
print(sibling.Hello) --> World
print(modules.Module.Foo) --> Bar
print(modules.Module.Fizz) --> Buzz
print(modules.Sibling.Hello) --> World
```
</Tab>
<Tab>
```lua copy filename="sibling.luau"
return {
Hello = "World",
}
```
</Tab>
<Tab>
```lua copy filename="modules/init.luau"
return {
Module = require("module"),
Sibling = require("../sibling"),
}
```
</Tab>
<Tab>
```lua copy filename="modules/module.luau"
return {
Foo = "Bar",
Fizz = "Buzz",
}
```
</Tab>
</Tabs>
## File Require Statements
Let's decipher these files and what they are doing:
- The `main` script requires `sibling` and `modules` next to it
- The `modules/init` script requires `module` next to it, and `sibling` going up one directory
using `../`
In the above `require` statements, we can see that are relative to the file that they are in, and in
Lune this is always the case, except for built-in libraries, which always start with an at sign
(`@`).
<Callout type="info" emoji="❔">
**Q:** Wait, hold on... The `main` script requires the _**directory**_ called `modules`? <br />
**A:** Yep, that's right. The file name `init` is special, and putting a file named `init.luau` in a
directory will let you use `require` directly on the directory. Similar to `index.js` in JavaScript
or `mod.rs` in Rust.
</Callout>

View file

@ -0,0 +1,139 @@
# The Task Scheduler
Lune has a built-in task scheduler, which can let you run things at fixed intervals, ensure some
work happens after everything else is already done, and more.
## Spawning Tasks & Waiting
This example script will run several tasks concurrently, in lightweight Lua threads, also known as
coroutines:
```lua copy
local task = require("@lune/task")
print("Hello, scheduler!")
task.spawn(function()
print("Spawned a task that will run instantly but not block")
task.wait(2)
print("The instant task resumed again after 2 seconds")
end)
print("Spawning a delayed task that will run after 5 seconds")
task.delay(5, function()
print("Waking up from my deep slumber...")
task.wait(1)
print("Hello again!")
task.wait(1)
print("Goodbye again! 🌙")
end)
```
## Deferring Work
This example script runs a bit of work after all other threads have finished their work or are
yielding waiting for some other result:
```lua copy
local task = require("@lune/task")
task.defer(function()
print("All the scheduled work has finished, let's do some more!")
local a = 0
for _ = 1, 100000 do
local b = a + 1
end
print("Phew, that was tough.")
end)
print("Working...")
local s = ""
for _ = 1, 5000 do
s ..= ""
end
print("Done!")
```
## Advanced Usage & Async
Spawning tasks like this can be very useful together with asynchronous APIs from other built-in
libraries, such as [`net.request`](../../api-reference/net.md#request):
```lua copy
local net = require("@lune/net")
local task = require("@lune/task")
local completed = false
task.spawn(function()
while not completed do
print("Waiting for response...")
task.wait() -- Wait the minimum amount possible
end
print("No longer waiting!")
end)
print("Sending request")
net.request("https://google.com")
print("Got response")
completed = true
```
<details>
<summary>Bonus</summary>
## Barebones Signal Implementation
Using the task library, it becomes trivial to implement signal objects that take callbacks to run
when a signal is fired, and that can handle both synchronous and yielding (async) callbacks without
additional complexity:
```lua copy
local task = require("@lune/task")
local function newSignal()
local callbacks = {}
local function connect(callback: (...any) -> ())
table.insert(callbacks, callback)
end
local function fire(...: any)
for _, callback in callbacks do
task.spawn(callback, ...)
end
end
return connect, fire
end
local connectToThing, fireThing = newSignal()
connectToThing(function(value)
print("Callback #1 got value:", value)
task.wait(1)
print("Callback #1 still has value:", value)
end)
connectToThing(function(value)
print("Callback #2 got value:", value)
task.wait(0.5)
print("Callback #2 still has value:", value)
end)
print("Before firing")
fireThing(123)
print("After firing")
--> Before firing
--> Callback #1 got value: 123
--> Callback #2 got value: 123
--> After firing
--> ...
--> Callback #2 still has value: 123
--> ...
--> Callback #1 still has value: 123
```
</details>

View file

@ -0,0 +1,12 @@
{
"1-hello-lune": "1 • Hello, Lune!",
"2-built-in-libraries": "2 • Built-in Libraries",
"3-standard-io": "3 • Standard I/O",
"4-script-arguments": "4 • Script Arguments",
"5-network-requests": "5 • Network Requests",
"6-files-and-directories": "6 • Files & Directories",
"7-environment-variables": "7 • Environment Variables",
"8-modules": "8 • Modules",
"9-task-scheduler": "9 • Task Scheduler",
"10-spawning-processes": "10 • Spawning Processes"
}

View file

@ -1,297 +0,0 @@
<!-- markdownlint-disable MD033 -->
<!-- markdownlint-disable MD026 -->
# Writing Lune Scripts
If you've already written some version of Lua (or Luau) scripts before, this walkthrough will make
you feel right at home.
Once you have a script you want to run, head over to the [Running Scripts](./2-running-scripts.md)
page.
## Hello, Lune!
```lua copy
--[[
EXAMPLE #1
Using arguments given to the program
]]
if #process.args > 0 then
print("Got arguments:")
print(process.args)
if #process.args > 3 then
error("Too many arguments!")
end
else
print("Got no arguments ☹️")
end
--[[
EXAMPLE #2
Using the stdio library to prompt for terminal input
]]
local text = stdio.prompt("text", "Please write some text")
print("You wrote '" .. text .. "'!")
local confirmed = stdio.prompt("confirm", "Please confirm that you wrote some text")
if confirmed == false then
error("You didn't confirm!")
else
print("Confirmed!")
end
--[[
EXAMPLE #3
Get & set environment variables
Checks if environment variables are empty or not,
prints out ❌ if empty and ✅ if they have a value
]]
print("Reading current environment 🔎")
-- Environment variables can be read directly
assert(process.env.PATH ~= nil, "Missing PATH")
assert(process.env.PWD ~= nil, "Missing PWD")
-- And they can also be accessed using Luau's generalized iteration (but not pairs())
for key, value in process.env do
local box = if value and value ~= "" then "✅" else "❌"
print(string.format("[%s] %s", box, key))
end
--[[
EXAMPLE #4
Writing a module
Modularizing and splitting up your code is Lune is very straight-forward,
in contrast to other scripting languages and shells such as bash
]]
local module = {}
function module.sayHello()
print("Hello, Lune! 🌙")
end
return module
--[[
EXAMPLE #5
Using a function from another module / script
Lune has path-relative imports, similar to other popular languages such as JavaScript
]]
local module = require("../modules/module")
module.sayHello()
--[[
EXAMPLE #6
Spawning concurrent tasks
These tasks will run at the same time as other Lua code which lets you do primitive multitasking
]]
task.spawn(function()
print("Spawned a task that will run instantly but not block")
task.wait(5)
end)
print("Spawning a delayed task that will run in 5 seconds")
task.delay(5, function()
print("...")
task.wait(1)
print("Hello again!")
task.wait(1)
print("Goodbye again! 🌙")
end)
--[[
EXAMPLE #7
Read files in the current directory
This prints out directory & file names with some fancy icons
]]
print("Reading current dir 🗂️")
local entries = fs.readDir(".")
-- NOTE: We have to do this outside of the sort function
-- to avoid yielding across the metamethod boundary, all
-- of the filesystem APIs are asynchronous and yielding
local entryIsDir = {}
for _, entry in entries do
entryIsDir[entry] = fs.isDir(entry)
end
-- Sort prioritizing directories first, then alphabetically
table.sort(entries, function(entry0, entry1)
if entryIsDir[entry0] ~= entryIsDir[entry1] then
return entryIsDir[entry0]
end
return entry0 < entry1
end)
-- Make sure we got some known files that should always exist
assert(table.find(entries, "Cargo.toml") ~= nil, "Missing Cargo.toml")
assert(table.find(entries, "Cargo.lock") ~= nil, "Missing Cargo.lock")
-- Print the pretty stuff
for _, entry in entries do
if fs.isDir(entry) then
print("📁 " .. entry)
else
print("📄 " .. entry)
end
end
--[[
EXAMPLE #8
Call out to another program / executable
You can also get creative and combine this with example #6 to spawn several programs at the same time!
]]
print("Sending 4 pings to google 🌏")
local result = process.spawn("ping", {
"google.com",
"-c 4",
})
--[[
EXAMPLE #9
Using the result of a spawned process, exiting the process
This looks scary with lots of weird symbols, but, it's just some Lua-style pattern matching
to parse the lines of "min/avg/max/stddev = W/X/Y/Z ms" that the ping program outputs to us
]]
if result.ok then
assert(#result.stdout > 0, "Result output was empty")
local min, avg, max, stddev = string.match(
result.stdout,
"min/avg/max/stddev = ([%d%.]+)/([%d%.]+)/([%d%.]+)/([%d%.]+) ms"
)
print(string.format("Minimum ping time: %.3fms", assert(tonumber(min))))
print(string.format("Maximum ping time: %.3fms", assert(tonumber(max))))
print(string.format("Average ping time: %.3fms", assert(tonumber(avg))))
print(string.format("Standard deviation: %.3fms", assert(tonumber(stddev))))
else
print("Failed to send ping to google!")
print(result.stderr)
process.exit(result.code)
end
--[[
EXAMPLE #10
Using the built-in networking library, encoding & decoding json
]]
print("Sending PATCH request to web API 📤")
local apiResult = net.request({
url = "https://jsonplaceholder.typicode.com/posts/1",
method = "PATCH",
headers = {
["Content-Type"] = "application/json",
},
body = net.jsonEncode({
title = "foo",
body = "bar",
}),
})
if not apiResult.ok then
print("Failed to send network request!")
print(string.format("%d (%s)", apiResult.statusCode, apiResult.statusMessage))
print(apiResult.body)
process.exit(1)
end
type ApiResponse = {
id: number,
title: string,
body: string,
userId: number,
}
local apiResponse: ApiResponse = net.jsonDecode(apiResult.body)
assert(apiResponse.title == "foo", "Invalid json response")
assert(apiResponse.body == "bar", "Invalid json response")
print("Got valid JSON response with changes applied")
--[[
EXAMPLE #11
Using the stdio library to print pretty
]]
print("Printing with pretty colors and auto-formatting 🎨")
print(stdio.color("blue") .. string.rep("—", 22) .. stdio.color("reset"))
print("API response:", apiResponse)
warn({
Oh = {
No = {
TooMuch = {
Nesting = {
"Will not print",
},
},
},
},
})
print(stdio.color("blue") .. string.rep("—", 22) .. stdio.color("reset"))
--[[
EXAMPLE #12
Saying goodbye 😔
]]
print("Goodbye, lune! 🌙")
```
More real-world examples of how to write Lune scripts can be found in the
[examples](https://github.com/filiptibell/lune/blob/main/.lune/examples/) folder.
Documentation for individual APIs and types can be found in the "API Reference" section in the
sidebar.

View file

@ -1,8 +1,8 @@
<!-- markdownlint-disable MD033 --> # Command-Line Usage
# Running Lune Scripts ## Running Scripts
After you've written a script file, for example `script-name.luau`, you can run it: When you've written a script file, for example `script-name.luau`, you can run it as such:
```sh copy ```sh copy
lune script-name lune script-name
@ -16,24 +16,7 @@ This will look for the file `script-name.luau`**_<sup>[1]</sup>_** in a few loca
- The folder `lune` in the _home_ directory, if it exists - The folder `lune` in the _home_ directory, if it exists
- The folder `.lune` in the _home_ directory, if it exists - The folder `.lune` in the _home_ directory, if it exists
## Passing Command-Line Arguments ## Listing Scripts
Arguments can be passed to a Lune script directory from the command line when running it:
```sh copy
lune script-name arg1 arg2 "argument three"
```
These arguments will then be available in your script using `process.args`:
```lua copy
local process = require("@lune/process")
print(process.args)
--> { "arg1", "arg2", "argument three" }
```
## Additional Commands
```sh copy ```sh copy
lune --list lune --list
@ -43,12 +26,18 @@ Lists all scripts found in `lune` or `.lune` directories, including any top-leve
comments. <br /> Lune description comments are always written at the top of a file and start with a comments. <br /> Lune description comments are always written at the top of a file and start with a
lua-style comment arrow (`-->`). lua-style comment arrow (`-->`).
## Advanced Usage
```sh copy ```sh copy
lune - lune -
``` ```
Runs a script passed to Lune using stdin. Occasionally useful for running scripts piped to Lune from Runs a script passed to Lune using stdin. Useful for running scripts piped to Lune from external
external sources. sources. Example:
```sh copy
echo "print 'Hello, terminal!'" | lune -
```
--- ---

View file

@ -1,6 +1,6 @@
{ {
"1-installation": "Installation", "1-installation": "Installation",
"2-writing-scripts": "Writing Scripts", "2-introduction": "Introduction",
"3-running-scripts": "Running Scripts", "3-command-line-usage": "Command-Line Usage",
"4-editor-setup": "Editor Setup" "4-editor-setup": "Editor Setup"
} }