mirror of
https://github.com/rubyjs/therubyrhino
synced 2023-03-27 23:21:34 -04:00
174 lines
4.5 KiB
Ruby
174 lines
4.5 KiB
Ruby
|
|
||
|
module Rhino
|
||
|
|
||
|
class RubyObject < JS::ScriptableObject
|
||
|
include JS::Wrapper
|
||
|
|
||
|
# wrap an arbitrary (ruby) object
|
||
|
def self.wrap(object)
|
||
|
new(object)
|
||
|
end
|
||
|
|
||
|
def initialize(object)
|
||
|
super()
|
||
|
@ruby = object
|
||
|
end
|
||
|
|
||
|
# abstract Object Wrapper#unwrap();
|
||
|
def unwrap
|
||
|
@ruby
|
||
|
end
|
||
|
|
||
|
# abstract String Scriptable#getClassName();
|
||
|
def getClassName
|
||
|
@ruby.class.name
|
||
|
end
|
||
|
|
||
|
def toString
|
||
|
"[ruby #{getClassName}]" # [object User]
|
||
|
end
|
||
|
|
||
|
# override Object Scriptable#get(String name, Scriptable start);
|
||
|
# override Object Scriptable#get(int index, Scriptable start);
|
||
|
def get(name, start)
|
||
|
if name.is_a?(String)
|
||
|
if @ruby.respond_to?(name)
|
||
|
method = @ruby.method(name)
|
||
|
if method.arity == 0 && # check if it is an attr_reader
|
||
|
( @ruby.respond_to?("#{name}=") || @ruby.instance_variables.include?("@#{name}") )
|
||
|
begin
|
||
|
return Rhino.to_javascript(method.call, self)
|
||
|
rescue => e
|
||
|
raise RubyFunction.wrap_error(e)
|
||
|
end
|
||
|
else
|
||
|
return RubyFunction.new(@ruby.method(name))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
super
|
||
|
end
|
||
|
|
||
|
# override boolean Scriptable#has(String name, Scriptable start);
|
||
|
# override boolean Scriptable#has(int index, Scriptable start);
|
||
|
def has(name, start)
|
||
|
if name.is_a?(String)
|
||
|
if @ruby.respond_to?(name) ||
|
||
|
@ruby.respond_to?("#{name}=") # might have a writer but no reader
|
||
|
return true
|
||
|
end
|
||
|
end
|
||
|
super
|
||
|
end
|
||
|
|
||
|
# override void Scriptable#put(String name, Scriptable start, Object value);
|
||
|
# override void Scriptable#put(int index, Scriptable start, Object value);
|
||
|
def put(name, start, value)
|
||
|
if name.is_a?(String)
|
||
|
if @ruby.respond_to?(set_name = "#{name}=")
|
||
|
return @ruby.send(set_name, Rhino.to_ruby(value))
|
||
|
end
|
||
|
end
|
||
|
super
|
||
|
end
|
||
|
|
||
|
# override Object[] Scriptable#getIds();
|
||
|
def getIds
|
||
|
ids = []
|
||
|
@ruby.public_methods(false).each do |name|
|
||
|
name = name[0...-1] if name[-1, 1] == '=' # 'foo=' ... 'foo'
|
||
|
name = name.to_java # java.lang.String
|
||
|
ids << name unless ids.include?(name)
|
||
|
end
|
||
|
super.each { |id| ids.unshift(id) }
|
||
|
ids.to_java
|
||
|
end
|
||
|
|
||
|
# protected Object ScriptableObject#equivalentValues(Object value)
|
||
|
def equivalentValues(other) # JS == operator
|
||
|
other.is_a?(RubyObject) && unwrap.eql?(other.unwrap)
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
class RubyFunction < JS::BaseFunction
|
||
|
|
||
|
# wrap a callable (Method/Proc)
|
||
|
def self.wrap(callable)
|
||
|
new(callable)
|
||
|
end
|
||
|
|
||
|
def self.wrap_error(e)
|
||
|
JS::WrappedException.new(org.jruby.exceptions.RaiseException.new(e))
|
||
|
end
|
||
|
|
||
|
def initialize(callable)
|
||
|
super()
|
||
|
@callable = callable
|
||
|
end
|
||
|
|
||
|
def unwrap
|
||
|
@callable
|
||
|
end
|
||
|
|
||
|
# protected Object ScriptableObject#equivalentValues(Object value)
|
||
|
def equivalentValues(other) # JS == operator
|
||
|
return false unless other.is_a?(RubyFunction)
|
||
|
return true if unwrap == other.unwrap
|
||
|
# Method.== does check if their bind to the same object
|
||
|
# JS == means they might be bind to different objects :
|
||
|
unwrap.to_s == other.unwrap.to_s # "#<Method: Foo#bar>"
|
||
|
end
|
||
|
|
||
|
# override Object ScriptableObject#getPrototype()
|
||
|
def getPrototype
|
||
|
unless proto = super
|
||
|
#proto = ScriptableObject.getFunctionPrototype(getParentScope)
|
||
|
#setPrototype(proto)
|
||
|
end
|
||
|
proto
|
||
|
end
|
||
|
|
||
|
# override Object BaseFunction#call(Context context, Scriptable scope,
|
||
|
# Scriptable thisObj, Object[] args)
|
||
|
def call(context, scope, this, args)
|
||
|
rb_args = Rhino.args_to_ruby(args.to_a)
|
||
|
begin
|
||
|
result = @callable.call(*rb_args)
|
||
|
rescue => e
|
||
|
# ... correct wrapping thus it's try { } catch (e) works in JS :
|
||
|
raise self.class.wrap_error(e)
|
||
|
end
|
||
|
Rhino.to_javascript(result, scope)
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
class RubyConstructor < RubyFunction
|
||
|
include JS::Wrapper
|
||
|
|
||
|
# wrap a ruby class as as constructor function
|
||
|
def self.wrap(klass)
|
||
|
new(klass)
|
||
|
end
|
||
|
|
||
|
def initialize(klass)
|
||
|
super(klass.method(:new))
|
||
|
@klass = klass
|
||
|
end
|
||
|
|
||
|
def unwrap
|
||
|
@klass
|
||
|
end
|
||
|
|
||
|
# override boolean Scriptable#hasInstance(Scriptable instance);
|
||
|
def hasInstance(instance)
|
||
|
return false unless instance
|
||
|
return true if instance.is_a?(@klass)
|
||
|
instance.is_a?(RubyObject) && instance.unwrap.is_a?(@klass)
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
end
|