Skip to content
Yuta Saito edited this page Dec 3, 2023 · 2 revisions

ruby.wasm Cheat Sheet

Node.js

To install the package, install @ruby/3.2-wasm-wasi and @ruby/wasm-wasi from npm:

npm install --save @ruby/3.2-wasm-wasi @ruby/wasm-wasi

Then instantiate a Ruby VM by the following code:

import fs from "fs/promises";
import { DefaultRubyVM } from "@ruby/wasm-wasi/dist/node";

const binary = await fs.readFile("./node_modules/@ruby/3.2-wasm-wasi/dist/ruby.wasm");
const module = await WebAssembly.compile(binary);
const { vm } = await DefaultRubyVM(module);
vm.eval(`puts "hello world"`);

Then run the example code with --experimental-wasi-unstable-preview1 flag to enable WASI support:

$ node --experimental-wasi-unstable-preview1 index.mjs

Browser

The easiest way to run Ruby on browser is to use browser.script.iife.js script from CDN:

<html>
  <script src="https://cdn.jsdelivr.net/npm/@ruby/3.2-wasm-wasi@2.3.0/dist/browser.script.iife.js"></script>
  <script type="text/ruby">
    require "js"
    JS.global[:document].write "Hello, world!"
  </script>
</html>

If you want to control Ruby VM from JavaScript, you can use @ruby/wasm-wasi package API:

<html>
  <script type="module">
    import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.3.0/dist/esm/browser.js";
    const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.2-wasm-wasi@2.3.0/dist/ruby+stdlib.wasm");
    const module = await WebAssembly.compileStreaming(response);
    const { vm } = await DefaultRubyVM(module);

    vm.eval(`
      require "js"
      JS.global[:document].write "Hello, world!"
    `);
  </script>
</html>

Use JavaScript from Ruby

Get/set JavaScript variables from Ruby

require "js"

document = JS.global[:document]
document[:title] = "Hello, world!"

Call JavaScript methods from Ruby

require "js"

JS.global[:document].createElement("div")

JS.global[:document].call(:createElement, "div".to_js) # same as above

Pass Ruby Proc to JavaScript

require "js"

JS.global.setTimeout(proc { puts "Hello, world!" }, 1000)

input = JS.global[:document].querySelector("input")
input.addEventListener("change") do |event|
  puts event[:target][:value].to_s
end

await JavaScript Promise from Ruby

<html>
  <script src="https://cdn.jsdelivr.net/npm/@ruby/3.2-wasm-wasi@2.3.0/dist/browser.script.iife.js"></script>
  <script type="text/ruby" data-eval="async">
    require "js"

    response = JS.global.fetch("https://www.ruby-lang.org/").await
    puts response[:status]
  </script>
</html>

Or using @ruby/wasm-wasi package API:

<html>
  <script type="module">
    import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.3.0/dist/esm/browser.js";
    const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/3.2-wasm-wasi@2.3.0/dist/ruby+stdlib.wasm");
    const module = await WebAssembly.compileStreaming(response);
    const { vm } = await DefaultRubyVM(module);

    vm.evalAsync(`
      require "js"

      response = JS.global.fetch("https://www.ruby-lang.org/").await
      puts response[:status]
    `);
  </script>
</html>

new JavaScript instance from Ruby

require "js"

JS.global[:Date].new(2021, 1, 1)

Convert returned JavaScript String value to Ruby String

require "js"

title = JS.global[:document].title # => JS::Object("Hello, world!")
title.to_s # => "Hello, world!"

Convert JavaScript Boolean value to Ruby true/false

require "js"

JS.global[:document].hasFocus? # => true
JS.global[:document].hasFocus  # => JS::Object(true)

Convert JavaScript Number value to Ruby Integer/Float

require "js"

rand = JS.global[:Math].random # JS::Object(0.123456789)
rand.to_i # => 0
rand.to_f # => 0.123456789
Clone this wiki locally