module V8 class Portal class Interceptors def initialize(portal) @portal @getter = NamedPropertyGetter.new(portal) @setter = NamedPropertySetter.new(portal) @query = nil @deleter = nil @enumerator = NamedPropertyEnumerator.new(portal) @igetter = IndexedPropertyGetter.new(portal) @isetter = IndexedPropertySetter.new(portal) @iquery = nil @ideleter = nil @ienumerator = IndexedPropertyEnumerator.new(portal) end def setup(template) template.SetNamedPropertyHandler(@getter,@setter,@query,@deleter,@enumerator) template.SetIndexedPropertyHandler(@igetter,@isetter,@iquery,@ideleter,@ienumerator) end class PropertyAttributes attr_reader :flags def initialize @flags = 0 end def read_only tap do @flags |= V8::C::ReadOnly end end def dont_enum tap do @flags |= V8::C::DontEnum end end def dont_delete tap do @flags |= V8::C::DontDelete end end end class Interceptor def initialize(portal) @to, @access = portal, portal.access end def intercept(info, retval = nil, &code) obj = @to.rb(info.This()) intercepts = true result = @to.rubyprotect do dontintercept = proc do intercepts = false end code.call(obj, dontintercept) end intercepts ? (retval || result) : C::Empty end end class NamedPropertyGetter < Interceptor def call(property, info) intercept(info) do |obj, dontintercept| @access.get(obj, @to.rb(property), &dontintercept) end end end class NamedPropertySetter < Interceptor def call(property, value, info) intercept(info, value) do |obj, dontintercept| @access.set(obj, @to.rb(property), @to.rb(value), &dontintercept) end end end class NamedPropertyQuery def call(property, info) attributes = PropertyAttributes.new result = intercept(info) do |obj, dontintercept| @access.query(obj, @to.rb(property), attributes, &dontintercept) end return result == C::Empty ? result : C::Integer::New(attributes.flags) end end class NamedPropertyEnumerator < Interceptor def call(info) intercept(info) do |obj, dontintercept| @access.names(obj, &dontintercept).to_a end end end class NamedPropertyDeleter < Interceptor def call(property, info) intercept(info) do |obj, dontintercept| @access.delete(obj, property, &dontintercept) end end end class IndexedPropertyGetter < Interceptor def call(index, info) intercept(info) do |obj, dontintercept| @access.iget(obj, index, &dontintercept) end end end class IndexedPropertySetter < Interceptor def call(index, value, info) intercept(info, value) do |obj, dontintercept| @access.iset(obj, index, @to.rb(value), &dontintercept) end end end class IndexedPropertyQuery < Interceptor def call(property, info) attributes = PropertyAttributes.new result = intercept(info) do |obj, dontintercept| @access.indices(obj, &dontintercept) end result == C::Empty ? C::Empty : C::Integer::New(attributes.flags) end end class IndexedPropertyDeleter < Interceptor def call(index, info) intercept(info) do |obj, dontintercept| @access.idelete(obj, index, &dontintercept) end end end class IndexedPropertyEnumerator < Interceptor def call(info) intercept(info) do |obj, dontintercept| @access.indices(obj, &dontintercept) end end end end end end