次のスクリプトはエラーになるでしょうか?
<html> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser.script.iife.js"></script> <script type="text/ruby"> require "js" JS::global.send(:require, 'erb') erb = ERB.new("Hello <%= val %>!") puts erb.result_with_hash val: "world" </script> </html>
ヒント。次のスクリプトはエラーになりません。
<html> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser.script.iife.js"></script> <script type="text/ruby"> require "erb" erb = ERB.new("Hello <%= val %>!") puts erb.result_with_hash val: "world" </script> </html>
ヒント2。JS::global
はRubyのオブジェクトです。
つまりKernelを継承しています。
ヒント3
irb(main):002:0> 1.send(:require, 'erb') => true
つぎのようなコードを書いたら無限ループしました。というお話でした。
- JavaScriptに
window.js_require_relative
って関数を定義 - Rubyに
Kernel#js_require_relative
って関数を定義 - 後者から
JS.global.js_require_relative
を呼んだ
<html> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser.script.iife.js"></script> <script> window.js_require_relative = function() { console.log("called") } </script> <script type="text/ruby"> require "js" module Kernel def js_require_relative JS::global.js_require_relative() end end js_require_relative </script> </html>
を実行すると
JS:global
のJavaScript側のメソッド検索はmethod_missingで行っています。
def method_missing(sym, *args, &block) if self[sym].typeof == "function" self.call(sym, *args, &block) else super end end
Kernel#js_require_relative
が定義されているため、method_missingが呼び出されていないのだと思います。
次のようにKernel#js_require_relative
をprivateメソッドにします。
<html> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser.script.iife.js"></script> <script> window.js_require_relative = function() { console.log("called") } </script> <script type="text/ruby"> require "js" module Kernel private def js_require_relative JS::global.js_require_relative() end end js_require_relative </script> </html>
するとJS::global.js_require_relative()
でNoMethodError
が発生し、無事にwindow.js_require_relative
が呼び出されます。
そもそも
- 同名してうれしいのか?
- windowオブジェクトに直接関数を増やしたらダメだろ
など、前提条件に疑問はあります。