---
title: Ruby&#039;s Blanket進捗報告
tags: 
author: [中島 滋](https://www.docswell.com/user/ledsun)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/VJPK1VZ3E8.jpg?width=480
description: RubyKaigi 2026 follow up ( https://rhc.connpass.com/event/392503/ ) の発表資料です。 RubyKaigi 2026で発表したRuby&#039;s Blanket（ruby.wasm上でJavaScriptからRubyを操作するAPIを充実させていくプロジェクト）の進捗報告です。
published: September 05, 26
canonical: https://www.docswell.com/s/ledsun/5E1JD1-progress-of-rubys-blanket
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/VJPK1VZ3E8.jpg)

Ruby’s blanket 進捗報告
2026/09/05
RubyKaigi 2026 follow up


# Page. 2

![Page Image](https://bcdn.docswell.com/page/2EVVYZWNEQ.jpg)

Self Introduction
Luxiar co., Ltd.
Shigeru Nakajima, Chief Architect
ledsun on GitHub and Twitter
ko.rb organizer
9/14 meetup in Tokyo
株式会社ラグザイアはRubyKaigi 2026 follow upのスポンサーです。
1/28


# Page. 3

![Page Image](https://bcdn.docswell.com/page/57GL94D5EL.jpg)

目次
Ruby::Box in the Browser
require_relative in the Node.js
Ruby’s Blanket
Ruby’s Blanketに限定せずにruby.wasmの進捗を話します。
2/28


# Page. 4

![Page Image](https://bcdn.docswell.com/page/4EQYWG1LJP.jpg)

Ruby::Box in the Browser
ブラウザ上のruby.wasmでRuby::Box動きます。
&lt;script
src=&quot;https://cdn.jsdelivr.net/npm/@ruby/head-wasm-wasi@latest/dist/browser.script.iife.js&quot;
data-env=&#039;{&quot;RUBY_BOX&quot;:&quot;1&quot;}&#039;
&gt;&lt;/script&gt;
&lt;script type=&quot;text/ruby&quot;&gt;
box = Ruby::Box.new
box.eval &lt;&lt;~RUBY
X = 123
RUBY
puts Ruby::Box.enabled? #=&gt; true
puts box::X
#=&gt; 123
&lt;/script&gt;
3/28


# Page. 5

![Page Image](https://bcdn.docswell.com/page/KJ4WK5R571.jpg)

data-env
ポイントはdata-env属性。
data-env=&#039;{&quot;RUBY_BOX&quot;:&quot;1&quot;}&#039;
任意の環境変数を設定できます。
RUBY_FIBER_MACHINE_STACK_SIZEも変更可能
前田修吾さんはRUBY_FIBER_MACHINE_STACK_SIZEを設定できなくて、2022年？
の忘年会のビンゴにつかうのを諦めた
4/28


# Page. 6

![Page Image](https://bcdn.docswell.com/page/LE1YXWQ27G.jpg)

背景
browser.script.iife.js では Ruby VM 起動後に
ユーザーコードが動く
Ruby::BoxはRuby VM起動時に環境変数が必要
ビルドし直せばできるけど・・・
ruby.wasmをフルビルドすると20分・・・
5/28


# Page. 7

![Page Image](https://bcdn.docswell.com/page/GEWGN6M2J2.jpg)

解決策
ビルドしないで任意の環境変数が設定できる！
6/28


# Page. 8

![Page Image](https://bcdn.docswell.com/page/47ZL3YQ4J3.jpg)

data-env の使い方
&lt;script
src=&quot;https://cdn.jsdelivr.net/npm/@ruby/head-wasm-wasi@latest/dist/browser.script.iife.js&quot;
data-env=&#039;{&quot;RUBY_BOX&quot;:&quot;1&quot;}&#039;
&gt;&lt;/script&gt;
scriptタグにdata-env属性を追加
JSON形式で環境変数を指定
キーと値は文字列(数値不可)
7/28


# Page. 9

![Page Image](https://bcdn.docswell.com/page/YJ6WXD6GJV.jpg)

require_relative in the Node.js
Node.js上のruby.wasmでrequire_relativeが動
きます。
const { vm } = await DefaultRubyVM(module, {
preopens: {
&quot;/app&quot;: &quot;./app&quot;,
},
});
vm.eval(`require_relative &quot;/app/main&quot;`);
ブラウザではすでにrequire_relativeは使えます。
8/28


# Page. 10

![Page Image](https://bcdn.docswell.com/page/GJ5MX36XJ4.jpg)

preopens
ポイントはpreopensオプション。
preopens: {
&quot;/app&quot;: &quot;./app&quot;,
},
任意のローカルディレクトリをマウントできる
9/28


# Page. 11

![Page Image](https://bcdn.docswell.com/page/9E29XZMQ7R.jpg)

没案
ブラウザはfetchを使ったJS::RequireRemoteを実装
Nodeもfs.readFileSyncを使って独自ローダーを
RubyKaigi 2026で動かしたデモはこの方式でした。
10/28


# Page. 12

![Page Image](https://bcdn.docswell.com/page/D7Y48RXYEM.jpg)

JS::RequireRemote方式のデメリット
Node.jsプロセスが参照できるディレクトリがす
べて読めてしまう
Node.jsのセキュリティモデルに依存
ロード処理が自前で、CRubyと挙動が変わる
fetchしか使えないブラウザでは妥協できる
ファイルシステムが使えるNode.jsならCRuby
と同じ挙動を期待
11/28


# Page. 13

![Page Image](https://bcdn.docswell.com/page/VENYQD1RJ8.jpg)

解決策
WASIのpreopensオプションを指定！
12/28


# Page. 14

![Page Image](https://bcdn.docswell.com/page/Y79PDG5ZE3.jpg)

preopensオプションの使い方
const { vm } = await DefaultRubyVM(module, {
preopens: {
&quot;/app&quot;: &quot;./local_dir&quot;,
},
});
ruby.wasmのVMの起動オプションを追加
JSON形式で指定
キーが仮想パス、値がローカルディレクトリ
13/28


# Page. 15

![Page Image](https://bcdn.docswell.com/page/G78D3V6Y7D.jpg)

Ruby’s Blanket
おさらい
14/28


# Page. 16

![Page Image](https://bcdn.docswell.com/page/L7LMV599JR.jpg)

Ruby-to-JavaScript vs JavaScript-to-Ruby
Feature
eval
Method Call
Property Access
Object Conversion
Load Ruby Scripts
R→J
Yes
Yes
Yes
Yes
browser
J→R
Yes
call
N/A
string
No
15/28


# Page. 17

![Page Image](https://bcdn.docswell.com/page/4EMYG3ZVEW.jpg)

Currently, JavaScript calls Ruby using eval
const script = `
class Dog
def name()= &#039;john&#039;
end
Dog.new
`
const dog = vm.eval(script);
dog.call(&quot;name&quot;).toString(); // =&gt; &quot;John&quot;
16/28


# Page. 18

![Page Image](https://bcdn.docswell.com/page/PER9ZQ6WJ9.jpg)

RubyKaigi 2026でのデモ
vm.eval(`
require &quot;js/require_local/relative_shim&quot;
JS::RequireLocal.instance.base_dir = &quot;require_local&quot;
require_relative &quot;./dog&quot;
`);
const dog = vm.eval(&quot;Dog.new&quot;);
console.log(dog.call(&quot;vow&quot;).toString()); // woof
console.log(dog.call(&quot;vow&quot;).toString()); // woof
console.log(dog.call(&quot;count_of_vows&quot;).toString()); // 2
17/28


# Page. 19

![Page Image](https://bcdn.docswell.com/page/P7XQ95MVEX.jpg)

preopensをつかえば
vm.eval(&quot;require_relative &#039;./dog&#039;&quot;);
const dog = vm.eval(&quot;Dog.new&quot;);
console.log(dog.call(&quot;vow&quot;).toString()); // woof
console.log(dog.call(&quot;vow&quot;).toString()); // woof
console.log(dog.call(&quot;count_of_vows&quot;).toString()); // 2
18/28


# Page. 20

![Page Image](https://bcdn.docswell.com/page/37K9P6G57D.jpg)

JavaScriptからRubyのメソッド呼び出ししたい
// before
user.call(&quot;name&quot;);
user.call(&quot;greeting&quot;);
// after
user.name();
user.greeting();
19/28


# Page. 21

![Page Image](https://bcdn.docswell.com/page/LJ3WX6N1J5.jpg)

RbValueのProxy化
RbValueオブジェクト（Rubyの値をラップする
JavaScriptのオブジェクト）に、JavaScriptのProxy
というメタプログラミング機能を使って、Rubyのメ
ソッドを動的に探せば実現可能。
仕様の整合性に考えることがたくさん
20/28


# Page. 22

![Page Image](https://bcdn.docswell.com/page/8JDK2VWKEG.jpg)

メソッド探索順序
1. RbValue オブジェクトに定義されたJavaScript
プロパティ
2. RbValue のJavaScript API
3. RbValue のプロトタイプチェーンで定義された
JavaScriptプロパティ
4. Rubyメソッドへの転送を禁止する予約名
5. Rubyメソッド
21/28


# Page. 23

![Page Image](https://bcdn.docswell.com/page/VEPK1V9378.jpg)

予約名とは？
JavaScriptのランタイムやツールが暗黙に呼ぶ名前
then
toJSON
inspect
Rubyオブジェクトに同名のメソッドが定義されてい
たら隠す（undefinedを返す）。
RbValueオブジェクトに動的に定義されたプロパ
ティがあればそれを返す。
22/28


# Page. 24

![Page Image](https://bcdn.docswell.com/page/27VVYZMN7Q.jpg)

JavaScriptのセッターは？
user.name = &quot;Bob&quot;;
JavaScriptのプロパティを更新する。
Rubyのメソッドを呼ばない。
value.call(&quot;name=&quot;, newName)
よびだければcallを使う。
JavaScriptのセッターは動的なメソッド定義にもなる
23/28


# Page. 25

![Page Image](https://bcdn.docswell.com/page/5JGL94G57L.jpg)

JavaScriptのメソッドオブジェクトとして使える？
const foo = value.foo;
foo();
考慮しない！
24/28


# Page. 26

![Page Image](https://bcdn.docswell.com/page/47QYWGXLEP.jpg)

メソッドに渡す引数はJavaScriptの値？
// before
array.push(vm.eval(&quot;123&quot;));
// after
array.push(123);
次のチャレンジとする！
25/28


# Page. 27

![Page Image](https://bcdn.docswell.com/page/KE4WK565J1.jpg)

JavaScriptのコールバック関数の場合は？
// before
JS.global.receive(
JS::Object.wrap(User.new(&quot;Alice&quot;))
)
// after
JS.global.receive(User.new(&quot;Alice&quot;))
次のチャレンジとする！
26/28


# Page. 28

![Page Image](https://bcdn.docswell.com/page/L71YXWV2JG.jpg)

JavaScriptのAPIでRubyのメソッド探せる？
typeof value.foo;
if (value.foo) {}
探せない。
value.call(&quot;respond_to?&quot;, vm.eval(&#039;&quot;foo&quot;&#039;));
callを使う
27/28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/G7WGN6L2E2.jpg)

おわり
ご清聴ありがとうございました。
28/28


