From 230ffe4b6ca0bd67025cb7b3ec657db921183428 Mon Sep 17 00:00:00 2001 From: ledsun Date: Mon, 19 Aug 2024 08:40:38 +0900 Subject: [PATCH 1/2] Undefine Object#send method to call JavaScript send method --- packages/gems/js/lib/js.rb | 10 ++++++++++ .../ruby-wasm-wasi/test/unit/test_object.rb | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/gems/js/lib/js.rb b/packages/gems/js/lib/js.rb index 04ef16761e..81c679641a 100644 --- a/packages/gems/js/lib/js.rb +++ b/packages/gems/js/lib/js.rb @@ -195,6 +195,16 @@ def respond_to_missing?(sym, include_private) self[sym].typeof == "function" end + # To call the JavaScript `send` method and to check whether the `send` method exists, delete the definition of `Object#send`. + # + # For example, the JavaScript `WebSocket` and `XMLHttpRequest` have a `send` method. + # The JavaScript method call short-hand in JS::Object is implemented using method_missing. + # Therefore, if `Object#send` is defined, `Object#send` will be given priority over the JavaScript `send` method. + # The same applies to the `respond_to_missing?` method. + # + # Please use `BasicObject#__send__` instead. + undef_method :send + # Call the receiver (a JavaScript function) with `undefined` as its receiver context. # This method is similar to JS::Object#call, but it is used to call a function that is not # a method of an object. diff --git a/packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb b/packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb index 84b2885552..8ccbc517bd 100644 --- a/packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb +++ b/packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb @@ -290,6 +290,13 @@ def test_method_missing assert_equal "o", JS.eval("return 'hello';").charAt(4).to_s end + def test_method_missing_for_send_method + object = JS.eval(<<~JS) + return { send(message) { return message; } }; + JS + assert_equal "hello", object.send('hello').to_s + end + def test_method_missing_with_block obj = JS.eval(<<~JS) return { @@ -351,6 +358,7 @@ def test_respond_to_missing? assert_true object.respond_to?(:foo) assert_true object.respond_to?(:new) assert_false object.respond_to?(:bar) + assert_false object.respond_to?(:send) end def test_member_get From b9695d4a8311c4cff88a8d22cf048fc0369b0e09 Mon Sep 17 00:00:00 2001 From: ledsun Date: Sat, 24 Aug 2024 14:04:22 +0900 Subject: [PATCH 2/2] Override the `Object#send` to give priority to `send` method of JavaScript It is too much to undefine the conventional methods in order to enable short-hand methods. --- packages/gems/js/lib/js.rb | 25 +++++++++++++------ .../ruby-wasm-wasi/test/unit/test_object.rb | 22 ++++++++++------ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/packages/gems/js/lib/js.rb b/packages/gems/js/lib/js.rb index 81c679641a..79a77fe493 100644 --- a/packages/gems/js/lib/js.rb +++ b/packages/gems/js/lib/js.rb @@ -195,15 +195,26 @@ def respond_to_missing?(sym, include_private) self[sym].typeof == "function" end - # To call the JavaScript `send` method and to check whether the `send` method exists, delete the definition of `Object#send`. + # Override the `Object#send` to give priority to `send` method of JavaScript. # - # For example, the JavaScript `WebSocket` and `XMLHttpRequest` have a `send` method. - # The JavaScript method call short-hand in JS::Object is implemented using method_missing. - # Therefore, if `Object#send` is defined, `Object#send` will be given priority over the JavaScript `send` method. - # The same applies to the `respond_to_missing?` method. + # This is to make it easier to use JavaScript Objects with `send` method such as `WebSocket` and `XMLHttpRequest`. + # The JavaScript method call short-hand in `JS::Object` is implemented using `method_missing`. + # Therefore, `Object#send` takes precedence over the JavaScript `send` method. + # If you want to call the JavaScript `send` method, you must use the `call` method as follows: # - # Please use `BasicObject#__send__` instead. - undef_method :send + # ws = JS.global[:WebSocket].new("ws://example.com") + # ws.call(:send, ["Hello, world! from Ruby"]) + # + # This method allows you to call the JavaScript `send` method with the following syntax: + # + # ws.send("Hello, world! from Ruby") + def send(name, *args) + if(self[:send].typeof == "function") + self.call(:send, [name, *args].to_js) + else + super + end + end # Call the receiver (a JavaScript function) with `undefined` as its receiver context. # This method is similar to JS::Object#call, but it is used to call a function that is not diff --git a/packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb b/packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb index 8ccbc517bd..5044ca40a0 100644 --- a/packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb +++ b/packages/npm-packages/ruby-wasm-wasi/test/unit/test_object.rb @@ -290,13 +290,6 @@ def test_method_missing assert_equal "o", JS.eval("return 'hello';").charAt(4).to_s end - def test_method_missing_for_send_method - object = JS.eval(<<~JS) - return { send(message) { return message; } }; - JS - assert_equal "hello", object.send('hello').to_s - end - def test_method_missing_with_block obj = JS.eval(<<~JS) return { @@ -358,7 +351,20 @@ def test_respond_to_missing? assert_true object.respond_to?(:foo) assert_true object.respond_to?(:new) assert_false object.respond_to?(:bar) - assert_false object.respond_to?(:send) + end + + def test_send_method_for_javascript_object_with_send_method + object = JS.eval(<<~JS) + return { send(message) { return message; } }; + JS + assert_equal "hello", object.send('hello').to_s + end + + def test_send_method_for_javascript_object_without_send_method + object = JS.eval(<<~JS) + return { write(message) { return message; } }; + JS + assert_equal "hello", object.send(:write, 'hello').to_s end def test_member_get