therubyracer 0.11.0beta8 → 0.11.0
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/Changelog.md +2 -2
- data/README.md +24 -23
- data/ext/v8/backref.cc +5 -14
- data/ext/v8/rr.h +59 -8
- data/lib/v8/context.rb +3 -1
- data/lib/v8/error.rb +36 -4
- data/lib/v8/version.rb +1 -1
- data/therubyracer.gemspec +2 -2
- metadata +12 -9
data/Changelog.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## 0.11
|
3
|
+
## 0.11.0 2012/12/04
|
4
4
|
|
5
5
|
* upgrade V8 version to 3.11.8
|
6
6
|
* remove dependency on libv8. enable compilation against system v8
|
@@ -91,7 +91,7 @@
|
|
91
91
|
* upgrade to rspec 2
|
92
92
|
* several bug fixes and stability fixes
|
93
93
|
|
94
|
-
## 0.7.5 -
|
94
|
+
## 0.7.5 - 2010/08/03
|
95
95
|
|
96
96
|
* upgrade to V8 2.3.3
|
97
97
|
* property interceptors from ruby via [] and []=
|
data/README.md
CHANGED
@@ -7,13 +7,13 @@
|
|
7
7
|
|
8
8
|
## DESCRIPTION
|
9
9
|
|
10
|
-
Embed the V8
|
10
|
+
Embed the V8 JavaScript interpreter into Ruby.
|
11
11
|
|
12
12
|
|
13
13
|
## FEATURES
|
14
14
|
|
15
|
-
* Evaluate
|
16
|
-
* Embed your Ruby objects into the
|
15
|
+
* Evaluate JavaScript from within Ruby
|
16
|
+
* Embed your Ruby objects into the JavaScript world
|
17
17
|
* Manipulate JavaScript objects and call JavaScript functions from Ruby
|
18
18
|
* API compatible with the The Ruby Rhino (for JRuby: http://github.com/cowboyd/therubyrhino)
|
19
19
|
|
@@ -21,13 +21,13 @@ Embed the V8 Javascript interpreter into Ruby.
|
|
21
21
|
|
22
22
|
gem install therubyracer
|
23
23
|
|
24
|
-
then in your
|
24
|
+
then in your Ruby code
|
25
25
|
|
26
26
|
require 'v8'
|
27
27
|
# or if using bundler (as with Rails), add the following to your Gemfile
|
28
28
|
gem "therubyracer", :require => 'v8'
|
29
29
|
|
30
|
-
evaluate some simple
|
30
|
+
evaluate some simple JavaScript
|
31
31
|
|
32
32
|
cxt = V8::Context.new
|
33
33
|
cxt.eval('7 * 6') #=> 42
|
@@ -37,12 +37,12 @@ embed values into the scope of your context
|
|
37
37
|
cxt['foo'] = "bar"
|
38
38
|
cxt.eval('foo') # => "bar"
|
39
39
|
|
40
|
-
embed
|
40
|
+
embed Ruby code into your scope and call it from JavaScript
|
41
41
|
|
42
42
|
cxt["say"] = lambda {|this, word, times| word * times}
|
43
43
|
cxt.eval("say('Hello', 3)") #=> HelloHelloHello
|
44
44
|
|
45
|
-
embed a
|
45
|
+
embed a Ruby object into your scope and access its properties/methods from JavaScript
|
46
46
|
|
47
47
|
class MyMath
|
48
48
|
def plus(lhs, rhs)
|
@@ -53,7 +53,7 @@ embed a ruby object into your scope and access its properties/methods from javas
|
|
53
53
|
cxt['math'] = MyMath.new
|
54
54
|
cxt.eval("math.plus(20,22)") #=> 42
|
55
55
|
|
56
|
-
make a
|
56
|
+
make a Ruby object *be* your global JavaScript scope.
|
57
57
|
|
58
58
|
math = MyMath.new
|
59
59
|
V8::Context.new(:with => math) do |cxt|
|
@@ -64,9 +64,9 @@ you can do the same thing with Object#eval_js
|
|
64
64
|
|
65
65
|
math.eval_js("plus(20,22)")
|
66
66
|
|
67
|
-
## Different ways of loading
|
67
|
+
## Different ways of loading JavaScript source
|
68
68
|
|
69
|
-
In addition to just evaluating strings, you can also use streams such as files.
|
69
|
+
In addition to just evaluating strings, you can also use streams, such as files.
|
70
70
|
|
71
71
|
evaluate bytes read from any File/IO object:
|
72
72
|
|
@@ -81,11 +81,11 @@ or load it by filename
|
|
81
81
|
|
82
82
|
## Safe by default, dangerous by demand
|
83
83
|
|
84
|
-
The Ruby Racer is designed to let you evaluate
|
85
|
-
dangerous. The default context is a hermetically sealed
|
86
|
-
and functions. Nothing from the
|
84
|
+
The Ruby Racer is designed to let you evaluate JavaScript as safely as possible unless you tell it to do something more
|
85
|
+
dangerous. The default context is a hermetically sealed JavaScript environment with only the standard JavaScript objects
|
86
|
+
and functions. Nothing from the Ruby world is accessible at all.
|
87
87
|
|
88
|
-
For
|
88
|
+
For Ruby objects that you explicitly embed into JavaScript, by default only the _public_ methods _below_ `Object` are
|
89
89
|
exposed by default. E.g.
|
90
90
|
|
91
91
|
class A
|
@@ -118,19 +118,20 @@ exposed by default. E.g.
|
|
118
118
|
If needed, you can override the [Ruby Access](https://github.com/cowboyd/therubyracer/blob/master/lib/v8/access.rb)
|
119
119
|
to allow whatever behavior you'd like
|
120
120
|
|
121
|
-
More documentation can be found on the [
|
121
|
+
More documentation can be found on the [GitHub wiki](https://github.com/cowboyd/therubyracer/wiki)
|
122
122
|
|
123
123
|
## PREREQUISITES
|
124
124
|
|
125
125
|
For platforms for which there is a binary version of therubyracer gem available, there are no
|
126
|
-
|
126
|
+
|
127
|
+
dependencies other than Ruby and rubygems.
|
127
128
|
|
128
129
|
If there is not a binary version for your system, then you will need to compile it from source.
|
129
130
|
To do this, you must have v8 >= 3.11.8 installed somewhere on your system. There are several
|
130
|
-
ways of doing this. For both you will need a C++ compiler.
|
131
|
+
ways of doing this. For both, you will need a C++ compiler.
|
131
132
|
|
132
|
-
The first method involves using a version of the v8 source which is maintained
|
133
|
-
[as a
|
133
|
+
The first method involves using a version of the v8 source, which is maintained
|
134
|
+
[as a RubyGem called libv8][1]. To use it, all you have to do is
|
134
135
|
add the following to your Gemfile:
|
135
136
|
|
136
137
|
gem 'libv8', '~> 3.11.8'
|
@@ -139,9 +140,9 @@ This will download and build v8 from source for you as part of the gem installat
|
|
139
140
|
process. When therubyracer is installed, it will find this gem if it is present and
|
140
141
|
link against the v8 binaries contained therein.
|
141
142
|
|
142
|
-
If you cannot, or do not wish to use the libv8
|
143
|
-
|
144
|
-
|
143
|
+
If you cannot, or do not wish to use the libv8 RubyGem, you can either install libv8
|
144
|
+
with you operating system's packaging system or you can [build it from source][2]. If
|
145
|
+
you build from source, be sure to set the library=shared option. Also, if you install
|
145
146
|
this shared library into a place that is not on your standard lib and include paths, then
|
146
147
|
you can pass your non-standard locations to therubyracer using the
|
147
148
|
`--with-v8-include` and `--with-v8-lib` configuration options.
|
@@ -182,4 +183,4 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
182
183
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
183
184
|
|
184
185
|
[1]: https://github.com/cowboyd/libv8
|
185
|
-
[2]: http://code.google.com/p/v8/wiki/BuildingWithGYP
|
186
|
+
[2]: http://code.google.com/p/v8/wiki/BuildingWithGYP
|
data/ext/v8/backref.cc
CHANGED
@@ -14,32 +14,23 @@ namespace rr {
|
|
14
14
|
}
|
15
15
|
|
16
16
|
Backref::Backref(VALUE initial) {
|
17
|
-
|
17
|
+
set(initial);
|
18
|
+
rb_gc_register_address(&storage);
|
18
19
|
}
|
19
20
|
|
20
21
|
Backref::~Backref() {
|
21
|
-
|
22
|
+
rb_gc_unregister_address(&storage);
|
22
23
|
}
|
23
24
|
|
24
|
-
|
25
|
+
VALUE Backref::set(VALUE data) {
|
25
26
|
this->storage = rb_funcall(Storage, _new, 1, data);
|
26
|
-
|
27
|
-
}
|
28
|
-
|
29
|
-
void Backref::deallocate() {
|
30
|
-
rb_gc_unregister_address(&storage);
|
27
|
+
return data;
|
31
28
|
}
|
32
29
|
|
33
30
|
VALUE Backref::get() {
|
34
31
|
return rb_funcall(storage, object, 0);
|
35
32
|
}
|
36
33
|
|
37
|
-
VALUE Backref::set(VALUE data) {
|
38
|
-
deallocate();
|
39
|
-
allocate(data);
|
40
|
-
return data;
|
41
|
-
}
|
42
|
-
|
43
34
|
v8::Handle<v8::Value> Backref::toExternal() {
|
44
35
|
v8::Local<v8::Value> wrapper = v8::External::Wrap(this);
|
45
36
|
v8::Persistent<v8::Value>::New(wrapper).MakeWeak(this, &release);
|
data/ext/v8/rr.h
CHANGED
@@ -96,6 +96,28 @@ private:
|
|
96
96
|
|
97
97
|
/**
|
98
98
|
* A pointer to V8 object managed by Ruby
|
99
|
+
*
|
100
|
+
* You deal with V8 objects as either pointers or handles.
|
101
|
+
* While handles are managed by the V8 garbage collector, pointers
|
102
|
+
* must be explicitly created and destroyed by your code.
|
103
|
+
*
|
104
|
+
* The pointer class provides a handly way to wrap V8 pointers
|
105
|
+
* into Ruby objects so that they will be deleted when the
|
106
|
+
* Ruby object is garbage collected. Automatic type coercion is
|
107
|
+
* used to make wrapping and unwrapping painless.
|
108
|
+
*
|
109
|
+
* To create Ruby VALUE:
|
110
|
+
*
|
111
|
+
* Pointer<v8::ScriptOrigin> ptr(new v8::ScriptOrigin());
|
112
|
+
* VALUE value = ptr; //automatically wraps in Data_Wrap_Struct
|
113
|
+
*
|
114
|
+
* Conversely, the pointer can be unwrapped from a struct
|
115
|
+
* created in this way and the underlying methods can be
|
116
|
+
* invoked:
|
117
|
+
*
|
118
|
+
* VALUE value = ...;
|
119
|
+
* Pointer<v8::ScriptOrigin> ptr(value);
|
120
|
+
* ptr->CallMethod();
|
99
121
|
*/
|
100
122
|
|
101
123
|
template <class T> class Pointer {
|
@@ -125,6 +147,29 @@ template <class T> VALUE Pointer<T>::Class;
|
|
125
147
|
|
126
148
|
/**
|
127
149
|
* A Reference to a V8 managed object
|
150
|
+
*
|
151
|
+
* Uses type coercion to quickly convert from a v8 handle
|
152
|
+
* to a ruby object and back again. Suppose we have a v8 handle
|
153
|
+
* that we want to return to Ruby. We can put it into a Ref:
|
154
|
+
*
|
155
|
+
* v8::Handle<v8::Object> object = v8::Object::New();
|
156
|
+
* VALUE val = Ref<v8::Object>(object);
|
157
|
+
*
|
158
|
+
* this will create a `v8::Persistent` handle for the object
|
159
|
+
* so that it will not be garbage collected by v8. It then
|
160
|
+
* stuffs this new persistent handle into a Data_Wrap_Struct
|
161
|
+
* which can then be passed to Ruby code. When this struct
|
162
|
+
* is garbage collected by Ruby, it enqueues the corresponding
|
163
|
+
* v8 handle to be released during v8 gc.
|
164
|
+
*
|
165
|
+
* By the same token, you can use Refs to unwrap a Data_Wrap_Struct
|
166
|
+
* which has been generated in this fashion and call through to
|
167
|
+
* the underlying v8 methods. Suppose we are passed a VALUE `val`
|
168
|
+
* wrapping a v8::Object:
|
169
|
+
*
|
170
|
+
* Ref<v8::Object> object(val);
|
171
|
+
* object->Get(v8::String::New("foo"));
|
172
|
+
*
|
128
173
|
*/
|
129
174
|
template <class T> class Ref {
|
130
175
|
public:
|
@@ -135,9 +180,15 @@ public:
|
|
135
180
|
this->handle = handle;
|
136
181
|
}
|
137
182
|
virtual ~Ref() {}
|
183
|
+
/*
|
184
|
+
* Coerce a Ref into a Ruby VALUE
|
185
|
+
*/
|
138
186
|
virtual operator VALUE() const {
|
139
|
-
return handle.IsEmpty() ? Qnil : (new Holder(handle
|
187
|
+
return handle.IsEmpty() ? Qnil : Data_Wrap_Struct(Class, 0, &Holder::enqueue, new Holder(handle));
|
140
188
|
}
|
189
|
+
/*
|
190
|
+
* Coerce a Ref into a v8::Handle.
|
191
|
+
*/
|
141
192
|
virtual operator v8::Handle<T>() const {
|
142
193
|
if (RTEST(this->value)) {
|
143
194
|
Holder* holder = NULL;
|
@@ -153,6 +204,12 @@ public:
|
|
153
204
|
holder->dispose();
|
154
205
|
}
|
155
206
|
|
207
|
+
/*
|
208
|
+
* Pointer de-reference operators, this lets you use a ref to
|
209
|
+
* call through to underlying v8 methods. e.g
|
210
|
+
*
|
211
|
+
* Ref<v8::Object>(value)->ToString();
|
212
|
+
*/
|
156
213
|
inline v8::Handle<T> operator->() const { return *this;}
|
157
214
|
inline v8::Handle<T> operator*() const {return *this;}
|
158
215
|
|
@@ -173,10 +230,9 @@ public:
|
|
173
230
|
class Holder {
|
174
231
|
friend class Ref;
|
175
232
|
public:
|
176
|
-
Holder(v8::Handle<T> handle
|
233
|
+
Holder(v8::Handle<T> handle) {
|
177
234
|
this->disposed_p = false;
|
178
235
|
this->handle = v8::Persistent<T>::New(handle);
|
179
|
-
this->value = Data_Wrap_Struct(klass, 0, &enqueue, this);
|
180
236
|
}
|
181
237
|
virtual ~Holder() {
|
182
238
|
this->dispose();
|
@@ -188,12 +244,10 @@ public:
|
|
188
244
|
}
|
189
245
|
}
|
190
246
|
protected:
|
191
|
-
VALUE value;
|
192
247
|
v8::Persistent<T> handle;
|
193
248
|
bool disposed_p;
|
194
249
|
|
195
250
|
static void enqueue(Holder* holder) {
|
196
|
-
holder->value = Qnil;
|
197
251
|
GC::Finalize(holder);
|
198
252
|
}
|
199
253
|
};
|
@@ -214,8 +268,6 @@ public:
|
|
214
268
|
v8::Handle<v8::Value> toExternal();
|
215
269
|
static void release(v8::Persistent<v8::Value> handle, void* data);
|
216
270
|
private:
|
217
|
-
void allocate(VALUE data);
|
218
|
-
void deallocate();
|
219
271
|
VALUE storage;
|
220
272
|
static VALUE Storage;
|
221
273
|
static ID _new;
|
@@ -564,7 +616,6 @@ public:
|
|
564
616
|
inline Object(VALUE value) : Ref<v8::Object>(value) {}
|
565
617
|
inline Object(v8::Handle<v8::Object> object) : Ref<v8::Object>(object) {}
|
566
618
|
virtual operator VALUE();
|
567
|
-
static VALUE toVALUE(VALUE yield, VALUE wrapper);
|
568
619
|
|
569
620
|
protected:
|
570
621
|
VALUE downcast();
|
data/lib/v8/context.rb
CHANGED
data/lib/v8/error.rb
CHANGED
@@ -13,8 +13,8 @@ module V8
|
|
13
13
|
# @return [Exception] the underlying error (if any) that triggered this error to be raised
|
14
14
|
attr_reader :cause
|
15
15
|
|
16
|
-
# @!attribute [
|
17
|
-
# @return the complete JavaScript stack at the point this error was thrown
|
16
|
+
# @!attribute [r] javascript_backtrace
|
17
|
+
# @return [V8::StackTrace] the complete JavaScript stack at the point this error was thrown
|
18
18
|
attr_reader :javascript_backtrace
|
19
19
|
|
20
20
|
# keep an alias to the StandardError#backtrace method so that we can capture
|
@@ -103,6 +103,40 @@ module V8
|
|
103
103
|
|
104
104
|
end
|
105
105
|
|
106
|
+
# Convert the result of a triggered JavaScript try/catch block into
|
107
|
+
# a V8::Error
|
108
|
+
#
|
109
|
+
# This is a bit of a yak-shave because JavaScript let's you throw all
|
110
|
+
# kinds of things. We do our best to make sure that the message property
|
111
|
+
# of the resulting V8::Error is as helpful as possible, and that it
|
112
|
+
# contains as much source location information as we can put onto it.
|
113
|
+
#
|
114
|
+
# For example:
|
115
|
+
#
|
116
|
+
# throw 4
|
117
|
+
# throw 'four'
|
118
|
+
# throw {number: 4}
|
119
|
+
#
|
120
|
+
# are all valid cases, none of which actually reference an exception object
|
121
|
+
# with a stack trace and a message. only with something like:
|
122
|
+
#
|
123
|
+
# throw new Error('fail!')
|
124
|
+
#
|
125
|
+
# do you get the a proper stacktrace and a message property. However a lot of
|
126
|
+
# times JavaScript library authors are lazy and do this:
|
127
|
+
#
|
128
|
+
# throw {message: 'foo', otherMetadata: 'bar'}
|
129
|
+
#
|
130
|
+
# It's common enough so we do the courtesy of having the resulting V8::Error
|
131
|
+
# have as its message in ruby land the 'message' property of the value object
|
132
|
+
#
|
133
|
+
# To further complicate things, SyntaxErrors do not have a JavaScript stack
|
134
|
+
# (even if they occur during js execution). This can make debugging a nightmare
|
135
|
+
# so we copy in the source location of the syntax error into the message of
|
136
|
+
# the resulting V8::Error
|
137
|
+
#
|
138
|
+
# @param [V8::C::TryCatch] native trycatch object that has been triggered
|
139
|
+
# @return [V8::Error] the error generated by this try/catch
|
106
140
|
def self.Error(trycatch)
|
107
141
|
exception = trycatch.Exception()
|
108
142
|
value = exception.to_ruby
|
@@ -114,8 +148,6 @@ module V8
|
|
114
148
|
if cause = exception.GetHiddenValue("rr::Cause")
|
115
149
|
cause = cause.Value()
|
116
150
|
end
|
117
|
-
# SyntaxErrors do not have a JavaScript stack (even if they occur during js execution).
|
118
|
-
# To caputre where the error occured, we need to put it in the message
|
119
151
|
if value['constructor'] == V8::Context.current['SyntaxError']
|
120
152
|
info = trycatch.Message()
|
121
153
|
resource_name = info.GetScriptResourceName().to_ruby
|
data/lib/v8/version.rb
CHANGED
data/therubyracer.gemspec
CHANGED
@@ -4,8 +4,8 @@ require File.expand_path('../lib/v8/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Charles Lowell"]
|
6
6
|
gem.email = ["javascript-and-friends@googlegroups.com"]
|
7
|
-
gem.summary = "Embed the V8
|
8
|
-
gem.description = "Call
|
7
|
+
gem.summary = "Embed the V8 JavaScript interpreter into Ruby"
|
8
|
+
gem.description = "Call JavaScript code and manipulate JavaScript objects from Ruby. Call Ruby code and manipulate Ruby objects from JavaScript."
|
9
9
|
gem.homepage = "http://github.com/cowboyd/therubyracer"
|
10
10
|
|
11
11
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: therubyracer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
5
|
-
prerelease:
|
4
|
+
version: 0.11.0
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Charles Lowell
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ref
|
@@ -27,8 +27,8 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
|
-
description: Call
|
31
|
-
|
30
|
+
description: Call JavaScript code and manipulate JavaScript objects from Ruby. Call
|
31
|
+
Ruby code and manipulate Ruby objects from JavaScript.
|
32
32
|
email:
|
33
33
|
- javascript-and-friends@googlegroups.com
|
34
34
|
executables: []
|
@@ -141,19 +141,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
141
141
|
version: '0'
|
142
142
|
segments:
|
143
143
|
- 0
|
144
|
-
hash: -
|
144
|
+
hash: -1132929021972714729
|
145
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
146
|
none: false
|
147
147
|
requirements:
|
148
|
-
- - ! '
|
148
|
+
- - ! '>='
|
149
149
|
- !ruby/object:Gem::Version
|
150
|
-
version:
|
150
|
+
version: '0'
|
151
|
+
segments:
|
152
|
+
- 0
|
153
|
+
hash: -1132929021972714729
|
151
154
|
requirements: []
|
152
155
|
rubyforge_project:
|
153
156
|
rubygems_version: 1.8.24
|
154
157
|
signing_key:
|
155
158
|
specification_version: 3
|
156
|
-
summary: Embed the V8
|
159
|
+
summary: Embed the V8 JavaScript interpreter into Ruby
|
157
160
|
test_files:
|
158
161
|
- spec/c/array_spec.rb
|
159
162
|
- spec/c/constants_spec.rb
|