From 112c1afa50801a9ca7fd769abd81313847507a93 Mon Sep 17 00:00:00 2001 From: kares Date: Sat, 21 Apr 2012 19:56:05 +0200 Subject: [PATCH] do not access internal JS names from Ruby + exclude [] & []= methods (RedJS 0.4 compatibility) --- Gemfile | 2 +- lib/rhino/ruby.rb | 85 ++++++++++++++++++++++++---------------- lib/rhino/ruby/access.rb | 19 +++++++-- spec/rhino/redjs_spec.rb | 14 +++++++ 4 files changed, 82 insertions(+), 38 deletions(-) diff --git a/Gemfile b/Gemfile index f9c19ef..8acda04 100644 --- a/Gemfile +++ b/Gemfile @@ -2,4 +2,4 @@ source :rubygems gemspec -gem 'redjs', :git => 'git://github.com/cowboyd/redjs.git', :tag => "0.3.0", :group => :test +gem 'redjs', :git => 'git://github.com/cowboyd/redjs.git', :branch => "0.4", :group => :test diff --git a/lib/rhino/ruby.rb b/lib/rhino/ruby.rb index f25742d..e874845 100644 --- a/lib/rhino/ruby.rb +++ b/lib/rhino/ruby.rb @@ -5,38 +5,7 @@ module Rhino # shared JS::Scriptable implementation module Scriptable - # override Object Scriptable#get(String name, Scriptable start); - # override Object Scriptable#get(int index, Scriptable start); - def get(name, start) - access.get(unwrap, name, self) { super } - end - - # override boolean Scriptable#has(String name, Scriptable start); - # override boolean Scriptable#has(int index, Scriptable start); - def has(name, start) - access.has(unwrap, name, self) { 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) - access.put(unwrap, name, value) { super } - end - - # override Object[] Scriptable#getIds(); - def getIds - ids = [] - unwrap.public_methods(false).each do |name| - name = name[0...-1] if name[-1, 1] == '=' # 'foo=' ... 'foo' - name = name.to_s.to_java # java.lang.String - ids << name unless ids.include?(name) - end - super.each { |id| ids.unshift(id) } - ids.to_java - end - @@access = nil - def self.access=(access) @@access = ( access.respond_to?(:get) && access.respond_to?(:put) ) ? access : begin @@ -61,11 +30,61 @@ module Rhino @@access ||= Ruby::DefaultAccess.new end + # override Object Scriptable#get(String name, Scriptable start); + # override Object Scriptable#get(int index, Scriptable start); + def get(name, start) + return nil if exclude?(name) + access.get(unwrap, name, self) { super } + end + + # override boolean Scriptable#has(String name, Scriptable start); + # override boolean Scriptable#has(int index, Scriptable start); + def has(name, start) + return nil if exclude?(name) + access.has(unwrap, name, self) { 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) + return nil if exclude?(name) + access.put(unwrap, name, value) { super } + end + + # override Object[] Scriptable#getIds(); + def getIds + ids = [] + unwrap.public_methods(false).each do |name| + next unless name = convert(name) + name = name.to_s.to_java # java.lang.String + ids << name unless ids.include?(name) + end + super.each { |id| ids.unshift(id) } + ids.to_java + end + private - def access - Scriptable.access + def convert(name) + if exclude?(name) + nil + elsif name[-1, 1] == '=' + name[0...-1] + else + name end + end + + FETCH = '[]'.freeze + STORE = '[]='.freeze + + def exclude?(name) + name == FETCH || name == STORE + end + + def access + Scriptable.access + end end diff --git a/lib/rhino/ruby/access.rb b/lib/rhino/ruby/access.rb index 698af4e..6b0596a 100644 --- a/lib/rhino/ruby/access.rb +++ b/lib/rhino/ruby/access.rb @@ -9,8 +9,10 @@ module Rhino def has(object, name, scope) # try [](name) method : if object.respond_to?(:'[]') && object.method(:'[]').arity == 1 - value = object.[](name) { return true } - return true unless value.nil? + unless internal?(name) + value = object.[](name) { return true } + return true unless value.nil? + end end yield end @@ -22,7 +24,7 @@ module Rhino object[name] rescue LocalJumpError nil - end + end unless internal?(name) return Rhino.to_javascript(value, scope) unless value.nil? end yield @@ -35,11 +37,20 @@ module Rhino begin return object[name] = rb_value rescue LocalJumpError - end + end unless internal?(name) end yield end + private + + UNDERSCORES = '__'.freeze + + def internal?(name) # e.g. '__iterator__', '__proto__' + name.is_a?(String) && + name[0..1] == UNDERSCORES && name[-2..-1] == UNDERSCORES + end + end module DeprecatedAccess diff --git a/spec/rhino/redjs_spec.rb b/spec/rhino/redjs_spec.rb index 129c1c5..493c231 100644 --- a/spec/rhino/redjs_spec.rb +++ b/spec/rhino/redjs_spec.rb @@ -8,4 +8,18 @@ describe Rhino::Context do it_behaves_like 'RedJS::Context' + it "keeps objects iterable when property accessor is provided" do + klass = Class.new do + def [](name); name; end + attr_accessor :foo + def bar=(bar); bar; end + end + + RedJS::Context.new do |cxt| + cxt['o'] = klass.new + cxt.eval('a = new Array(); for (var i in o) a.push(i);') + cxt['a'].length.should == 2 # [ 'foo', 'bar' ] + end + end + end \ No newline at end of file