diff --git a/packages/gems/js/lib/js.rb b/packages/gems/js/lib/js.rb index cbf1074485..9a3fcaf584 100644 --- a/packages/gems/js/lib/js.rb +++ b/packages/gems/js/lib/js.rb @@ -189,6 +189,20 @@ def respond_to_missing?(sym, include_private) self[sym].typeof == "function" 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 + # a method of an object. + # + # floor = JS.global[:Math][:floor] + # floor.apply(3.14) # => 3 + # JS.global[:Promise].new do |resolve, reject| + # resolve.apply(42) + # end.await # => 42 + def apply(*args, &block) + args = args + [block] if block + JS.global[:Reflect].call(:apply, self, JS::Undefined, args.to_js) + end + # Await a JavaScript Promise like `await` in JavaScript. # This method looks like a synchronous method, but it actually runs asynchronously using fibers. # In other words, the next line to the `await` call at Ruby source will be executed after the 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 5fb77c8e21..ba18ea46b9 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 @@ -357,4 +357,13 @@ def test_member_set_with_stress_gc JS.global[:tmp] = "1" GC.stress = false end + + def test_apply + object = JS.eval(<<~JS) + return { foo(a, b, c) { return a + b + c; } }; + JS + assert_equal 6, object[:foo].apply(1, 2, 3).to_i + floor = JS.global[:Math][:floor] + assert_equal 3, floor.apply(3.14).to_i + end end