lib/v8/access.rb in therubyracer-0.7.5 vs lib/v8/access.rb in therubyracer-0.8.0.pre

- old
+ new

@@ -1,202 +1,87 @@ require 'set' module V8 - - #TODO each context should get its own access rules instead of sharing them across - # contetxts - ###### --cowboyd 07/07/2010 class Access - def self.[](cls) - @access ||= Access.new - @access[cls] - end - - def initialize - @classes = {} - end - - def [](cls) - @classes ||= {} - if ref = @classes[cls.object_id] - if ref.weakref_alive? - ref.__getobj__ - else - @classes.delete(cls.object_id) - self[cls] - end + def get(obj, name, &dontintercept) + methods = accessible_methods(obj) + if methods.include?(name) + method = obj.method(name) + method.arity == 0 ? method.call : method.unbind + elsif obj.respond_to?(:[]) + obj.send(:[], name, &dontintercept) else - template(cls).tap do |t| - Access.setuptemplate(t.InstanceTemplate()) - if cls.name && cls.name =~ /(::)?(\w+?)$/ - t.SetClassName(C::String::NewSymbol("rb::" + $2)) - else - t.SetClassName("Ruby") - end - @classes[cls.object_id] = WeakRef.new(t) - end + yield end end - def template(cls) - C::FunctionTemplate::New() do |arguments| - unless arguments.Length() == 1 && arguments[0].kind_of?(C::External) - C::ThrowException(C::Exception::Error(C::String::New("cannot call native constructor from javascript"))) - else - arguments.This().tap do |this| - this.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), arguments[0]) - end - end + def iget(obj, index, &dontintercept) + if obj.respond_to?(:[]) + obj.send(:[], index, &dontintercept) + else + yield end end - def self.rubyobject - @rubyobject ||= C::ObjectTemplate::New().tap do |t| - setuptemplate(t) + def set(obj, name, value, &dontintercept) + setter = name + "=" + methods = accessible_methods(obj, true) + if methods.include?(setter) + obj.send(setter, value) + elsif obj.respond_to?(:[]=) + obj.send(:[]=, name, value, &dontintercept) + else + yield end end - def self.setuptemplate(t) - t.SetNamedPropertyHandler( - NamedPropertyGetter, - NamedPropertySetter, - nil, - nil, - NamedPropertyEnumerator - ) - t.SetIndexedPropertyHandler( - IndexedPropertyGetter, - IndexedPropertySetter, - nil, - nil, - IndexedPropertyEnumerator - ) - end - end - - class Constructors < Access - def self.[](cls) - Access[cls].tap do |template| - template.SetCallHandler() do |arguments| - wrap = nil - if arguments.Length() > 0 && arguments[0].kind_of?(C::External) - wrap = arguments[0] - else - rbargs = [] - for i in 0..arguments.Length() - 1 - rbargs << To.rb(arguments[i]) - end - instance = V8::Function.rubysend(cls, :new, *rbargs) - wrap = C::External::New(instance) - end - arguments.This().tap do |this| - this.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), wrap) - end - end + def iset(obj, index, value, &dontintercept) + if obj.respond_to?(:[]=) + obj.send(:[]=, index, value, &dontintercept) + else + yield end end - end - module AccessibleMethods - def accessible_methods(obj) - obj.public_methods(false).map {|m| m.to_s}.to_set.tap do |methods| - ancestors = obj.class.ancestors.dup - while ancestor = ancestors.shift - break if ancestor == ::Object - methods.merge(ancestor.public_instance_methods(false).map {|m| m.to_s}) + def query(obj, name, attributes) + if obj.respond_to?(name) + attributes.dont_delete + unless obj.respond_to?(name + "=") + attributes.read_only end - methods.reject! {|m| m == "[]" || m == "[]="} + else + yield end end - end - class NamedPropertyGetter - extend AccessibleMethods - def self.call(property, info) - name = To.rb(property) - obj = To.rb(info.This()) - methods = accessible_methods(obj) - if methods.include?(name) - method = obj.method(name) - if method.arity == 0 - Function.rubycall(method) - else - To.v8(method) + def iquery(obj, index, attributes) + if obj.respond_to?(:[]) + attributes.dont_delete + unless obj.respond_to?(:[]=) + attributes.read_only end - elsif obj.respond_to?(:[]) - Function.rubysend(obj, :[], name) else - C::Empty + yield end end - end - class NamedPropertySetter - extend AccessibleMethods - def self.call(property, value, info) - obj = To.rb(info.This()) - name = To.rb(property) - setter = name + "=" - methods = accessible_methods(obj) - if methods.include?(setter) - Function.rubysend(obj, setter, To.rb(value)) - value - elsif obj.respond_to?(:[]=) - Function.rubysend(obj, :[]=, name, To.rb(value)) - value - else - C::Empty - end + def names(obj) + accessible_methods(obj) end - end - class NamedPropertyEnumerator - extend AccessibleMethods - def self.call(info) - obj = To.rb(info.This()) - methods = accessible_methods(obj).reject! {|m| m.to_s =~ /=$/} - names = V8::C::Array::New(methods.length) - methods.each_with_index do |name, i| - names.Set(i, C::String::New(name)) - end - return names + def indices(obj) + obj.respond_to?(:length) ? (0..obj.length).to_a : yield end - end - class IndexedPropertyGetter - def self.call(index, info) - obj = To.rb(info.This()) - if obj.respond_to?(:[]) - Function.rubysend(obj, :[], index) - else - C::Empty - end - end - end + private - class IndexedPropertySetter - def self.call(index, value, info) - obj = To.rb(info.This()) - if obj.respond_to?(:[]=) - Function.rubysend(obj, :[]=, index, To.rb(value)) - value - else - C::Empty - end - end - end - - class IndexedPropertyEnumerator - def self.call(info) - obj = To.rb(info.This()) - if obj.respond_to?(:length) - C::Array::New(obj.length).tap do |indices| - for index in 0..obj.length - 1 - rputs "index: #{index}" - indices.Set(index,index) - end + def accessible_methods(obj, special_methods = false) + obj.public_methods(false).map {|m| m.to_s}.to_set.tap do |methods| + ancestors = obj.class.ancestors.dup + while ancestor = ancestors.shift + break if ancestor == ::Object + methods.merge(ancestor.public_instance_methods(false).map {|m| m.to_s}) end - else - C::Array::New() + methods.reject! {|m| m == "[]" || m == "[]=" || m =~ /=$/} unless special_methods end end end -end +end \ No newline at end of file