Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undefine Object#send method to call JavaScript send method #509

Closed
wants to merge 2 commits into from

Conversation

ledsun
Copy link
Contributor

@ledsun ledsun commented Aug 18, 2024

Background

The following ruby.wasm code will cause an error.

ws = JS.global[:WebSocket].new("ws://localhost:9292")
ws[:onopen] = -> (event) {
  ws.send("Hello")
}
Error: /bundle/gems/js-2.6.2/lib/js.rb:184:in `method_missing': undefined method `Hello' for an instance of JS::Object (NoMethodError)

This error is caused by the Object#send method being called instead of the send method of the JavaScript WebSocket object.

Currently, we can use the send method by using the call method as follows.

ws.call(:send, ["Hello"])

Goal

Enable to call the JavaScript send method with the following syntax:

ws.send("Hello, world! from Ruby")

Solution

1st approch

Undef Object#send method.
But, this is too much change to enable short-hand methods.

2nd approch

Overirde Object#send method.
Then, it checks whether the JavaScript object has a send method and changes its behavior.

@kateinoigakukun
Copy link
Member

kateinoigakukun commented Aug 19, 2024

Given that method_missing API is just a shorthand of JS::Object#call, it might be too much to undefine such conventional methods. Could you collect some case studies on how other similar method_missing users (e.g. ActiveRecord, PyCall.rb, etc...) address this kind of name conflict?

…cript

It is too much to undefine the conventional methods in order to enable short-hand methods.
@ledsun
Copy link
Contributor Author

ledsun commented Aug 24, 2024

I have collected case studies.

In ActiveRecord, the send column is defined as a method using define_attribute_methods. In other words, the Object#send method is overridden.

In PyCall, if there is a name conflict with the send method, the Object#send method is given priority. To call the send method of a Python object, use PyColl.getattr as follows.

require 'pycall'
client = PyCall.import_module 'http.client'
conn = client.HTTPConnection.new('www.example.com')
PyCall.getattr(conn, 'send').("GET / HTTP/1.0\r\n\r\n".b)

I like the way Rails does it. So I defined the JS::Object#send method.

@ledsun ledsun marked this pull request as ready for review August 24, 2024 05:33
@kateinoigakukun
Copy link
Member

kateinoigakukun commented Aug 29, 2024

Sorry for my late response. I have been thinking about this, how about inheriting BasicObject instead of Object? If we do that, we don't need to care about most of conventional methods (not only for send) except for a few like __send__.
It slightly breaks API compatibility but shouldn't be a big deal considering its use cases.

@ledsun
Copy link
Contributor Author

ledsun commented Aug 30, 2024

how about inheriting BasicObject instead of Object?

I think it's an interesting idea. I'll try to see how it's implemented.

@ledsun
Copy link
Contributor Author

ledsun commented Sep 7, 2024

It looks like it can be successfully implemented by inheriting the BasicObject.
I will create a new pull request with a new implementation.

I close this pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants