-
-
Notifications
You must be signed in to change notification settings - Fork 942
Description
There appears to be a regression in how we handle method lookup and monkey-patching of Java classes.
The following script produces an arity error when run with JRuby master (9.2.1) and current execjs and therubyrhino:
require 'execjs'
src = <<JS
;function compile(script, options) {
function (a, b) {}
}
JS
func = ExecJS.compile(src)
func.call("compile", 1, 2) # errorAnd the output:
$ jruby asdf.rb
ArgumentError: wrong number of arguments (2 for 4)
call at /Users/headius/projects/jruby/lib/ruby/gems/shared/gems/execjs-2.7.0/lib/execjs/ruby_rhino_runtime.rb:39
<main> at asdf.rb:13
This pattern originates from the coffee-script gem, which uses JS similar to the above to call the coffeescript compiler and return a function. The func.call line invokes the compile function defined above, which returns another anonymous function.
That anonymous function is from Rhino, of Java types InterpretedFunction. InterpretedFunction does define a 4-arity call method, but it is originally declared two classes higher in the hierarchy, at BaseFunction. BaseFunction gets patched by TheRubyRhino to have a different version of call:
lib/rhino/rhino_ext.rb from therubyrhino
...
# The base class for all JavaScript function objects.
class Java::OrgMozillaJavascript::BaseFunction
# Object call(Context context, Scriptable scope, Scriptable this, Object[] args)
alias_method :__call__, :call
# make JavaScript functions callable Ruby style e.g. `fn.call('42')`
#
# NOTE: That invoking #call does not have the same semantics as
# JavaScript's Function#call but rather as Ruby's Method#call !
# Use #apply or #bind before calling to achieve the same effect.
def call(*args)
context = Rhino::JS::Context.enter; scope = current_scope(context)
# calling as a (var) stored function - no this === undefined "use strict"
# TODO can't pass Undefined.instance as this - it's not a Scriptable !?
this = Rhino::JS::ScriptRuntime.getGlobal(context)
js_args = Rhino.args_to_javascript(args, scope)
Rhino.to_ruby __call__(context, scope, this, js_args)
rescue Rhino::JS::JavaScriptException => e
raise Rhino::JSError.new(e)
ensure
Rhino::JS::Context.exit
end
...It appears this replaced call method is getting wiped out or otherwise ignored when calling against Java descendants of BaseFunction like InterpretedFunction.