therubyracer 0.10.1 → 0.10.2beta1

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.

data/ext/v8/extconf.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  require 'mkmf'
2
2
  require 'set'
3
3
  begin
4
- require 'libv8'
5
- rescue LoadError
6
4
  require 'rubygems'
5
+ gem 'libv8', '~> 3.3.10'
6
+ require 'libv8'
7
+ rescue LoadError, Gem::LoadError
7
8
  require 'libv8'
8
9
  end
9
10
 
data/lib/v8/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module V8
2
- VERSION = "0.10.1"
2
+ VERSION = "0.10.2beta1"
3
3
  end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: therubyracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
5
- prerelease:
4
+ version: 0.10.2beta1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Charles Lowell
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-04-05 00:00:00.000000000 Z
13
+ date: 2012-08-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: libv8
17
- requirement: &2156377220 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,15 @@ dependencies:
22
22
  version: 3.3.10
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2156377220
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: 3.3.10
26
31
  - !ruby/object:Gem::Dependency
27
32
  name: rake
28
- requirement: &2156376120 !ruby/object:Gem::Requirement
33
+ requirement: !ruby/object:Gem::Requirement
29
34
  none: false
30
35
  requirements:
31
36
  - - ! '>='
@@ -33,10 +38,15 @@ dependencies:
33
38
  version: '0'
34
39
  type: :development
35
40
  prerelease: false
36
- version_requirements: *2156376120
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
37
47
  - !ruby/object:Gem::Dependency
38
48
  name: rspec
39
- requirement: &2156374760 !ruby/object:Gem::Requirement
49
+ requirement: !ruby/object:Gem::Requirement
40
50
  none: false
41
51
  requirements:
42
52
  - - ~>
@@ -44,10 +54,15 @@ dependencies:
44
54
  version: '2.0'
45
55
  type: :development
46
56
  prerelease: false
47
- version_requirements: *2156374760
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '2.0'
48
63
  - !ruby/object:Gem::Dependency
49
64
  name: rake-compiler
50
- requirement: &2156373840 !ruby/object:Gem::Requirement
65
+ requirement: !ruby/object:Gem::Requirement
51
66
  none: false
52
67
  requirements:
53
68
  - - ! '>='
@@ -55,7 +70,12 @@ dependencies:
55
70
  version: '0'
56
71
  type: :development
57
72
  prerelease: false
58
- version_requirements: *2156373840
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
59
79
  description: Call javascript code and manipulate javascript objects from ruby. Call
60
80
  ruby code and manipulate ruby objects from javascript.
61
81
  email: cowboyd@thefrontside.net
@@ -155,10 +175,6 @@ files:
155
175
  - specthread/threading_spec.rb
156
176
  - thefrontside.png
157
177
  - therubyracer.gemspec
158
- - spec/redjs/.gitignore
159
- - spec/redjs/README.txt
160
- - spec/redjs/jsapi_spec.rb
161
- - spec/redjs/loadme.js
162
178
  homepage: http://github.com/cowboyd/therubyracer
163
179
  licenses: []
164
180
  post_install_message:
@@ -174,19 +190,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
174
190
  version: '0'
175
191
  segments:
176
192
  - 0
177
- hash: -1402630877173126943
193
+ hash: 1052494851132937733
178
194
  required_rubygems_version: !ruby/object:Gem::Requirement
179
195
  none: false
180
196
  requirements:
181
- - - ! '>='
197
+ - - ! '>'
182
198
  - !ruby/object:Gem::Version
183
- version: '0'
184
- segments:
185
- - 0
186
- hash: -1402630877173126943
199
+ version: 1.3.1
187
200
  requirements: []
188
201
  rubyforge_project: therubyracer
189
- rubygems_version: 1.8.17
202
+ rubygems_version: 1.8.24
190
203
  signing_key:
191
204
  specification_version: 3
192
205
  summary: Embed the V8 Javascript interpreter into Ruby
@@ -1 +0,0 @@
1
- *.rbc
@@ -1,8 +0,0 @@
1
- Rspecs for a Ruby interface to javascript.
2
-
3
- This is useful for different javascript interpreters wanting to present a unified interface to ruby.
4
-
5
- Currently used by
6
- The Ruby Rhino: http://github.com/cowboyd/therubyrhino
7
- The Ruby Racer: http://github.com/cowboyd/therubyracer
8
-
@@ -1,922 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- require "#{File.dirname(__FILE__)}/../redjs_helper.rb"
3
-
4
- describe "Ruby Javascript API" do
5
-
6
- describe "Basic Evaluation" do
7
-
8
- before do
9
- @cxt = Context.new
10
- end
11
-
12
- it "can evaluate some javascript" do
13
- @cxt.eval("5 + 3").should == 8
14
- end
15
-
16
- it "can pass back null to ruby" do
17
- @cxt.eval("null").should be_nil
18
- end
19
-
20
- it "can pass back undefined to ruby" do
21
- @cxt.eval("this.undefined").should be_nil
22
- end
23
-
24
- it "can pass the empty string back to ruby" do
25
- @cxt.eval("''").should == ""
26
- end
27
-
28
- it "can pass doubles back to ruby" do
29
- @cxt.eval("2.5").should == 2.5
30
- end
31
-
32
- it "can pass fixed numbers back to ruby" do
33
- @cxt.eval("1").should == 1
34
- end
35
-
36
- it "can pass boolean values back to ruby" do
37
- @cxt.eval("true").should be(true)
38
- @cxt.eval("false").should be(false)
39
- end
40
-
41
- it "treats nil and the empty string as the same thing when it comes to eval" do
42
- @cxt.eval(nil).should == @cxt.eval('')
43
- end
44
-
45
- it "can pass back strings to ruby" do
46
- @cxt['foo'] = "Hello World"
47
- @cxt.eval("foo").should == "Hello World"
48
- end
49
-
50
- it "can pass back very long strings to ruby" do
51
- lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis faucibus, diam vel pellentesque aliquet, nisl sapien molestie eros, vitae vehicula libero massa vel neque. Phasellus tempor pharetra ipsum vel venenatis. Quisque vitae nisl vitae quam mattis pellentesque et in sapien. Sed at lectus quis eros pharetra feugiat non ac neque. Vivamus lacus eros, feugiat at volutpat at, viverra id nisl. Vivamus ac dolor eleifend libero venenatis pharetra ut iaculis arcu. Donec neque nibh, vehicula non porta a, consectetur eu erat. Sed eleifend, metus vel euismod placerat, lectus lectus sollicitudin nisl, ac elementum sem quam nec dolor. In hac habitasse platea dictumst. Proin vitae suscipit orci. Suspendisse a ipsum vel lorem tempus scelerisque et vitae neque. Proin sodales, tellus sit amet consequat cursus, odio massa ultricies enim, eu fermentum velit lectus in lacus. Quisque eu porttitor diam. Nunc felis purus, facilisis non tristique ac, pulvinar nec nulla. Duis dolor risus, egestas nec tristique ac, ullamcorper cras amet."
52
- @cxt.eval("'#{lorem}'").should == lorem
53
- end
54
-
55
- it "correctly handles translating strings that have non-standard characters" do
56
- @cxt['utf8'] = "Σὲ γνωρίζω ἀπὸ τὴν κόψη"
57
- @cxt['utf8'].should == "Σὲ γνωρίζω ἀπὸ τὴν κόψη"
58
- @cxt.eval('var nativeUtf8 = "Σὲ γνωρίζω ἀπὸ τὴν κόψη"')
59
- @cxt['nativeUtf8'].should == "Σὲ γνωρίζω ἀπὸ τὴν κόψη"
60
- end
61
-
62
- it "translates JavaScript dates properly into ruby Time objects" do
63
- now = Time.now
64
- @cxt.eval('new Date()').tap do |time|
65
- time.should be_kind_of(Time)
66
- time.year.should == now.year
67
- time.day.should == now.day
68
- time.month.should == now.month
69
- time.min.should == now.min
70
- time.sec.should == now.sec
71
- end
72
- end
73
-
74
- it "can pass objects back to ruby" do
75
- @cxt.eval("({foo: 'bar', baz: 'bang', '5': 5, embedded: {badda: 'bing'}})").tap do |object|
76
- object.should_not be_nil
77
- object['foo'].should == 'bar'
78
- object['baz'].should == 'bang'
79
- object['5'].should == 5
80
- object['embedded'].tap do |embedded|
81
- embedded.should_not be_nil
82
- embedded['badda'].should == 'bing'
83
- end
84
- end
85
- end
86
-
87
- it "unwraps ruby objects returned by embedded ruby code to maintain referential integrity" do
88
- Object.new.tap do |o|
89
- @cxt['get'] = lambda {o}
90
- @cxt.eval('get()').should be(o)
91
- end
92
- end
93
-
94
- it "always returns the same ruby object for a single javascript object" do
95
- obj = @cxt.eval('obj = {}')
96
- obj.should be(@cxt['obj'])
97
- @cxt.eval('obj').should be(@cxt['obj'])
98
- @cxt['obj'].should be(@cxt['obj'])
99
- end
100
-
101
- it "converts arrays to javascript" do
102
- @cxt['a'] = [1,2,4]
103
- @cxt.eval('var sum = 0;for (var i = 0; i < a.length; i++) {sum += a[i]}; sum').should == 7
104
- @cxt.eval('[1,2,3]').tap do |a|
105
- a.length.should == 3
106
- a.to_a.should == [1,2,3]
107
- end
108
- end
109
-
110
- it "can iterate over arrays" do
111
- @cxt['a'] = @cxt.eval('[{num: 1},{num:2},{num:3},{num: 4}]')
112
- a = @cxt['a']
113
- a.inject(0) do |sum, item|
114
- sum + item['num']
115
- end.should == 10
116
-
117
- end
118
-
119
- it "converts ruby hashes to javascript objects" do
120
- @cxt['h'] = {:foo => 'bar', :baz => 'bang', :bar => {'hello' => 'world'}}
121
- @cxt['h']['foo'].should == 'bar'
122
- @cxt['h']['baz'].should == 'bang'
123
- @cxt['h']['bar']['hello'].should == 'world'
124
- end
125
- end
126
-
127
- describe "Calling Ruby Code From Within Javascript" do
128
-
129
- before(:each) do
130
- @class = Class.new
131
- @instance = @class.new
132
- @cxt = Context.new
133
- @cxt['puts'] = lambda {|o| puts o.inspect}
134
- @cxt['o'] = @instance
135
- end
136
-
137
- it "can embed a closure into a context and call it" do
138
- @cxt["say"] = lambda {|this, word, times| word * times}
139
- @cxt.eval("say('Hello',2)").should == "HelloHello"
140
- end
141
-
142
- it "truncates the arguments passed in to match the arity of the function" do
143
- @cxt['testing'] = lambda {|this|}
144
- expect{@cxt.eval('testing(1,2,3)')}.should_not raise_error
145
- @cxt['testing'] = lambda {}
146
- expect{@cxt.eval('testing(1,2,3)')}.should_not raise_error
147
- end
148
-
149
- it "recognizes the same closure embedded into the same context as the same function object" do
150
- @cxt['say'] = @cxt['declare'] = lambda {|word, times| word * times}
151
- @cxt.eval('say == declare').should be(true)
152
- @cxt.eval('say === declare').should be(true)
153
- end
154
-
155
- it "translates ruby Array to Javascript Array" do
156
- class_eval do
157
- def ruby_array
158
- []
159
- end
160
- end
161
- evaljs('o.ruby_array instanceof Array').should == true
162
- end
163
-
164
- it "translates ruby Time to Javascript Date" do
165
- now = Time.now
166
- class_eval do
167
- def ruby_time
168
- @now
169
- end
170
- end
171
- @instance.instance_variable_set(:@now, now)
172
- evaljs('o.ruby_time instanceof Date').should == true
173
- evaljs('o.ruby_time.getFullYear()').should == now.year
174
- evaljs('o.ruby_time.getMonth() + 1').should == now.month
175
- evaljs('o.ruby_time.getDate()').should == now.day
176
- evaljs('o.ruby_time.getMinutes()').should == now.min
177
- evaljs('o.ruby_time.getSeconds()').should == now.sec
178
- end
179
-
180
- it "translates ruby true to Javascript true" do
181
- class_eval do
182
- def bool
183
- true
184
- end
185
- end
186
- evaljs('o.bool === true').should == true
187
- end
188
-
189
- it "translates ruby false to Javascript false" do
190
- class_eval do
191
- def bool
192
- false
193
- end
194
- end
195
- evaljs('o.bool === false').should == true
196
- end
197
-
198
- it "can embed a ruby object into a context and call its methods" do
199
- class_eval do
200
- def say_hello(to)
201
- "Hello #{to}!"
202
- end
203
- end
204
- evaljs('o.say_hello("Gracie")').should == "Hello Gracie!"
205
- end
206
-
207
- it "recognizes object method as the same." do |variable|
208
- class_eval do
209
- def foo(*a);end
210
- end
211
- @cxt.eval('o.foo == o.foo').should be(true)
212
- end
213
-
214
- it "recognizes functions on objects of the same class as being the same function" do
215
- cls = class_eval do
216
- def foo(*a);end
217
- self
218
- end
219
- @cxt['one'] = cls.new
220
- @cxt['two'] = cls.new
221
- @cxt.eval('one.foo === two.foo').should be(true)
222
- #TODO: nice to have, but a bit tricky.
223
- # @cxt.eval('one.foo === one.constructor.prototype.foo').should be(true)
224
- end
225
-
226
- it "can call a bound ruby method" do
227
- five = class_eval do
228
- def initialize(lhs)
229
- @lhs = lhs
230
- end
231
- def times(rhs)
232
- @lhs * rhs
233
- end
234
- new(5)
235
- end
236
-
237
- @cxt['timesfive'] = five.method(:times)
238
- @cxt.eval('timesfive(3)').should == 15
239
- end
240
-
241
- describe "Default Ruby Object Access" do
242
-
243
- it "can call public locally defined ruby methods" do
244
- class_eval do
245
- def voo(str)
246
- "voo#{str}"
247
- end
248
- end
249
- evaljs("o.voo('doo')").should == "voodoo"
250
- end
251
-
252
- it "reports ruby methods that do not exist as undefined" do
253
- Context.new(:with => Object.new) do |cxt|
254
- cxt.eval('this.foobar').should be_nil
255
- end
256
- end
257
-
258
- it "can access methods defined in an object's superclass" do
259
- o = Class.new.class_eval do
260
- attr_accessor :foo
261
- def foo
262
- @foo ||= "FOO"
263
- end
264
- Class.new(self)
265
- end.new
266
- Context.new(:with => o) do |cxt|
267
- cxt.eval('this.foo').should == 'FOO'
268
- cxt.eval('this.foo = "bar!"')
269
- cxt.eval('this.foo').should == "bar!"
270
- end
271
- end
272
-
273
- it "allows a ruby object to intercept property access with []" do
274
- Class.new.class_eval do
275
- def [](val)
276
- "FOO"
277
- end
278
- Context.new(:with => new) do |cxt|
279
- cxt.eval('this.foo').should == "FOO"
280
- cxt.eval('this.bar').should == "FOO"
281
- end
282
- end
283
- end
284
-
285
- it "allows a ruby object to intercept property setting with []=" do
286
- Class.new.class_eval do
287
- def initialize
288
- @properties = {}
289
- end
290
- def [](name)
291
- @properties[name]
292
- end
293
- def []=(name, value)
294
- @properties[name] = value
295
- end
296
-
297
- Context.new(:with => new) do |cxt|
298
- cxt.eval('this.foo = "bar"').should == "bar"
299
- cxt.eval('this.foo').should == "bar"
300
- end
301
- end
302
- end
303
-
304
- it "allows a ruby object which intercepts property access to take a pass on intercepting the property" do
305
- Class.new.class_eval do
306
- def initialize
307
- @attrs = {}
308
- end
309
- def [](name)
310
- name =~ /foo/ ? @attrs[name] : yield
311
- end
312
- def []=(name, value)
313
- name =~ /foo/ ? @attrs[name] = "#{value}-diddly" : yield
314
- end
315
- Context.new do |cxt|
316
- cxt['foo'] = new
317
- cxt.eval('typeof foo.bar').should == 'undefined'
318
- cxt.eval('foo.bar = "baz"')
319
- cxt.eval('foo.bar').should == 'baz'
320
- cxt.eval('foo.foobar').should == nil
321
- cxt.eval('foo.foobar = "baz"')
322
- cxt.eval('foo.foobar').should == "baz-diddly"
323
- end
324
- end
325
- end
326
-
327
- it "allows a ruby object to take a pass on intercepting an indexed property" do
328
- Class.new.class_eval do
329
- def initialize
330
- @a = []
331
- end
332
- def [](i)
333
- i >= 5 ? @a[i] : yield
334
- end
335
- def []=(i, value)
336
- i >= 5 ? @a[i] = "#{value}-diddly" : yield
337
- end
338
- Context.new do |cxt|
339
- cxt['obj'] = new
340
- cxt.eval('typeof obj[1]').should == 'undefined'
341
- cxt.eval('obj[1] = "foo"')
342
- cxt.eval('obj[1]').should == "foo"
343
- cxt.eval('obj[5] = "foo"').should == "foo"
344
- cxt.eval('obj[5]').should == "foo-diddly"
345
- end
346
- end
347
- end
348
-
349
- it "does not make the [] and []= methods visible or enumerable by default" do
350
- Class.new.class_eval do
351
- def [](name)
352
- end
353
- def []=(name, value)
354
- end
355
- def bar=(value)
356
- end
357
- Context.new do |cxt|
358
- cxt['o'] = new
359
- cxt.eval('o["[]"]').should == nil
360
- cxt.eval('o["[]="]').should == nil
361
- cxt.eval('a = new Array(); for (var i in o) {a.push(i)}')
362
- cxt['a'].length.should == 0
363
- end
364
- end
365
- end
366
-
367
- it "doesn't kill the whole process if a dynamic interceptor or setter throws an exception" do
368
- cls = Class.new.class_eval do
369
- def [](name)
370
- raise "BOOM!"
371
- end
372
- def []=(name, val)
373
- raise "Bam!"
374
- end
375
- self
376
- end
377
- Context.new do |cxt|
378
- cxt['foo'] = cls.new
379
- lambda {
380
- cxt.eval('foo.bar')
381
- }.should raise_error
382
- lambda {
383
- cxt.eval('foo.bar = "baz"')
384
- }.should raise_error
385
- end
386
- end
387
-
388
- it "doesn't kill the whole process if reader or accessor throws an exception" do
389
- cxt = Class.new.class_eval do
390
- def foo
391
- raise "NO GET 4 U!"
392
- end
393
- def foo=(val)
394
- raise "NO SET 4 U!"
395
- end
396
- Context.new(:with => new)
397
- end
398
- lambda {
399
- cxt.eval(this.foo)
400
- }.should raise_error
401
- lambda {
402
- cxt.eval("this.foo = 'bar'")
403
- }.should raise_error
404
- end
405
-
406
- it "allows access to methods defined on an objects included/extended modules (class)" do
407
- m = Module.new.module_eval do
408
- attr_accessor :foo
409
- def foo
410
- @foo ||= "FOO"
411
- end
412
- self
413
- end
414
- o = Class.new.class_eval do
415
- include m
416
- new
417
- end
418
- Context.new(:with => o) do |cxt|
419
- cxt.eval('this.foo').should == "FOO"
420
- cxt.eval('this.foo = "bar!"')
421
- cxt.eval('this.foo').should == "bar!"
422
- end
423
- end
424
-
425
- it "allows access to methods defined on an objects included/extended modules (instance)" do
426
- m = Module.new.module_eval do
427
- attr_accessor :foo
428
- def foo
429
- @foo ||= "FOO"
430
- end
431
- self
432
- end
433
- Object.new.tap do |o|
434
- o.extend(m)
435
- Context.new(:with => o) do |cxt|
436
- cxt.eval('this.foo').should == "FOO"
437
- cxt.eval('this.foo = "bar!"')
438
- cxt.eval('this.foo').should == "bar!"
439
- end
440
- end
441
- end
442
-
443
- it "allows access to public singleton methods" do
444
- Object.new.tap do |o|
445
- class << o
446
- attr_accessor :foo
447
- end
448
- def o.foo
449
- @foo ||= "FOO"
450
- end
451
- Context.new(:with => o) do |cxt|
452
- cxt.eval("this.foo").should == "FOO"
453
- cxt.eval('this.foo = "bar!"')
454
- cxt.eval('this.foo').should == "bar!"
455
- end
456
- end
457
- end
458
-
459
- it "does not allow access to methods defined on Object and above" do
460
- o = Class.new.class_eval do
461
- def foo
462
- "FOO"
463
- end
464
- self.new
465
- end
466
- Context.new(:with => o) do |cxt|
467
- for method in Object.public_instance_methods
468
- cxt.eval("this['#{method}']").should be_nil
469
- end
470
- end
471
- end
472
-
473
- it "hides methods derived from Object, Kernel, etc..." do
474
- class_eval do
475
- def bar
476
- end
477
- end
478
- evaljs("o.to_s").should be_nil
479
- end
480
-
481
- describe "with an integer index" do
482
- it "allows accessing indexed properties via the []() method" do
483
- class_eval do
484
- def [](i)
485
- "foo" * i
486
- end
487
- end
488
- evaljs("o[3]").should == "foofoofoo"
489
- end
490
- it "allows setting indexed properties via the []=() method" do
491
- class_eval do
492
- def [](i)
493
- @storage ||= []
494
- @storage[i]
495
- end
496
- def []=(i, val)
497
- @storage ||= []
498
- @storage[i] = val
499
- end
500
- end
501
- evaljs("o[3] = 'three'").should == 'three'
502
- evaljs("o[3]").should == 'three'
503
- end
504
-
505
- it "doesn't kill the whole process if indexed interceptors throw exceptions" do
506
- class_eval do
507
- def [](idx)
508
- raise "No Indexed Get For You!"
509
- end
510
- def []=(idx, value)
511
- raise "No Indexed Set For You!"
512
- end
513
- end
514
- lambda {
515
- evaljs("o[1] = 'boo'")
516
- }.should raise_error
517
- lambda {
518
- evaljs("o[1]")
519
- }.should raise_error end
520
-
521
- #TODO: I'm not sure this is warranted
522
- #it "will enumerate indexed properties if a length property is provided"
523
- end
524
-
525
- end
526
-
527
- it "will see a method that appears after the wrapper was first created" do
528
- @cxt['o'] = @instance
529
- class_eval do
530
- def whiz(str)
531
- "whiz#{str}!"
532
- end
533
- end
534
- @cxt.eval("o.whiz('bang')").should == "whizbang!"
535
- end
536
-
537
- it "treats ruby methods that have an arity of 0 as javascript properties by default" do
538
- class_eval do
539
- def property
540
- "flan!"
541
- end
542
- end
543
- evaljs('o.property').should == 'flan!'
544
- end
545
-
546
- it "will call ruby accesssor function when setting a property from javascript" do
547
- class_eval do
548
- def dollars
549
- @dollars
550
- end
551
-
552
- def dollars=(amount)
553
- @dollars = amount
554
- end
555
- end
556
- evaljs('o.dollars = 50')
557
- @instance.dollars.should == 50
558
- end
559
-
560
- it "will accept expando properties by default for properties on ruby object that are not implemented in ruby" do
561
- evaljs('o.five = 5; o.five').should == 5
562
- end
563
-
564
- it "it silently fails to replace properties which are defined on ruby objects but which are read-only" do
565
- class_eval do
566
- def bar
567
- "baz"
568
- end
569
- end
570
- evaljs('o.bar = "bing"; o.bar').should == "baz"
571
- end
572
-
573
- def evaljs(str)
574
- @cxt.eval(str)
575
- end
576
-
577
- def class_eval(&body)
578
- @class.class_eval &body
579
- end
580
-
581
- end
582
-
583
- describe "Calling JavaScript Code From Within Ruby" do
584
-
585
- before(:each) do
586
- @cxt = Context.new
587
- end
588
-
589
- it "allows you to capture a reference to a javascript function and call it" do
590
- f = @cxt.eval('(function add(lhs, rhs) {return lhs + rhs})')
591
- f.call(1,2).should == 3
592
- end
593
-
594
- it "can path the 'this' object into a function as context with methodcall()" do
595
- obj = @cxt.eval('({num: 5})')
596
- times = @cxt.eval('(function times(num) {return this.num * num})')
597
- times.methodcall(obj, 5).should == 25
598
- end
599
-
600
- it "unwraps objects that are backed by javascript objects to pass their native equivalents" do |cxt|
601
- @cxt.eval('obj = {foo: "bar"}')
602
- f = @cxt.eval('(function() {return this == obj})')
603
- f.methodcall(@cxt['obj']).should be(true)
604
- end
605
-
606
- it "can invoke a javacript constructor and return the new object reflected into ruby" do
607
- wrapper = @cxt.eval('(function Wrapper(value) {this.value = value})')
608
- wrapper.new(5)['value'].should == 5
609
- end
610
-
611
- it "can call a javascript method directly from a ruby object" do
612
- obj = @cxt.eval('Object').new
613
- obj.should respond_to(:toString)
614
- obj.toString().should == '[object Object]'
615
- end
616
-
617
- it "can access properties defined on a javascript object through ruby" do
618
- obj = @cxt.eval('({str: "bar", num: 5})')
619
- obj.str.should == "bar"
620
- obj.num.should == 5
621
- end
622
-
623
- it "can set properties on the javascript object via ruby setter methods" do
624
- obj = @cxt.eval('({str: "bar", num: 5})')
625
- obj.str = "baz"
626
- obj.str.should == "baz"
627
- obj.double = proc {|i| i * 2}
628
- obj.double.call(2).should == 4
629
- obj.array = 1,2,3
630
- obj.array.to_a.should == [1,2,3]
631
- obj.array = [1,2,3]
632
- obj.array.to_a.should == [1,2,3]
633
- end
634
-
635
- it "is an error to try and pass parameters to a property" do
636
- obj = @cxt.eval('({num: 1})')
637
- lambda {
638
- obj.num(5)
639
- }.should raise_error(ArgumentError)
640
- end
641
- end
642
-
643
- describe "Setting up the Host Environment" do
644
- before(:each) do
645
- @cxt = Context.new
646
- end
647
-
648
- it "can eval javascript with a given ruby object as the scope." do
649
- scope = Class.new.class_eval do
650
- def plus(lhs, rhs)
651
- lhs + rhs
652
- end
653
-
654
- def minus(lhs, rhs)
655
- lhs - rhs
656
- end
657
-
658
- new
659
- end
660
-
661
- Context.new(:with => scope) do |cxt|
662
- cxt.eval("plus(1,2)", "test").should == 3
663
- cxt.eval("minus(10, 20)", "test").should == -10
664
- cxt.eval("this").should be(scope)
665
- end
666
- end
667
-
668
- it "can directly embed ruby values into javascript" do
669
- @cxt["bar"] = 9
670
- @cxt['foo'] = "bar"
671
- @cxt['num'] = 3.14
672
- @cxt['trU'] = true
673
- @cxt['falls'] = false
674
- @cxt.eval("bar + 10").should be(19)
675
- @cxt.eval('foo').should == "bar"
676
- @cxt.eval('num').should == 3.14
677
- @cxt.eval('trU').should be(true)
678
- @cxt.eval('falls').should be(false)
679
- end
680
-
681
- it "has the global object available as a javascript value" do
682
- @cxt['foo'] = 'bar'
683
- @cxt.scope.should be_kind_of(V8::Object)
684
- @cxt.scope['foo'].should == 'bar'
685
- end
686
-
687
- it "will treat class objects as constructors by default" do
688
- @cxt[:MyClass] = Class.new.tap do |cls|
689
- cls.class_eval do
690
- attr_reader :one, :two
691
- def initialize(one, two)
692
- @one, @two = one, two
693
- # rputs "one: #{@one}, two: #{@two}"
694
- end
695
- end
696
- end
697
- @cxt.eval('new MyClass(1,2).one').should == 1
698
- @cxt.eval('new MyClass(1,2).two').should == 2
699
- end
700
-
701
- it "exposes class properties as javascript properties on the corresponding constructor" do
702
- @cxt[:MyClass] = Class.new.tap do |cls|
703
- def cls.foo
704
- "bar"
705
- end
706
- end
707
- @cxt.eval('MyClass.foo').should == "bar"
708
- end
709
-
710
- it "unwraps reflected ruby constructor objects into their underlying ruby classes" do
711
- @cxt['RubyObject'] = Object
712
- @cxt['RubyObject'].should be(Object)
713
- end
714
-
715
- it "honors the instanceof operator for ruby instances when compared to their reflected constructors" do
716
- @cxt['RubyObject'] = Object
717
- @cxt['one'] = Object.new
718
- @cxt['two'] = Object.new
719
- @cxt.eval('one instanceof RubyObject')
720
- @cxt.eval('two instanceof RubyObject')
721
- @cxt.eval('RubyObject instanceof Function').should be(true)
722
- @cxt.eval('new RubyObject() instanceof RubyObject').should be(true)
723
- @cxt.eval('new RubyObject() instanceof Array').should be(false)
724
- @cxt.eval('new RubyObject() instanceof Object').should be(true)
725
- end
726
-
727
- it "unwraps instances created by a native constructor when passing them back to ruby" do
728
- cls = Class.new.tap do |c|
729
- c.class_eval do
730
- def definitely_a_product_of_this_one_off_class?
731
- true
732
- end
733
- end
734
- end
735
- @cxt['RubyClass'] = cls
736
- @cxt.eval('new RubyClass()').should be_definitely_a_product_of_this_one_off_class
737
- end
738
-
739
- it "does not allow you to call a native ruby constructor, unless that constructor has been directly embedded" do
740
- @cxt['o'] = Class.new.new
741
- lambda {
742
- @cxt.eval('new (o.constructor)()')
743
- }.should raise_error(JSError)
744
- end
745
-
746
- it "extends object to allow for the arbitrary execution of javascript with any object as the scope" do
747
- Class.new.class_eval do
748
-
749
- def initialize
750
- @lhs = 5
751
- end
752
-
753
- def timesfive(rhs)
754
- @lhs * rhs
755
- end
756
-
757
- new.eval_js("timesfive(6)").should == 30
758
- end
759
- end
760
-
761
- # it "can limit the number of instructions that are executed in the context" do
762
- # pending "haven't figured out how to constrain resources in V8"
763
- # lambda {
764
- # Context.new do |cxt|
765
- # cxt.instruction_limit = 100 * 1000
766
- # timeout(1) do
767
- # cxt.eval('while (true);')
768
- # end
769
- # end
770
- # }.should raise_error(RunawayScriptError)
771
- # end
772
- end
773
-
774
- describe "Loading javascript source into the interpreter" do
775
-
776
- it "can take an IO object in the eval method instead of a string" do
777
- source = StringIO.new(<<-EOJS)
778
- /*
779
- * we want to have a fairly verbose function so that we can be assured tha
780
- * we overflow the buffer size so that we see that the reader is chunking
781
- * it's payload in at least several fragments.
782
- *
783
- * That's why we're wasting space here
784
- */
785
- function five() {
786
- return 5
787
- }
788
- foo = 'bar'
789
- five();
790
- EOJS
791
- Context.new do |cxt|
792
- cxt.eval(source, "StringIO").should == 5
793
- cxt['foo'].should == "bar"
794
- end
795
- end
796
-
797
- it "can load a file into the runtime" do
798
- Context.new do |cxt|
799
- cxt.load(Pathname(__FILE__).dirname.join("loadme.js")).should == "I am Legend"
800
- end
801
- end
802
- end
803
-
804
- describe "A Javascript Object Reflected Into Ruby" do
805
-
806
- before(:each) do
807
- @cxt = Context.new
808
- @o = @cxt.eval("o = new Object(); o")
809
- end
810
-
811
- def evaljs(js)
812
- @cxt.eval(js)
813
- end
814
-
815
- it "can have its properties manipulated via ruby style [] hash access" do
816
- @o["foo"] = 'bar'
817
- evaljs('o.foo').should == "bar"
818
- evaljs('o.blue = "blam"')
819
- @o["blue"].should == "blam"
820
- end
821
-
822
- it "doesn't matter if you use a symbol or a string to set a value" do
823
- @o[:foo] = "bar"
824
- @o['foo'].should == "bar"
825
- @o['baz'] = "bang"
826
- @o[:baz].should == "bang"
827
- end
828
-
829
- it "returns nil when the value is null, null, or not defined" do
830
- @o[:foo].should be_nil
831
- end
832
-
833
- it "traverses the prototype chain when hash accessing properties from the ruby object" do
834
- Context.new do |cxt|
835
- cxt.eval(<<EOJS)['bar'].should == "baz"
836
- function Foo() {}
837
- Foo.prototype.bar = 'baz'
838
- new Foo()
839
- EOJS
840
- end
841
- end
842
-
843
- it "is enumenable" do
844
- evaljs("o.foo = 'bar'; o.bang = 'baz'; o[5] = 'flip'")
845
- {}.tap do |h|
846
- @o.each do |k,v|
847
- h[k] = v
848
- end
849
- h.should == {"foo" => 'bar', "bang" => 'baz', 5 => 'flip'}
850
- end
851
- end
852
- end
853
-
854
- describe "Exception Handling" do
855
- it "raises javascript exceptions as ruby exceptions" do
856
- lambda {
857
- Context.new.eval('foo')
858
- }.should raise_error(JSError)
859
- end
860
-
861
- it "can handle syntax errors" do
862
- lambda {
863
- Context.eval('does not compiles')
864
- }.should raise_error
865
- end
866
-
867
- it "translates ruby exceptions into javascript exceptions if they are thrown from code called it javascript" do
868
- Context.new do |cxt|
869
- cxt['rputs'] = lambda {|this, msg| rputs msg}
870
- cxt['boom'] = lambda do |this|
871
- raise "BOOM!"
872
- end
873
- cxt.eval('var msg;try {boom()} catch (e) {msg = e.message};msg').should == 'BOOM!'
874
- end
875
- end
876
-
877
- it "will allow exceptions to pass through multiple languages boundaries (i.e. js -> rb -> js -> rb)" do
878
- Context.new do |cxt|
879
- cxt['one'] = lambda do
880
- cxt.eval('two()', 'one.js')
881
- end
882
- cxt['two'] = lambda do
883
- cxt.eval('three()', 'two.js')
884
- end
885
- cxt['three'] = lambda do
886
- cxt.eval('throw "BOOM!"', "three.js")
887
- end
888
- lambda {
889
- cxt['one'].call(cxt.scope)
890
- }.should raise_error {|e|
891
- #TODO: assert something about the contents of the stack?
892
- #--cowboyd 05/25/2010
893
- }
894
- end
895
- end
896
- end
897
-
898
- describe "A Ruby class reflected into JavaScript" do
899
- it "will extend instances of the class when properties are added to the corresponding JavaScript constructor's prototype" do
900
- Class.new.tap do |cls|
901
- Context.new do |cxt|
902
- cxt['RubyObject'] = cls
903
- cxt.eval('RubyObject.prototype.foo = function() {return "bar"}')
904
- cxt['o'] = cls.new
905
- cxt.eval('o.foo()').should == "bar"
906
- end
907
- end
908
- end
909
-
910
- it "will extend instances of subclasses when properties are added to the corresponding JavaScript constructor's prototype" do
911
- superclass = Class.new
912
- subclass = Class.new(superclass)
913
- Context.new do |cxt|
914
- cxt['SuperClass'] = superclass
915
- cxt['SubClass'] = subclass
916
- cxt['o'] = subclass.new
917
- cxt.eval('SuperClass.prototype.foo = function() {return "bar"}')
918
- cxt.eval('o.foo()').should == "bar"
919
- end
920
- end
921
- end
922
- end
data/spec/redjs/loadme.js DELETED
@@ -1 +0,0 @@
1
- "I am Legend"