Repository: pyscript/pyscript
File: pyscript.core/esm/interpreter/ruby-wasm-wasi.js (JavaScript)

Code before:

// MISSING:
//  * there is no VFS apparently or I couldn't reach any
//  * I've no idea how to override the stderr and stdout
//  * I've no idea how to import packages

// REQUIRES INTEGRATION TEST
/* c8 ignore start */
export default {
    type,
    experimental: true,
    module: (version = "2.0.0") =>
        `https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${version}/dist/browser.esm.js`,
    async engine({ DefaultRubyVM }, config, url) {
        const response = await fetch(
            `${url.slice(0, url.lastIndexOf("/"))}/ruby.wasm`,
        );
        const module = await WebAssembly.compile(await response.arrayBuffer());
        const { vm: interpreter } = await DefaultRubyVM(module);
        if (config.fetch) await fetchPaths(this, interpreter, config.fetch);
        return interpreter;
    },
    registerJSModule,
    setGlobal(interpreter, name, value) {
        const id = `__pyscript_ruby_wasm_wasi_${name}`;
        globalThis[id] = value;
        this.run(interpreter, `require "js";$${name}=JS::eval("return ${id}")`);
    },
    deleteGlobal(interpreter, name) {
        const id = `__pyscript_ruby_wasm_wasi_${name}`;
        this.run(interpreter, `$${name}=nil`);
        delete globalThis[id];
    },
    run: (interpreter, code) => interpreter.eval(clean(code)),
    runAsync: (interpreter, code) => interpreter.evalAsync(clean(code)),
    writeFile: () => {
        throw new Error(`writeFile is not supported in ${type}`);
    },
};
/* c8 ignore stop */


Review comment (bug):
This means that, if the user's event code has side-effects, they will happen (before presumably an error is thrown):

```html
<button ruby-wasm-wasi-click='print "ruby #{ RUBY_VERSION }p#{ RUBY_PATCHLEVEL }"'>
    Click to Print (and Error)
</button>
```
![image](https://github.com/pyscript/pyscript/assets/1931111/502e2a5d-12ae-4847-b854-1c2a1eeec00f)

I don't have a better suggestion of how to implement this - it's an issue we've run into on previous iterations of trying to augment event handlers, of needing to do evaluation in some contexts just to recover the global. Just something worth documenting I think, since the user may think "My code 'worked', but then it also crashed?"



Code after:

// MISSING:
//  * there is no VFS apparently or I couldn't reach any
//  * I've no idea how to override the stderr and stdout
//  * I've no idea how to import packages

// REQUIRES INTEGRATION TEST
/* c8 ignore start */
export default {
    type,
    experimental: true,
    module: (version = "2.0.0") =>
        `https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${version}/dist/browser.esm.js`,
    async engine({ DefaultRubyVM }, config, url) {
        const response = await fetch(
            `${url.slice(0, url.lastIndexOf("/"))}/ruby.wasm`,
        );
        const module = await WebAssembly.compile(await response.arrayBuffer());
        const { vm: interpreter } = await DefaultRubyVM(module);
        if (config.fetch) await fetchPaths(this, interpreter, config.fetch);
        return interpreter;
    },
    registerJSModule,
    getGlobal(interpreter, name) {
        try {
            return this.run(interpreter, name);
        } catch (_) {
            const method = this.run(interpreter, `method(:${name})`);
            return (...args) =>
                method.call(
                    name,
                    ...args.map((value) => interpreter.wrap(value)),
                );
        }
    },
    setGlobal(interpreter, name, value) {
        const id = `__pyscript_ruby_wasm_wasi_${name}`;
        globalThis[id] = value;
        this.run(interpreter, `require "js";$${name}=JS::eval("return ${id}")`);
    },
    deleteGlobal(interpreter, name) {
        const id = `__pyscript_ruby_wasm_wasi_${name}`;
        this.run(interpreter, `$${name}=nil`);
        delete globalThis[id];
    },
    run: (interpreter, code) => interpreter.eval(clean(code)),
    runAsync: (interpreter, code) => interpreter.evalAsync(clean(code)),
    writeFile: () => {
        throw new Error(`writeFile is not supported in ${type}`);
    },
};