@@ -125,7 +125,23 @@ def self.__async(future, &block)
125
125
end
126
126
end
127
127
128
- class JS ::Object
128
+ # Inherit BasicObject to prevent define coventional menthods. #Override the `Object#send` to give priority to `send` method of JavaScript.
129
+ #
130
+ # This is to make it easier to use JavaScript Objects with `send` method such as `WebSocket` and `XMLHttpRequest`.
131
+ # The JavaScript method call short-hand in `JS::Object` is implemented using `method_missing`.
132
+ # If JS::Object inherits from Object, the `send` method defined in Ruby will take precedence over the JavaScript `send` method.
133
+ # If you want to call the JavaScript `send` method, you must use the `call` method as follows:
134
+ #
135
+ # ws = JS.global[:WebSocket].new("ws://example.com")
136
+ # ws.call(:send, ["Hello, world! from Ruby"])
137
+ #
138
+ # This inheritation allows you to call the JavaScript `send` method with the following syntax:
139
+ #
140
+ # ws.send("Hello, world! from Ruby")
141
+
142
+
143
+
144
+ class JS ::Object < BasicObject
129
145
# Create a JavaScript object with the new method
130
146
#
131
147
# The below examples show typical usage in Ruby
@@ -141,16 +157,16 @@ class JS::Object
141
157
#
142
158
def new ( *args , &block )
143
159
args = args + [ block ] if block
144
- JS . global [ :Reflect ] . construct ( self , args . to_js )
160
+ :: JS . global [ :Reflect ] . construct ( self , args . to_js )
145
161
end
146
162
147
163
# Converts +self+ to an Array:
148
164
#
149
165
# JS.eval("return [1, 2, 3]").to_a.map(&:to_i) # => [1, 2, 3]
150
166
# JS.global[:document].querySelectorAll("p").to_a # => [[object HTMLParagraphElement], ...
151
167
def to_a
152
- as_array = JS . global [ :Array ] . from ( self )
153
- Array . new ( as_array [ :length ] . to_i ) { as_array [ _1 ] }
168
+ as_array = :: JS . global [ :Array ] . from ( self )
169
+ :: Array . new ( as_array [ :length ] . to_i ) { as_array [ _1 ] }
154
170
end
155
171
156
172
# Provide a shorthand form for JS::Object#call
@@ -176,7 +192,7 @@ def method_missing(sym, *args, &block)
176
192
result = invoke_js_method ( sym_str [ 0 ..-2 ] . to_sym , *args , &block )
177
193
# Type coerce the result to boolean type
178
194
# to match the true/false determination in JavaScript's if statement.
179
- return JS . global . Boolean ( result ) == JS ::True
195
+ return :: JS . global . Boolean ( result ) == :: JS ::True
180
196
end
181
197
182
198
invoke_js_method ( sym , *args , &block )
@@ -186,7 +202,6 @@ def method_missing(sym, *args, &block)
186
202
#
187
203
# See JS::Object#method_missing for details.
188
204
def respond_to_missing? ( sym , include_private )
189
- return true if super
190
205
sym_str = sym . to_s
191
206
sym = sym_str [ 0 ..-2 ] . to_sym if sym_str . end_with? ( "?" )
192
207
self [ sym ] . typeof == "function"
@@ -203,7 +218,7 @@ def respond_to_missing?(sym, include_private)
203
218
# end.await # => 42
204
219
def apply ( *args , &block )
205
220
args = args + [ block ] if block
206
- JS . global [ :Reflect ] . call ( :apply , self , JS ::Undefined , args . to_js )
221
+ :: JS . global [ :Reflect ] . call ( :apply , self , :: JS ::Undefined , args . to_js )
207
222
end
208
223
209
224
# Await a JavaScript Promise like `await` in JavaScript.
@@ -233,8 +248,13 @@ def apply(*args, &block)
233
248
# JS.eval("return new Promise((ok, err) => err(new Error())").await # => raises JS::Error
234
249
def await
235
250
# Promise.resolve wrap a value or flattens promise-like object and its thenable chain
236
- promise = JS . global [ :Promise ] . resolve ( self )
237
- JS . promise_scheduler . await ( promise )
251
+ promise = ::JS . global [ :Promise ] . resolve ( self )
252
+ ::JS . promise_scheduler . await ( promise )
253
+ end
254
+
255
+ # https://github.com/rails/rails/blob/5c0b7496ab32c25c80f6d1bdc8b32ec6f75ce1e4/activerecord/lib/active_record/promise.rb#L40-L42
256
+ [ :nil? , :is_a? ] . each do |method |
257
+ define_method ( method , ::Object . instance_method ( method ) )
238
258
end
239
259
240
260
private
@@ -246,12 +266,12 @@ def invoke_js_method(sym, *args, &block)
246
266
return self . call ( sym , *args , &block ) if self [ sym ] . typeof == "function"
247
267
248
268
# Check to see if a non-functional property exists.
249
- if JS . global [ :Reflect ] . call ( :has , self , sym . to_s ) == JS ::True
250
- raise TypeError ,
269
+ if :: JS . global [ :Reflect ] . call ( :has , self , sym . to_s ) == :: JS ::True
270
+ raise :: TypeError ,
251
271
"`#{ sym } ` is not a function. To reference a property, use `[:#{ sym } ]` syntax instead."
252
272
end
253
273
254
- raise NoMethodError ,
274
+ raise :: NoMethodError ,
255
275
"undefined method `#{ sym } ' for an instance of JS::Object"
256
276
end
257
277
end
0 commit comments