therubyracer 0.5.0-x86-darwin-9 → 0.5.1-x86-darwin-9

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/History.txt CHANGED
@@ -1,3 +1,7 @@
1
+ === 0.5.1 2010-02-17
2
+ * 1 minor enhancement
3
+ * fix bug in 1.8.6 by creating Object#tap if it does not exist
4
+
1
5
  === 0.5.0 2010-02-17
2
6
  * 1 major enhancement
3
7
  * support for Linux 64 bit
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ begin
9
9
  require 'jeweler'
10
10
  Jeweler::Tasks.new do |gemspec|
11
11
  gemspec.name = gemspec.rubyforge_project = "therubyracer"
12
- gemspec.version = "0.5.0"
12
+ gemspec.version = "0.5.1"
13
13
  gemspec.summary = "Embed the V8 Javascript interpreter into Ruby"
14
14
  gemspec.description = "Call javascript code and manipulate javascript objects from ruby. Call ruby code and manipulate ruby objects from javascript."
15
15
  gemspec.email = "cowboyd@thefrontside.net"
@@ -34,6 +34,12 @@ rescue LoadError
34
34
  puts "Rake Compiler not available. Install it with: gem install rake-compiler"
35
35
  end
36
36
 
37
+ require 'spec/rake/spectask'
38
+ Spec::Rake::SpecTask.new(:spec) do |spec|
39
+ spec.libs << 'lib' << 'spec'
40
+ spec.spec_files = FileList['spec/**/*_spec.rb']
41
+ end
42
+
37
43
  desc "Build gem"
38
44
  task :gem => :build
39
45
 
data/lib/v8/tap.rb ADDED
@@ -0,0 +1,8 @@
1
+
2
+ unless Object.method_defined?(:tap)
3
+ class Object
4
+ def tap
5
+ yield self
6
+ end
7
+ end
8
+ end
data/lib/v8/v8.bundle CHANGED
Binary file
data/lib/v8.rb CHANGED
@@ -2,9 +2,10 @@ $:.unshift(File.dirname(__FILE__)) unless
2
2
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
3
 
4
4
  module V8
5
- VERSION = '0.5.0'
5
+ VERSION = '0.5.1'
6
6
  require 'v8/v8' #native glue
7
7
  require 'v8/to'
8
8
  require 'v8/context'
9
9
  require 'v8/object'
10
+ require 'v8/tap'
10
11
  end
@@ -0,0 +1,405 @@
1
+
2
+ require "#{File.dirname(__FILE__)}/../redjs_helper.rb"
3
+
4
+ describe "Ruby Javascript API" do
5
+
6
+ describe "Basic Evaluation" do
7
+ it "can evaluate some javascript" do
8
+ Context.eval("5 + 3")
9
+ end
10
+
11
+ it "can pass back null to ruby" do
12
+ Context.eval("null").should be_nil
13
+ end
14
+
15
+ it "can pass back undefined to ruby" do
16
+ Context.eval("this.undefined").should be_nil
17
+ end
18
+
19
+ it "can pass the empty string back to ruby" do
20
+ Context.eval("''").should == ""
21
+ end
22
+
23
+ it "can pass doubles back to ruby" do
24
+ Context.eval("2.5").should == 2.5
25
+ end
26
+
27
+ it "can pass fixed numbers back to ruby" do
28
+ Context.eval("1").should == 1
29
+ end
30
+
31
+ it "can pass boolean values back to ruby" do
32
+ Context.eval("true").should be(true)
33
+ Context.eval("false").should be(false)
34
+ end
35
+
36
+ it "treats nil and the empty string as the same thing when it comes to eval" do
37
+ Context.eval(nil).should == Context.eval('')
38
+ end
39
+
40
+ it "can pass back strings to ruby" do
41
+ Context.open do |cxt|
42
+ cxt['foo'] = "Hello World"
43
+ cxt.eval("foo").should == "Hello World"
44
+ end
45
+ end
46
+
47
+ it "can pass back very long strings to ruby" do
48
+ 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."
49
+ Context.open do |cxt|
50
+ cxt.eval("'#{lorem}'").should == lorem
51
+ end
52
+ end
53
+
54
+ it "can pass objects back to ruby" do
55
+ Context.open do |cxt|
56
+ cxt.eval("({foo: 'bar', baz: 'bang', '5': 5, embedded: {badda: 'bing'}})").tap do |object|
57
+ object.should_not be_nil
58
+ object['foo'].should == 'bar'
59
+ object['baz'].should == 'bang'
60
+ object['5'].should == 5
61
+ object['embedded'].tap do |embedded|
62
+ embedded.should_not be_nil
63
+ embedded['badda'].should == 'bing'
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ it "unwraps ruby objects returned by embedded ruby code to maintain referential integrity" do
70
+ Object.new.tap do |o|
71
+ Context.open do |cxt|
72
+ cxt['get'] = lambda {o}
73
+ cxt.eval('get()').should be(o)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "Calling Ruby Code From Within Javascript" do
80
+
81
+ before(:each) do
82
+ @class = Class.new
83
+ @instance = @class.new
84
+ end
85
+
86
+ it "can embed a closure into a context and call it" do
87
+ Context.open do |cxt|
88
+ cxt["say"] = lambda {|word, times| word * times}
89
+ cxt.eval("say('Hello',2)").should == "HelloHello"
90
+ end
91
+ end
92
+
93
+ it "can embed a ruby object into a context and call its methods" do
94
+ class_eval do
95
+ def say_hello(to)
96
+ "Hello #{to}!"
97
+ end
98
+ end
99
+ evaljs('o.say_hello("Gracie")').should == "Hello Gracie!"
100
+ end
101
+
102
+ it "can call a bound ruby method" do
103
+ five = class_eval do
104
+ def initialize(lhs)
105
+ @lhs = lhs
106
+ end
107
+ def times(rhs)
108
+ @lhs * rhs
109
+ end
110
+ new(5)
111
+ end
112
+ Context.open do |cxt|
113
+ cxt['timesfive'] = five.method(:times)
114
+ cxt.eval('timesfive(3)').should == 15
115
+ end
116
+ end
117
+
118
+ it "reports ruby methods that do not exist as undefined" do
119
+ Context.open(:with => Object.new) do |cxt|
120
+ cxt.eval('this.foobar').should be_nil
121
+ end
122
+ end
123
+
124
+ it "can call public locally defined ruby methods" do
125
+ class_eval do
126
+ def voo(str)
127
+ "voo#{str}"
128
+ end
129
+ end
130
+ evaljs("o.voo('doo')").should == "voodoo"
131
+ end
132
+
133
+ it "translates ruby naming conventions into javascript naming conventions, but you can still access them by their original names" do
134
+ class_eval do
135
+ def my_special_method(to)
136
+ "hello #{to}"
137
+ end
138
+ end
139
+ evaljs("o.mySpecialMethod('Frank')").should == "hello Frank"
140
+ evaljs("o.my_special_method('Jack')").should == "hello Jack"
141
+ end
142
+
143
+ it "hides methods not defined directly on this instance's class" do
144
+ class_eval do
145
+ def bar
146
+ end
147
+ end
148
+ evaljs("o.to_s").should be_nil
149
+ end
150
+
151
+ it "translated camel case properties are enumerated by default, but perl case are not" do
152
+ class_eval do
153
+ def foo_bar
154
+ end
155
+
156
+ def baz_bang
157
+ end
158
+ end
159
+ require 'set'
160
+ evaljs(<<-EOJS).to_set.should == Set.new(["fooBar","bazBang"])
161
+ var names = [];
162
+ for (var p in o) {
163
+ names.push(p);
164
+ }
165
+ names;
166
+ EOJS
167
+ end
168
+
169
+ it "will see a method that appears after the wrapper was first created" do
170
+ Context.open do |cxt|
171
+ cxt['o'] = @instance
172
+ class_eval do
173
+ def whiz(str)
174
+ "whiz#{str}!"
175
+ end
176
+ end
177
+ cxt.eval("o.whiz('bang')").should == "whizbang!"
178
+ end
179
+ end
180
+
181
+ it "treats ruby methods that have an arity of 0 as javascript properties by default" do
182
+ class_eval do
183
+ def property
184
+ "flan!"
185
+ end
186
+ end
187
+ evaljs('o.property').should == 'flan!'
188
+ end
189
+
190
+ it "will call ruby accesssor function when setting a property from javascript" do
191
+ class_eval do
192
+ def dollars
193
+ @dollars
194
+ end
195
+
196
+ def dollars=(amount)
197
+ @dollars = amount
198
+ end
199
+ end
200
+ evaljs('o.dollars = 50')
201
+ @instance.dollars.should == 50
202
+ end
203
+
204
+ it "will accept expando properties by default for properties on ruby object that are not implemented in ruby" do
205
+ evaljs('o.five = 5; o.five').should == 5
206
+ end
207
+
208
+ it "it silently fails to replace properties which are defined on ruby objects but which are read-only" do
209
+ class_eval do
210
+ def bar
211
+ "baz"
212
+ end
213
+ end
214
+ evaljs('o.bar = "bing"; o.bar').should == "baz"
215
+ end
216
+
217
+ def evaljs(str)
218
+ Context.open do |cxt|
219
+ cxt['puts'] = lambda {|o| puts o.inspect}
220
+ cxt['o'] = @instance
221
+ cxt.eval(str)
222
+ end
223
+ end
224
+
225
+ def class_eval(&body)
226
+ @class.class_eval &body
227
+ end
228
+
229
+ end
230
+
231
+ describe "Setting up the Host Environment" do
232
+ it "can eval javascript with a given ruby object as the scope." do
233
+ scope = Class.new.class_eval do
234
+ def plus(lhs, rhs)
235
+ lhs + rhs
236
+ end
237
+
238
+ def minus(lhs, rhs)
239
+ lhs - rhs
240
+ end
241
+
242
+ new
243
+ end
244
+
245
+ Context.open(:with => scope) do |cxt|
246
+ cxt.eval("plus(1,2)").should == 3
247
+ cxt.eval("minus(10, 20)").should == -10
248
+ cxt.eval("this").should be(scope)
249
+ end
250
+ end
251
+
252
+ it "can directly embed ruby values into javascript" do
253
+ Context.open do |cxt|
254
+ cxt["bar"] = 9
255
+ cxt['foo'] = "bar"
256
+ cxt['num'] = 3.14
257
+ cxt['trU'] = true
258
+ cxt['falls'] = false
259
+ cxt.eval("bar + 10").should be(19)
260
+ cxt.eval('foo').should == "bar"
261
+ cxt.eval('num').should == 3.14
262
+ cxt.eval('trU').should be(true)
263
+ cxt.eval('falls').should be(false)
264
+ end
265
+ end
266
+
267
+ it "extends object to allow for the arbitrary execution of javascript with any object as the scope" do
268
+ Class.new.class_eval do
269
+
270
+ def initialize
271
+ @lhs = 5
272
+ end
273
+
274
+ def timesfive(rhs)
275
+ @lhs * rhs
276
+ end
277
+
278
+ new.eval_js("timesfive(6)").should == 30
279
+ end
280
+ end
281
+
282
+ it "can limit the number of instructions that are executed in the context" do
283
+ pending "haven't figured out how to constrain resources in V8"
284
+ lambda {
285
+ Context.open do |cxt|
286
+ cxt.instruction_limit = 100 * 1000
287
+ timeout(1) do
288
+ cxt.eval('while (true);')
289
+ end
290
+ end
291
+ }.should raise_error(RunawayScriptError)
292
+ end
293
+ end
294
+
295
+ describe "loading javascript source into the interpreter" do
296
+
297
+ it "can take an IO object in the eval method instead of a string" do
298
+ source = StringIO.new(<<-EOJS)
299
+ /*
300
+ * we want to have a fairly verbose function so that we can be assured tha
301
+ * we overflow the buffer size so that we see that the reader is chunking
302
+ * it's payload in at least several fragments.
303
+ *
304
+ * That's why we're wasting space here
305
+ */
306
+ function five() {
307
+ return 5
308
+ }
309
+ foo = 'bar'
310
+ five();
311
+ EOJS
312
+ Context.open do |cxt|
313
+ cxt.eval(source, "StringIO").should == 5
314
+ cxt['foo'].should == "bar"
315
+ end
316
+ end
317
+
318
+ it "can load a file into the runtime" do
319
+ mock(:JavascriptSourceFile).tap do |file|
320
+ File.should_receive(:open).with("path/to/mysource.js").and_yield(file)
321
+ Context.open do |cxt|
322
+ cxt.should_receive(:evaluate).with(file, "path/to/mysource.js", 1)
323
+ cxt.load("path/to/mysource.js")
324
+ end
325
+ end
326
+
327
+ end
328
+ end
329
+
330
+ describe "A Javascript Object Reflected Into Ruby" do
331
+
332
+ before(:each) do
333
+ @o = Context.open do |cxt|
334
+ @cxt = cxt
335
+ cxt.eval("o = new Object(); o")
336
+ end
337
+ end
338
+
339
+ def evaljs(js)
340
+ @cxt.open do
341
+ @cxt.eval(js)
342
+ end
343
+ end
344
+
345
+ it "can have its properties manipulated via ruby style [] hash access" do
346
+ @o["foo"] = 'bar'
347
+ evaljs('o.foo').should == "bar"
348
+ evaljs('o.blue = "blam"')
349
+ @o["blue"].should == "blam"
350
+ end
351
+
352
+ it "doesn't matter if you use a symbol or a string to set a value" do
353
+ @o[:foo] = "bar"
354
+ @o['foo'].should == "bar"
355
+ @o['baz'] = "bang"
356
+ @o[:baz].should == "bang"
357
+ end
358
+
359
+ it "returns nil when the value is null, null, or not defined" do
360
+ @o[:foo].should be_nil
361
+ end
362
+
363
+ it "traverses the prototype chain when hash accessing properties from the ruby object" do
364
+ Context.open do |cxt|
365
+ cxt.eval(<<EOJS)['bar'].should == "baz"
366
+ function Foo() {}
367
+ Foo.prototype.bar = 'baz'
368
+ new Foo()
369
+ EOJS
370
+ end
371
+ end
372
+
373
+ it "is enumenable" do
374
+ @cxt.open do
375
+ evaljs("o.foo = 'bar'; o.bang = 'baz'; o[5] = 'flip'")
376
+ @o.inject({}) {|i,p| k,v = p; i.tap {i[k] = v}}.should == {"foo" => 'bar', "bang" => 'baz', 5 => 'flip'}
377
+ end
378
+ end
379
+ end
380
+
381
+ describe "Exception Handling" do
382
+ it "raises javascript exceptions as ruby exceptions" do
383
+ lambda {
384
+ Context.new.eval('foo')
385
+ }.should raise_error(JavascriptError)
386
+ end
387
+
388
+ it "can handle syntax errors" do
389
+ lambda {
390
+ Context.eval('does not compiles')
391
+ }.should raise_error
392
+ end
393
+
394
+ it "should track message state" do
395
+ begin
396
+ Context.open do |cxt|
397
+ cxt.eval("var foo = 'bar';\nsyntax error!", "foo.js")
398
+ end
399
+ rescue JavascriptError => e
400
+ e.line_number.should == 2
401
+ e.source_name.should == "foo.js"
402
+ end
403
+ end
404
+ end
405
+ end
data/therubyracer.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{therubyracer}
8
- s.version = "0.5.0"
8
+ s.version = "0.5.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Charles Lowell", "Bill Robertson"]
12
- s.date = %q{2010-02-16}
12
+ s.date = %q{2010-02-17}
13
13
  s.description = %q{Call javascript code and manipulate javascript objects from ruby. Call ruby code and manipulate ruby objects from javascript.}
14
14
  s.email = %q{cowboyd@thefrontside.net}
15
15
  s.extensions = ["ext/v8/extconf.rb"]
@@ -639,6 +639,7 @@ Gem::Specification.new do |s|
639
639
  "lib/v8.rb",
640
640
  "lib/v8/context.rb",
641
641
  "lib/v8/object.rb",
642
+ "lib/v8/tap.rb",
642
643
  "lib/v8/to.rb",
643
644
  "script/console",
644
645
  "script/destroy",
@@ -661,6 +662,7 @@ Gem::Specification.new do |s|
661
662
  s.test_files = [
662
663
  "spec/ext/cxt_spec.rb",
663
664
  "spec/ext/obj_spec.rb",
665
+ "spec/redjs/jsapi_spec.rb",
664
666
  "spec/redjs_helper.rb",
665
667
  "spec/spec_helper.rb",
666
668
  "spec/v8/to_spec.rb"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: therubyracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: x86-darwin-9
6
6
  authors:
7
7
  - Charles Lowell
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-02-16 00:00:00 -06:00
13
+ date: 2010-02-17 00:00:00 -06:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -606,6 +606,7 @@ files:
606
606
  - ext/v8/upstream/2.0.6/src/ia32/jump-target-ia32.cc
607
607
  - ext/v8/upstream/scons/engine/SCons/Executor.py
608
608
  - ext/v8/upstream/2.0.6/src/arm/builtins-arm.cc
609
+ - lib/v8/tap.rb
609
610
  - ext/v8/v8_template.cpp
610
611
  - spec/v8/to_spec.rb
611
612
  - ext/v8/upstream/scons/engine/SCons/Node/__init__.py
@@ -657,6 +658,7 @@ files:
657
658
  - ext/v8/upstream/2.0.6/src/ia32/debug-ia32.cc
658
659
  - ext/v8/upstream/2.0.6/src/disassembler.cc
659
660
  - ext/v8/upstream/2.0.6/src/objects-debug.cc
661
+ - spec/redjs/jsapi_spec.rb
660
662
  - lib/v8/v8.bundle
661
663
  has_rdoc: true
662
664
  homepage: http://github.com/cowboyd/therubyracer
@@ -689,6 +691,7 @@ summary: Embed the V8 Javascript interpreter into Ruby
689
691
  test_files:
690
692
  - spec/ext/cxt_spec.rb
691
693
  - spec/ext/obj_spec.rb
694
+ - spec/redjs/jsapi_spec.rb
692
695
  - spec/redjs_helper.rb
693
696
  - spec/spec_helper.rb
694
697
  - spec/v8/to_spec.rb