自分でビルドしたruby.wasmを実行する環境をつくる - @ledsun blog で、ruby.wasmのカスタムビルドを動かせるようになりました。
実装中の require_relative
が動くか確かめてみましょう。
次のような index.hml
を作成します。
<html> <script src="browser.script.iife.js"></script> <script type="text/ruby"> require 'js/require_remote' module Kernel def require_relative(path) = JS::RequireRemote.instance.load(path) end </script> <script type="text/ruby" data-eval="async"> require_relative 'app' </script> </html>
現在は、ruby.wasmで Kernel#require_relative
自体を改変しない方針を採っています。
代わりに、ブラウザ上で Kernel#require_relative
のように動く、JS::RequireRemote#load
*1を作成しています。
ローダー周りのメソッドはパッチを当てられがちです。*2
ユーザーは別の目的で Kernel#require_relative
にパッチを当てたいかも知れません。
パッチを当てるかどうかの判断をユーザーに委ねるためです。
require_relative
の読込先として、次のような app.rb を用意します。
puts 'Hello, World!'
前回と同じように Hello, world!
が表示されます。
ちなみに上記の Kenerl#require_relative
のパッチは、既存の動作を壊しています。
たとえば、require 'csv'
を実行すると次のエラーが起きます。
csv gemの中のrequire_relative "csv/fields_converter"
*3の動作が変わって起きたエラーです。
既存の動作を壊さないさないようにするには、次のように、もう少し複雑なパッチを当てる必要があります。
module Kernel alias original_require_relative require_relative def require_relative(path) caller_path = caller_locations(1, 1).first.absolute_path || '' dir = File.dirname(caller_path) file = File.absolute_path(path, dir) original_require_relative(file) rescue LoadError JS::RequireRemote.instance.load(path) end end
最初にオリジナルの Kernel#require_relative
を実行して、見つからなかったときだけ JS::RequireRemote#load
を実行します。
*1:仮名です。
*2: たとえばzeitwerkは Kernel#require にパッチを当てています。https://github.com/fxn/zeitwerk/blob/4f44672102d4629ada277ae047cfde337ab2b9b2/lib/zeitwerk/kernel.rb#L27-L47
*3:https://github.com/ruby/ruby/blob/63fdfa1312a8d54ff5f1493dd4759de0253848f1/lib/csv.rb#L96