@ledsun blog

無味の味は佳境に入らざればすなわち知れず

require_relativeの動作確認する

自分でビルドした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! が表示されます。

ブラウザの開発コンソールにHello, world!が表示されているスクリーンショット

ちなみに上記の Kenerl#require_relative のパッチは、既存の動作を壊しています。 たとえば、require 'csv'を実行すると次のエラーが起きます。

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 を実行します。