therubyracer 0.7.5 → 0.8.0.pre

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of therubyracer might be problematic. Click here for more details.

@@ -3,9 +3,9 @@ module V8
3
3
  class Array < V8::Object
4
4
 
5
5
  def each
6
- @context.enter do
6
+ @portal.open do |to|
7
7
  for i in 0..(@native.Length() - 1)
8
- yield To.rb(@native.Get(i))
8
+ yield to.rb(@native.Get(i))
9
9
  end
10
10
  end
11
11
  end
@@ -2,12 +2,14 @@ require 'stringio'
2
2
 
3
3
  module V8
4
4
  class Context
5
- attr_reader :native, :scope
5
+ attr_reader :native, :scope, :access
6
6
  def initialize(opts = {})
7
- @native = opts[:with] ? C::Context::New(Access.rubyobject) : C::Context::New()
7
+ @access = Access.new
8
+ @to = Portal.new(self, @access)
9
+ @native = opts[:with] ? C::Context::New(@to.rubytemplate) : C::Context::New()
8
10
  @native.enter do
11
+ @scope = @to.rb(@native.Global())
9
12
  @native.Global().SetHiddenValue(C::String::New("TheRubyRacer::RubyObject"), C::External::New(opts[:with])) if opts[:with]
10
- @scope = To.rb(@native.Global())
11
13
  end
12
14
  yield(self) if block_given?
13
15
  end
@@ -20,15 +22,15 @@ module V8
20
22
  value = nil
21
23
  C::TryCatch.try do |try|
22
24
  @native.enter do
23
- script = C::Script::Compile(To.v8(javascript.to_s), To.v8(filename.to_s))
25
+ script = C::Script::Compile(@to.v8(javascript.to_s), @to.v8(filename.to_s))
24
26
  if try.HasCaught()
25
- err = JSError.new(try)
27
+ err = JSError.new(try, @to)
26
28
  else
27
29
  result = script.Run()
28
30
  if try.HasCaught()
29
- err = JSError.new(try)
31
+ err = JSError.new(try, @to)
30
32
  else
31
- value = To.rb(result)
33
+ value = @to.rb(result)
32
34
  end
33
35
  end
34
36
  end
@@ -3,7 +3,8 @@ module V8
3
3
  class JSError < StandardError
4
4
  attr_reader :value, :boundaries
5
5
 
6
- def initialize(try)
6
+ def initialize(try, to)
7
+ @to = to
7
8
  begin
8
9
  super(initialize_unsafe(try))
9
10
  rescue Exception => e
@@ -15,7 +16,7 @@ module V8
15
16
 
16
17
  def initialize_unsafe(try)
17
18
  message = nil
18
- ex = To.rb(try.Exception())
19
+ ex = @to.rb(try.Exception())
19
20
  @boundaries = [Boundary.new(:rbframes => caller(3), :jsframes => parse_js_frames(try))]
20
21
  if V8::Object === ex
21
22
  if msg = ex['message']
@@ -79,7 +80,7 @@ module V8
79
80
  end if trace_javascript
80
81
  rbcontext = b.rbframes
81
82
  jscontext = b.jsframes
82
- rbframes.reject! {|f| f =~ /lib\/v8\/\w+\.rb/} unless trace_framework
83
+ rbframes.reject! {|f| f =~ /lib\/v8\/.*\.rb/} unless trace_framework
83
84
  mixed.unshift(*rbframes) if trace_ruby
84
85
  mixed.unshift(*jsframes) if trace_javascript
85
86
  end
@@ -87,7 +88,7 @@ module V8
87
88
  end
88
89
 
89
90
  def parse_js_frames(try)
90
- raw = To.rb(try.StackTrace())
91
+ raw = @to.rb(try.StackTrace())
91
92
  if raw && !raw.empty?
92
93
  raw.split("\n")[1..-1].tap do |frames|
93
94
  frames.each {|frame| frame.strip!.chomp!(",")}
@@ -5,10 +5,10 @@ module V8
5
5
  err = nil
6
6
  return_value = nil
7
7
  C::TryCatch.try do |try|
8
- @context.enter do
9
- this = To.v8(thisObject)
10
- return_value = To.rb(@native.Call(this, To.v8(args)))
11
- err = JSError.new(try) if try.HasCaught()
8
+ @portal.open do |to|
9
+ this = to.v8(thisObject)
10
+ return_value = to.rb(@native.Call(this, to.v8(args)))
11
+ err = JSError.new(try, to) if try.HasCaught()
12
12
  end
13
13
  end
14
14
  raise err if err
@@ -16,39 +16,12 @@ module V8
16
16
  end
17
17
 
18
18
  def call(*args)
19
- self.methodcall(@context.Global(), *args)
19
+ self.methodcall(@portal.context.native.Global(), *args)
20
20
  end
21
21
 
22
22
  def new(*args)
23
- @context.enter do
24
- To.rb(@native.NewInstance(To.v8(args)))
25
- end
26
- end
27
-
28
- def self.rubyprotect
29
- begin
30
- To.v8(yield)
31
- rescue Exception => e
32
- case e
33
- when SystemExit, NoMemoryError
34
- raise e
35
- else
36
- error = V8::C::Exception::Error(V8::C::String::New(e.message))
37
- error.SetHiddenValue("TheRubyRacer::Cause", C::External::New(e))
38
- V8::C::ThrowException(error)
39
- end
40
- end
41
- end
42
-
43
- def self.rubycall(rubycode, *args)
44
- rubyprotect do
45
- rubycode.call(*args)
46
- end
47
- end
48
-
49
- def self.rubysend(obj, message, *args)
50
- rubyprotect do
51
- obj.send(message, *args)
23
+ @portal.open do |to|
24
+ to.rb(@native.NewInstance(to.v8(args)))
52
25
  end
53
26
  end
54
27
  end
@@ -3,35 +3,33 @@ module V8
3
3
  class Object
4
4
  include Enumerable
5
5
 
6
- def initialize(native, context = nil)
7
- @native = native
8
- @context = context || C::Context::GetEntered()
9
- raise ScriptError, "V8::Object.new called without an open V8 context" unless @context
6
+ def initialize(native, portal)
7
+ @native, @portal = native, portal
10
8
  end
11
9
 
12
10
  def [](key)
13
- @context.enter do
14
- To.rb(@native.Get(To.v8(key)))
11
+ @portal.open do |to|
12
+ to.rb(@native.Get(to.v8(key)))
15
13
  end
16
14
  end
17
15
 
18
16
  def []=(key, value)
19
17
  value.tap do
20
- @context.enter do
21
- @native.Set(To.v8(key), To.v8(value))
18
+ @portal.open do |to|
19
+ @native.Set(to.v8(key), to.v8(value))
22
20
  end
23
21
  end
24
22
  end
25
23
 
26
24
  def to_s
27
- @context.enter do
28
- To.rb(@native.ToString())
25
+ @portal.open do |to|
26
+ to.rb(@native.ToString())
29
27
  end
30
28
  end
31
29
 
32
30
  def each
33
- @context.enter do
34
- for prop in To.rb(@native.GetPropertyNames())
31
+ @portal.open do |to|
32
+ for prop in to.rb(@native.GetPropertyNames())
35
33
  yield prop, self[prop]
36
34
  end
37
35
  end
@@ -0,0 +1,325 @@
1
+
2
+ module V8
3
+ class Portal
4
+ attr_reader :context
5
+
6
+ def initialize(context, access)
7
+ @context, @access = context, access
8
+ @named_property_getter = Interceptor(NamedPropertyGetter)
9
+ @named_property_setter = Interceptor(NamedPropertySetter)
10
+ @named_property_query = nil
11
+ @named_property_deleter = nil
12
+ @named_property_enumerator = Interceptor(NamedPropertyEnumerator)
13
+
14
+ @indexed_property_getter = Interceptor(IndexedPropertyGetter)
15
+ @indexed_property_setter = Interceptor(IndexedPropertySetter)
16
+ @indexed_property_query = nil
17
+ @indexed_property_deleter = nil
18
+ @indexed_property_enumerator = Interceptor(IndexedPropertyEnumerator)
19
+
20
+ @constructors = Hash.new do |h, cls|
21
+ h[cls] = template = C::FunctionTemplate::New() do |arguments|
22
+ unless arguments.Length() == 1 && arguments[0].kind_of?(C::External)
23
+ C::ThrowException(C::Exception::Error(C::String::New("cannot call native constructor from javascript")))
24
+ else
25
+ arguments.This().tap do |this|
26
+ this.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), arguments[0])
27
+ end
28
+ end
29
+ end
30
+ template.tap do
31
+ setuptemplate(template.InstanceTemplate())
32
+ if cls != ::Object && cls.superclass != ::Object && cls.superclass != ::Class
33
+ template.Inherit(@constructors[cls.superclass])
34
+ end
35
+ if cls.name && cls.name =~ /(::)?(\w+?)$/
36
+ template.SetClassName(C::String::NewSymbol("rb::" + $2))
37
+ else
38
+ template.SetClassName("Ruby")
39
+ end
40
+ end
41
+ end
42
+
43
+ @instances = Hash.new do |h, obj|
44
+ args = C::Array::New(1)
45
+ args.Set(0, C::External::New(obj))
46
+ h[obj] = @constructors[obj.class].GetFunction().NewInstance(args)
47
+ end
48
+
49
+ @functions = Functions.new(self)
50
+
51
+ @embedded_constructors = Hash.new do |h, cls|
52
+ template = @constructors[cls]
53
+ template.SetCallHandler() do |arguments|
54
+ wrap = nil
55
+ if arguments.Length() > 0 && arguments[0].kind_of?(C::External)
56
+ wrap = arguments[0]
57
+ else
58
+ rbargs = []
59
+ for i in 0..arguments.Length() - 1
60
+ rbargs << rb(arguments[i])
61
+ end
62
+ instance = rubysend(cls, :new, *rbargs)
63
+ wrap = C::External::New(instance)
64
+ end
65
+ arguments.This().tap do |this|
66
+ this.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), wrap)
67
+ end
68
+ end
69
+ h[cls] = template
70
+ end
71
+ end
72
+
73
+ def open
74
+ @context.native.enter do
75
+ yield(self)
76
+ end if block_given?
77
+ end
78
+
79
+ def rb(value)
80
+ case value
81
+ when V8::C::Function then peer(value) {V8::Function}
82
+ when V8::C::Array then peer(value) {V8::Array}
83
+ when V8::C::Object then peer(value) {V8::Object}
84
+ when V8::C::String then value.Utf8Value()
85
+ when V8::C::Date then Time.at(value.NumberValue())
86
+ when V8::C::Value then nil if value.IsEmpty()
87
+ else
88
+ value
89
+ end
90
+ end
91
+
92
+ def v8(value)
93
+ case value
94
+ when V8::Object
95
+ value.instance_eval {@native}
96
+ when String
97
+ C::String::New(value.to_s)
98
+ when Symbol
99
+ C::String::NewSymbol(value.to_s)
100
+ when Proc,Method,UnboundMethod
101
+ @functions[value]
102
+ when ::Array
103
+ C::Array::New(value.length).tap do |a|
104
+ value.each_with_index do |item, i|
105
+ a.Set(i, v8(item))
106
+ end
107
+ end
108
+ when ::Hash
109
+ C::Object::New().tap do |o|
110
+ value.each do |key, value|
111
+ o.Set(v8(key), v8(value))
112
+ end
113
+ end
114
+ when ::Time
115
+ C::Date::New(value)
116
+ when ::Class
117
+ @embedded_constructors[value].GetFunction().tap do |f|
118
+ f.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"), C::External::New(value))
119
+ #set the function's prototype object to the object that will have the named property handlers
120
+ prototype = rubytemplate.NewInstance()
121
+ #set *that* object's prototype to an empty function so that it will look and behave like a function.
122
+ prototype.SetPrototype(C::FunctionTemplate::New() {}.GetFunction())
123
+ f.SetPrototype(prototype)
124
+ end
125
+ when nil,Numeric,TrueClass,FalseClass, C::Value
126
+ value
127
+ else
128
+ @instances[value]
129
+ end
130
+ end
131
+
132
+ def rubyprotect
133
+ begin
134
+ v8 yield
135
+ rescue Exception => e
136
+ case e
137
+ when SystemExit, NoMemoryError
138
+ raise e
139
+ else
140
+ error = V8::C::Exception::Error(V8::C::String::New(e.message))
141
+ error.SetHiddenValue("TheRubyRacer::Cause", C::External::New(e))
142
+ V8::C::ThrowException(error)
143
+ end
144
+ end
145
+ end
146
+
147
+ def rubycall(rubycode, *args, &block)
148
+ rubyprotect do
149
+ rubycode.call(*args, &block)
150
+ end
151
+ end
152
+
153
+ def rubysend(obj, message, *args, &block)
154
+ rubyprotect do
155
+ obj.send(message, *args, &block)
156
+ end
157
+ end
158
+
159
+ def rubytemplate
160
+ C::ObjectTemplate::New().tap do |t|
161
+ setuptemplate(t)
162
+ end
163
+ end
164
+
165
+ def setuptemplate(t)
166
+ t.SetNamedPropertyHandler(
167
+ @named_property_getter,
168
+ @named_property_setter,
169
+ nil,
170
+ nil,
171
+ @named_property_enumerator
172
+ )
173
+ t.SetIndexedPropertyHandler(
174
+ @indexed_property_getter,
175
+ @indexed_property_setter,
176
+ nil,
177
+ nil,
178
+ @indexed_property_enumerator
179
+ )
180
+ end
181
+
182
+ private
183
+
184
+ def peer(value)
185
+ external = value.GetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"))
186
+ if external && !external.IsEmpty()
187
+ external.Value()
188
+ else
189
+ yield.new(value, self)
190
+ end
191
+ end
192
+
193
+ class Interceptor
194
+ def initialize(portal, access)
195
+ @to, @access = portal, access
196
+ end
197
+
198
+ def intercept(info, retval = nil, &code)
199
+ obj = @to.rb(info.This())
200
+ intercepts = true
201
+ result = @to.rubyprotect do
202
+ dontintercept = proc do
203
+ intercepts = false
204
+ end
205
+ code.call(obj, dontintercept)
206
+ end
207
+ intercepts ? (retval || result) : C::Empty
208
+ end
209
+
210
+ end
211
+
212
+ def Interceptor(cls)
213
+ cls.new self, @access
214
+ end
215
+
216
+ class PropertyAttributes
217
+ attr_reader :flags
218
+ def initialize
219
+ @flags = 0
220
+ end
221
+
222
+ def read_only
223
+ tap do
224
+ @flags |= V8::C::ReadOnly
225
+ end
226
+ end
227
+
228
+ def dont_enum
229
+ tap do
230
+ @flags |= V8::C::DontEnum
231
+ end
232
+ end
233
+
234
+ def dont_delete
235
+ tap do
236
+ @flags |= V8::C::DontDelete
237
+ end
238
+ end
239
+ end
240
+
241
+ class NamedPropertyGetter < Interceptor
242
+ def call(property, info)
243
+ intercept(info) do |obj, dontintercept|
244
+ @access.get(obj, @to.rb(property), &dontintercept)
245
+ end
246
+ end
247
+ end
248
+
249
+ class NamedPropertySetter < Interceptor
250
+ def call(property, value, info)
251
+ intercept(info, value) do |obj, dontintercept|
252
+ @access.set(obj, @to.rb(property), @to.rb(value), &dontintercept)
253
+ end
254
+ end
255
+ end
256
+
257
+ class NamedPropertyQuery
258
+ def call(property, info)
259
+ attributes = PropertyAttributes.new
260
+ result = intercept(info) do |obj, dontintercept|
261
+ @access.query(obj, @to.rb(property), attributes, &dontintercept)
262
+ end
263
+ return result == C::Empty ? result : C::Integer::New(attributes.flags)
264
+ end
265
+ end
266
+
267
+ class NamedPropertyEnumerator < Interceptor
268
+ def call(info)
269
+ intercept(info) do |obj, dontintercept|
270
+ @access.names(obj, &dontintercept).to_a
271
+ end
272
+ end
273
+ end
274
+
275
+ class NamedPropertyDeleter < Interceptor
276
+ def call(property, info)
277
+ intercept(info) do |obj, dontintercept|
278
+ @access.delete(obj, property, &dontintercept)
279
+ end
280
+ end
281
+ end
282
+
283
+ class IndexedPropertyGetter < Interceptor
284
+ def call(index, info)
285
+ intercept(info) do |obj, dontintercept|
286
+ @access.iget(obj, index, &dontintercept)
287
+ end
288
+ end
289
+ end
290
+
291
+ class IndexedPropertySetter < Interceptor
292
+ def call(index, value, info)
293
+ intercept(info, value) do |obj, dontintercept|
294
+ @access.iset(obj, index, @to.rb(value), &dontintercept)
295
+ end
296
+ end
297
+ end
298
+
299
+ class IndexedPropertyQuery < Interceptor
300
+ def call(property, info)
301
+ attributes = PropertyAttributes.new
302
+ result = intercept(info) do |obj, dontintercept|
303
+ @access.indices(obj, &dontintercept)
304
+ end
305
+ result == C::Empty ? C::Empty : C::Integer::New(attributes.flags)
306
+ end
307
+ end
308
+
309
+ class IndexedPropertyDeleter < Interceptor
310
+ def call(index, info)
311
+ intercept(info) do |obj, dontintercept|
312
+ @access.idelete(obj, index, &dontintercept)
313
+ end
314
+ end
315
+ end
316
+
317
+ class IndexedPropertyEnumerator < Interceptor
318
+ def call(info)
319
+ intercept(info) do |obj, dontintercept|
320
+ @access.indices(obj, &dontintercept)
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end