Questions and answers
Written for Ring developers who would rather not become web developers. No JavaScript knowledge is assumed, and every answer below was run against the RingScript build this site ships — the error messages are the real ones, copied from the runtime.
Getting your Ring files in
Does load "myfile.ring" work?
Not for your own files
A browser tab has no filesystem. There is no folder for load to look in —
the same rule that stops any web page from reading your hard disk. This is not something
RingScript withholds; there is genuinely nothing there to open.
If you point load at a file sitting next to your HTML, this is what
comes back:
load "helpers.ring"
Error (E9) : Can't open file helpers.ring eval Line (1) Error (C27) : Syntax Error! eval errors count : 1
Two messages, one cause: the file was never found, so nothing could be parsed. If
you see E9, stop looking for a syntax mistake — it is a missing file.
So how do I split my program across several files?
Give the script tag a src
List your files the way you would list load lines, and RingScript
fetches and runs each one for you. There is no JavaScript to write:
<script src="ringscript.js"></script> <script type="text/ring" src="helpers.ring"></script> <script type="text/ring" src="invoice.ring"></script> <script type="text/ring"> oBill = new Invoice oBill.Add(120) ? Greet("Mansour") </script> <script>RingScript.boot()</script>
They run in the order they appear, each finishing before the next begins — so a file
may freely use functions and classes an earlier one defined, exactly as consecutive
load lines behave. Inline blocks and src blocks can be mixed
in any order.
Your .ring files stay ordinary Ring files, with nothing added for the
web: the same helpers.ring still runs under ring.exe.
One rule: the files must be served over http:// or
https://, not opened as file:// — browsers refuse to read
the local disk. RingScript ships a small server for exactly this: double-click
start-playground and it serves the folder for you. If a file is missing
or misspelled, the browser console names it and the rest of the page carries on.
If you would rather drive it yourself — loading a file only under some condition, say
— the manual equivalent is two lines, and eval can be called whenever you
like:
const ring = await RingScript.load("ringscript.wasm"); ring.eval(await (await fetch("reports.ring")).text());
Does what I load stay loaded?
Yes — one VM per page
A single virtual machine lives for as long as the page does. Functions, classes and variables defined by one evaluation are still there for every later one, so loading three files in a row and using all three together works the way you would expect:
# helpers.ring, evaluated first func Greet cName return "Ahlan, " + cName + "!" # later, from anywhere else on the page ? Greet("Mansour") # Ahlan, Mansour!
The same holds for classes: define one in a file, create objects from it minutes later in response to a click.
Then why does load exist in RingScript at all?
Because a library can be baked into the wasm when the runtime is built, and
for those files load works normally. That is how the JSON codec RingScript
uses internally gets there. It is the right route for a library you always want present
and never want to fetch — but it means rebuilding the runtime, which needs Zig.
For your own application code, fetching and evaluating is simpler and needs no toolchain at all.
The language itself
Which functions do I get without loading anything?
Everything built into the Ring VM, which is most of what you reach for day to day:
? upper("ab") + lower("CD") # ABcd ? substr("hello", "ll") # 3 ? sort([3,1,2]) # 1 2 3 ? find([1,2,3], 2) # 2 ? number("42") + 1 # 43 ? sqrt(16) ? pow(2,10) # 4, then 1024 ? date() ? clock() # time, uptime ? JsonEncode([ :a = 1 ]) # {"a":1} — built in
Classes, objects, inheritance, lists, try/catch and declarative blocks
all behave exactly as they do natively — this is Ring's own compiler and VM, not an
imitation of it.
What is not there is Ring's stdlib.ring layer. The most common
surprise is split():
Error (R3) : Calling Function without definition: split
If you need those, the honest answer today is to write the handful you use, or to
have them embedded into the runtime. Fetching Ring's own stdlib.ring does
not work cleanly, because that file itself uses load.
Can I read and write files?
No — and no web page can
Error (R35) : Can't create/open the file
Every application in a browser lives by this rule, so it is not a RingScript
restriction. You get a clean, catchable Ring error rather than a dead runtime, so a
program that tries can recover. Where a desktop program would save a file, a web app saves to the
server, or to browser storage. The same applies to system(), threads and
anything else that needs an operating system.
How does the user type something in? Does give work?
Yes, and it really does wait
give pauses the program and asks the page for a value, the way it pauses
and asks the console natively. In the Playground an input field appears with a
Continue button; the program resumes where it stopped.
? "What is your name?" give cName ? "Ahlan, " + cName
In your own page you decide where the value comes from — a form field, a dialog, or anything else — by handling it in the loader.
Talking to the page
How do I run a Ring function when a button is clicked?
Name the function in the markup. There is no listener to register:
<button onclick="ring.call('Greet')">Greet</button>
To read and write the page from Ring, use Page():
func Greet cName = Page(:getvalue, [ :id = "guest" ]) if cName = "" cName = "stranger" ok Page(:settext, [ :id = "hello", :text = "Ahlan, " + cName ])
If you only want Ring on the page and nothing more, RingScript.boot()
does the wiring for you and runs every
<script type="text/ring"> block on the page in order.
Can Ring call JavaScript, and JavaScript call Ring?
Both ways, over JSON
# Ring calling out cReply = jscall("savedraft", JsonEncode([ :id = 7 ]))
// JavaScript calling in: JSON in, JSON out const r = ring.call("Price", {qty: 3}); console.log(r.result);
Page() and Platform() are the same seam with the JSON
handled for you: Page() for this document, Platform() for a
capability of whatever the app is deployed to — storage, notifications, exit. The
seam is deliberately thin, and entirely optional: plenty of pages never use it.
What happens when my Ring code has an error?
You get the message and the real line number, and the page carries on. A mistake in one evaluation does not poison the VM — the next one runs normally, with everything defined before it still intact. This is checked continuously, including that memory stays flat after a thousand failing evaluations.
Setting up
Do I need Zig, Node, or npm?
None of them
You need two files next to your HTML — ringscript.js and
ringscript.wasm, about 360 KB together — and any web server. Copy them onto
GitHub Pages, nginx, a shared host, whatever you already use. There is no build step and
nothing to install.
Zig is needed only to rebuild the runtime itself, which is of interest if you want to change RingScript or embed a library into it. Ring users can install everything with RingPM:
ringpm install ringscript from mayouni
Where does this leave WebLib and Bolt?
Exactly where they are. Ring on the server keeps doing what it does well — with WebLib or Bolt — and RingScript covers the one place Ring could not previously reach: the page itself. One language on both sides, instead of two.
Is it really the Ring I know?
Ring 1.27, compiled
Not reimplemented, not a lookalike: it is Ring's own compiler and virtual machine
built to WebAssembly. Around 850
programs — the official sample set and every code block in Ring's documentation — are
checked to print byte-identical output to the native interpreter, with no mismatches.
If it behaves differently from ring.exe on your machine, that is a bug
worth reporting.