@@ -173,16 +173,13 @@ def method_missing(sym, *args, &block)
173
173
if sym_str . end_with? ( "?" )
174
174
# When a JS method is called with a ? suffix, it is treated as a predicate method,
175
175
# and the return value is converted to a Ruby boolean value automatically.
176
- result = self . call ( sym_str [ 0 ..-2 ] . to_sym , *args , &block )
177
-
176
+ result = invoke_js_method ( sym_str [ 0 ..-2 ] . to_sym , *args , &block )
178
177
# Type coerce the result to boolean type
179
178
# to match the true/false determination in JavaScript's if statement.
180
- JS . global . Boolean ( result ) == JS ::True
181
- elsif self [ sym ] . typeof == "function"
182
- self . call ( sym , *args , &block )
183
- else
184
- super
179
+ return JS . global . Boolean ( result ) == JS ::True
185
180
end
181
+
182
+ invoke_js_method ( sym , *args , &block )
186
183
end
187
184
188
185
# Check if a JavaScript method exists
@@ -195,10 +192,10 @@ def respond_to_missing?(sym, include_private)
195
192
self [ sym ] . typeof == "function"
196
193
end
197
194
198
- # Call the receiver (a JavaScript function) with `undefined` as its receiver context.
195
+ # Call the receiver (a JavaScript function) with `undefined` as its receiver context.
199
196
# This method is similar to JS::Object#call, but it is used to call a function that is not
200
197
# a method of an object.
201
- #
198
+ #
202
199
# floor = JS.global[:Math][:floor]
203
200
# floor.apply(3.14) # => 3
204
201
# JS.global[:Promise].new do |resolve, reject|
@@ -239,6 +236,24 @@ def await
239
236
promise = JS . global [ :Promise ] . resolve ( self )
240
237
JS . promise_scheduler . await ( promise )
241
238
end
239
+
240
+ private
241
+
242
+ # Invoke a JavaScript method
243
+ # If the property of JavaScritp object does not exist, raise a `NoMethodError`.
244
+ # If the property exists but is not a function, raise a `TypeError`.
245
+ def invoke_js_method ( sym , *args , &block )
246
+ return self . call ( sym , *args , &block ) if self [ sym ] . typeof == "function"
247
+
248
+ # 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 ,
251
+ "`#{ sym } ` is not a function. To reference a property, use `[:#{ sym } ]` syntax instead."
252
+ end
253
+
254
+ raise NoMethodError ,
255
+ "undefined method `#{ sym } ' for an instance of JS::Object"
256
+ end
242
257
end
243
258
244
259
# A wrapper class for JavaScript Error to allow the Error to be thrown in Ruby.
0 commit comments