therubyracer 0.4.4 → 0.4.5
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 +9 -1
- data/Manifest.txt +1 -0
- data/ext/v8/callbacks.cpp +136 -1
- data/ext/v8/callbacks.h +6 -0
- data/ext/v8/converters.cpp +8 -22
- data/ext/v8/converters.h +0 -2
- data/ext/v8/v8_cxt.cpp +3 -1
- data/ext/v8/v8_obj.cpp +1 -0
- data/ext/v8/v8_template.cpp +16 -0
- data/ext/v8/v8_template.h +2 -0
- data/lib/v8.rb +1 -1
- data/lib/v8/context.rb +5 -3
- data/lib/v8/to.rb +6 -2
- data/spec/redjs/jsapi_spec.rb +54 -21
- data/spec/v8/to_spec.rb +15 -0
- data/therubyracer.gemspec +2 -2
- metadata +3 -2
data/History.txt
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
=== 0.
|
1
|
+
=== 0.4.5 2010-01-18
|
2
|
+
* 3 major enhancements
|
3
|
+
* case munging so that ruby methods(perl_case) are accessed through javascript in camelCase.
|
4
|
+
* access 0-arity ruby methods as javascript properties
|
5
|
+
* invoke ruby setters from javascript as properties
|
6
|
+
* 1 minor enhancements
|
7
|
+
* contexts detect whether they are open or not and open when needed
|
8
|
+
|
9
|
+
=== 0.4.4 2010-01-14
|
2
10
|
* 2 major enhancements:
|
3
11
|
* Ruby objects embedded into javascript are passed back to ruby as themselves and not a wrapped V8 object wrapping a ruby object.
|
4
12
|
* Use any ruby object as the scope of eval().
|
data/Manifest.txt
CHANGED
data/ext/v8/callbacks.cpp
CHANGED
@@ -5,6 +5,39 @@
|
|
5
5
|
|
6
6
|
using namespace v8;
|
7
7
|
|
8
|
+
namespace {
|
9
|
+
VALUE unwrap(const AccessorInfo& info) {
|
10
|
+
return (VALUE)External::Unwrap(info.Data());
|
11
|
+
}
|
12
|
+
|
13
|
+
Local<Array> TO_ARRAY(Arguments& args) {
|
14
|
+
Local<Array> array = Array::New(args.Length());
|
15
|
+
for (int i = 0; i < args.Length(); i++) {
|
16
|
+
array->Set(Integer::New(i), args[i]);
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
Local<Value> Racer_Call_Ruby_Method(VALUE object, VALUE method, Local<Array> args) {
|
21
|
+
VALUE * arguments = new VALUE[args->Length()];
|
22
|
+
for (unsigned int i = 0; i < args->Length(); i++) {
|
23
|
+
Handle<Value> val = args->Get(Integer::New(i));
|
24
|
+
arguments[i] = V82RB(val);
|
25
|
+
}
|
26
|
+
VALUE result = rb_funcall2(object, rb_to_id(method), args->Length(), arguments);
|
27
|
+
Local<Value> converted = RB2V8(result);
|
28
|
+
return converted;
|
29
|
+
}
|
30
|
+
|
31
|
+
Local<Value> Racer_Access_Ruby_Property(VALUE object, VALUE name) {
|
32
|
+
VALUE method = rb_obj_method(object, name);
|
33
|
+
if (FIX2INT(rb_funcall(method, rb_intern("arity"), 0)) == 0) {
|
34
|
+
return Racer_Call_Ruby_Method(object, name, Array::New(0));
|
35
|
+
} else {
|
36
|
+
return RB2V8(method);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
8
41
|
Handle<Value> RacerRubyInvocationCallback(const Arguments& args) {
|
9
42
|
VALUE code = (VALUE)External::Unwrap(args.Data());
|
10
43
|
if (NIL_P(code)) {
|
@@ -22,4 +55,106 @@ Handle<Value> RacerRubyInvocationCallback(const Arguments& args) {
|
|
22
55
|
Handle<Value> convertedResult = RB2V8(result);
|
23
56
|
return convertedResult ;
|
24
57
|
}
|
25
|
-
}
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
/**
|
64
|
+
* NamedProperty[Getter|Setter] are used as interceptors on object.
|
65
|
+
* See ObjectTemplate::SetNamedPropertyHandler.
|
66
|
+
*/
|
67
|
+
|
68
|
+
Handle<Value> RacerRubyNamedPropertyGetter(Local<String> property, const AccessorInfo& info) {
|
69
|
+
// printf("Getter '%s'<br/>", *String::AsciiValue(property));
|
70
|
+
if (property->Length() == 0) {
|
71
|
+
return Handle<Value>();
|
72
|
+
}
|
73
|
+
VALUE object = unwrap(info);
|
74
|
+
VALUE camel_name = V82RB((Local<Value>&)property);
|
75
|
+
VALUE perl_name = rb_funcall(V8_To, rb_intern("perl_case"), 1, camel_name);
|
76
|
+
VALUE methods = rb_funcall(object, rb_intern("public_methods"), 1, Qfalse);
|
77
|
+
|
78
|
+
if (RTEST(rb_ary_includes(methods, perl_name))) {
|
79
|
+
return Racer_Access_Ruby_Property(object, perl_name);
|
80
|
+
}
|
81
|
+
if (RTEST(rb_ary_includes(methods, camel_name))) {
|
82
|
+
return Racer_Access_Ruby_Property(object, camel_name);
|
83
|
+
}
|
84
|
+
return Handle<Value>();
|
85
|
+
}
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Returns the value if the setter intercepts the request.
|
89
|
+
* Otherwise, returns an empty handle.
|
90
|
+
*/
|
91
|
+
Handle<Value> RacerRubyNamedPropertySetter(Local<String> property, Local<Value> value, const AccessorInfo& info) {
|
92
|
+
if (property->Length() == 0) {
|
93
|
+
return Handle<Value>();
|
94
|
+
}
|
95
|
+
// printf("Setter: '%s'<br/>", *String::AsciiValue(property));
|
96
|
+
std::string setter = V82String((Handle<Value>&)property);
|
97
|
+
setter += "=";
|
98
|
+
Local<String> setter_name = String::New(setter.c_str());
|
99
|
+
VALUE object = unwrap(info);
|
100
|
+
VALUE camel_name = V82RB((Local<Value>&)setter_name);
|
101
|
+
VALUE perl_name = rb_funcall(V8_To, rb_intern("perl_case"), 1, camel_name);
|
102
|
+
VALUE methods = rb_funcall(object, rb_intern("public_methods"), 1, Qfalse);
|
103
|
+
Local<Array> args = Array::New(1);
|
104
|
+
args->Set(Integer::New(0), value);
|
105
|
+
if (RTEST(rb_ary_includes(methods, perl_name))) {
|
106
|
+
Racer_Call_Ruby_Method(object, perl_name, args);
|
107
|
+
return value;
|
108
|
+
}
|
109
|
+
if (RTEST(rb_ary_includes(methods, camel_name))) {
|
110
|
+
Racer_Call_Ruby_Method(object, camel_name, args);
|
111
|
+
return value;
|
112
|
+
}
|
113
|
+
return Handle<Value>();
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Returns a non-empty handle if the interceptor intercepts the request.
|
118
|
+
* The result is true if the property exists and false otherwise.
|
119
|
+
*/
|
120
|
+
Handle<Boolean> RacerRubyNamedPropertyQuery(Local<String> property, const AccessorInfo& info) {
|
121
|
+
printf("Query: '%s'<br/>", *String::AsciiValue(property));
|
122
|
+
if (property->Length() == 0) {
|
123
|
+
return False();
|
124
|
+
}
|
125
|
+
VALUE object = unwrap(info);
|
126
|
+
VALUE methods = rb_funcall(object, rb_intern("public_methods"), 1, Qfalse);
|
127
|
+
VALUE attr_name = V82RB((Local<Value>&)property);
|
128
|
+
VALUE perl_name = rb_funcall(V8_To, rb_intern("perl_case"), 1, attr_name);
|
129
|
+
|
130
|
+
if (RTEST(rb_ary_includes(methods, attr_name)) || RTEST(rb_ary_includes(methods, perl_name))) {
|
131
|
+
return True();
|
132
|
+
} else {
|
133
|
+
return Handle<Boolean>();
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
/**
|
138
|
+
* Returns a non-empty handle if the deleter intercepts the request.
|
139
|
+
* The return value is true if the property could be deleted and false
|
140
|
+
* otherwise.
|
141
|
+
*/
|
142
|
+
Handle<Boolean> RacerRubyNamedPropertyDeleter(Local<String> property, const AccessorInfo& info) {
|
143
|
+
return False();
|
144
|
+
}
|
145
|
+
|
146
|
+
/**
|
147
|
+
* Returns an array containing the names of the properties the named
|
148
|
+
* property getter intercepts.
|
149
|
+
*/
|
150
|
+
Handle<Array> RacerRubyNamedPropertyEnumerator(const AccessorInfo& info) {
|
151
|
+
VALUE object = unwrap(info);
|
152
|
+
VALUE methods = rb_funcall(object, rb_intern("public_methods"), 1, Qfalse);
|
153
|
+
int length = RARRAY_LEN(methods);
|
154
|
+
Local<Array> properties = Array::New(length);
|
155
|
+
for (int i = 0; i < length; i++) {
|
156
|
+
VALUE camel_name = rb_funcall(V8_To, rb_intern("camel_case"), 1, rb_ary_entry(methods, i));
|
157
|
+
properties->Set(Integer::New(i), RB2V8(camel_name));
|
158
|
+
}
|
159
|
+
return properties;
|
160
|
+
}
|
data/ext/v8/callbacks.h
CHANGED
@@ -5,4 +5,10 @@
|
|
5
5
|
|
6
6
|
v8::Handle<v8::Value> RacerRubyInvocationCallback(const v8::Arguments& args);
|
7
7
|
|
8
|
+
v8::Handle<v8::Value> RacerRubyNamedPropertyGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
|
9
|
+
v8::Handle<v8::Value> RacerRubyNamedPropertySetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
|
10
|
+
v8::Handle<v8::Boolean> RacerRubyNamedPropertyQuery(v8::Local<v8::String> property, const v8::AccessorInfo& info);
|
11
|
+
v8::Handle<v8::Boolean> RacerRubyNamedPropertyDeleter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
|
12
|
+
v8::Handle<v8::Array> RacerRubyNamedPropertyEnumerator(const v8::AccessorInfo& info);
|
13
|
+
|
8
14
|
#endif /* end of include guard: CALLBACKS_H_8VK3LWBG */
|
data/ext/v8/converters.cpp
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
#include "v8_ref.h"
|
4
4
|
#include "v8_obj.h"
|
5
5
|
#include "v8_cxt.h"
|
6
|
+
#include "v8_template.h"
|
6
7
|
|
7
8
|
using namespace v8;
|
8
9
|
|
@@ -32,8 +33,10 @@ VALUE V82RB(Handle<Value>& value) {
|
|
32
33
|
if (value->IsObject()) {
|
33
34
|
Local<Object> object(Object::Cast(*value));
|
34
35
|
Local<Value> peer = object->GetHiddenValue(String::New("TheRubyRacer::RubyObject"));
|
36
|
+
// Local<Value> peer = object->GetInternalField(0);
|
35
37
|
if (peer.IsEmpty()) {
|
36
38
|
VALUE context_ref = V8_Ref_Create(V8_C_Context, Context::GetCurrent());
|
39
|
+
// object->SetPointerInInternalField(1, (void *)context_ref);
|
37
40
|
object->SetHiddenValue(String::New("TheRubyRacer::Context"), External::Wrap((void *)context_ref));
|
38
41
|
return V8_Ref_Create(V8_C_Object, value, context_ref);
|
39
42
|
} else {
|
@@ -55,10 +58,10 @@ Local<Value> RB2V8(VALUE value) {
|
|
55
58
|
if (convert(value, result)) {
|
56
59
|
return result;
|
57
60
|
}
|
58
|
-
Local<
|
59
|
-
|
60
|
-
|
61
|
-
return
|
61
|
+
Local<Object> o = Racer_Create_V8_ObjectTemplate(value)->NewInstance();
|
62
|
+
o->SetHiddenValue(String::New("TheRubyRacer::RubyObject"), External::Wrap((void *) value));
|
63
|
+
// o->SetPointerInInternalField(0, (void*)value);
|
64
|
+
return o;
|
62
65
|
}
|
63
66
|
|
64
67
|
std::string V82String(Handle<Value>& value) {
|
@@ -77,21 +80,4 @@ std::string V82String(Handle<Value>& value) {
|
|
77
80
|
}
|
78
81
|
|
79
82
|
return UNDEFINED_STR;
|
80
|
-
}
|
81
|
-
|
82
|
-
Local<ObjectTemplate> RB_VALUE_2_V8_ObjectTemplate(VALUE value) {
|
83
|
-
Local<ObjectTemplate> tmpl = ObjectTemplate::New();
|
84
|
-
VALUE methods = rb_funcall(value, rb_intern("public_methods"), 1, Qfalse);
|
85
|
-
int len = RARRAY_LEN(methods);
|
86
|
-
for (int i = 0; i < len; i++) {
|
87
|
-
VALUE method_name = RARRAY_PTR(methods)[i];
|
88
|
-
VALUE camel_method_name = rb_funcall(V8_To, rb_intern("camelcase"), 1, method_name);
|
89
|
-
VALUE method = rb_funcall(value, rb_intern("method"), 1, method_name);
|
90
|
-
Local<String> keystr = (String *)*RB2V8(method_name);
|
91
|
-
Local<String> camelstr = (String *)*RB2V8(camel_method_name);
|
92
|
-
Local<FunctionTemplate> fun = FunctionTemplate::New(RacerRubyInvocationCallback, External::Wrap((void *)method));
|
93
|
-
tmpl->Set(keystr, fun);
|
94
|
-
tmpl->Set(camelstr, fun);
|
95
|
-
}
|
96
|
-
return tmpl;
|
97
|
-
}
|
83
|
+
}
|
data/ext/v8/converters.h
CHANGED
data/ext/v8/v8_cxt.cpp
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "v8_cxt.h"
|
2
2
|
#include "v8_msg.h"
|
3
|
+
#include "v8_template.h"
|
3
4
|
#include "converters.h"
|
4
5
|
|
5
6
|
using namespace v8;
|
@@ -16,9 +17,10 @@ VALUE v8_Context_New(int argc, VALUE *argv, VALUE self) {
|
|
16
17
|
if (NIL_P(scope)) {
|
17
18
|
return V8_Ref_Create(self, Context::New());
|
18
19
|
} else {
|
19
|
-
Persistent<Context> context = Context::New(0,
|
20
|
+
Persistent<Context> context = Context::New(0, Racer_Create_V8_ObjectTemplate(scope));
|
20
21
|
Context::Scope enter(context);
|
21
22
|
context->Global()->SetHiddenValue(String::New("TheRubyRacer::RubyObject"), External::Wrap((void *)scope));
|
23
|
+
// context->Global()->SetPointerInInternalField(0, (void*)scope);
|
22
24
|
VALUE ref = V8_Ref_Create(self, context, scope);
|
23
25
|
context.Dispose();
|
24
26
|
return ref;
|
data/ext/v8/v8_obj.cpp
CHANGED
@@ -47,5 +47,6 @@ VALUE v8_Object_context(VALUE self) {
|
|
47
47
|
HandleScope handles;
|
48
48
|
Local<Object> object = unwrap(self);
|
49
49
|
Local<Value> cxt = object->GetHiddenValue(String::New("TheRubyRacer::Context"));
|
50
|
+
// Local<Value> cxt = object->GetInternalField(1);
|
50
51
|
return cxt.IsEmpty() ? Qnil : (VALUE)External::Unwrap(cxt);
|
51
52
|
}
|
data/ext/v8/v8_template.cpp
CHANGED
@@ -7,6 +7,22 @@
|
|
7
7
|
#include "callbacks.h"
|
8
8
|
|
9
9
|
using namespace v8;
|
10
|
+
|
11
|
+
Local<ObjectTemplate> Racer_Create_V8_ObjectTemplate(VALUE value) {
|
12
|
+
Local<ObjectTemplate> tmpl = ObjectTemplate::New();
|
13
|
+
// tmpl->SetInternalFieldCount(2);
|
14
|
+
tmpl->SetNamedPropertyHandler(
|
15
|
+
RacerRubyNamedPropertyGetter,
|
16
|
+
RacerRubyNamedPropertySetter,
|
17
|
+
0, // RacerRubyNamedPropertyQuery,
|
18
|
+
0, // RacerRubyNamedPropertyDeleter,
|
19
|
+
RacerRubyNamedPropertyEnumerator,
|
20
|
+
External::Wrap((void *)value)
|
21
|
+
);
|
22
|
+
return tmpl;
|
23
|
+
}
|
24
|
+
|
25
|
+
|
10
26
|
|
11
27
|
VALUE v8_Template_Set(VALUE self, VALUE name, VALUE value) {
|
12
28
|
HandleScope handles;
|
data/ext/v8/v8_template.h
CHANGED
data/lib/v8.rb
CHANGED
data/lib/v8/context.rb
CHANGED
@@ -22,9 +22,11 @@ module V8
|
|
22
22
|
if IO === javascript || StringIO === javascript
|
23
23
|
javascript = javascript.read()
|
24
24
|
end
|
25
|
-
@native.
|
26
|
-
|
27
|
-
|
25
|
+
@native.open do
|
26
|
+
@native.eval(javascript).tap do |result|
|
27
|
+
raise JavascriptError.new(result) if result.kind_of?(C::Message)
|
28
|
+
return To.ruby(result)
|
29
|
+
end
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
data/lib/v8/to.rb
CHANGED
data/spec/redjs/jsapi_spec.rb
CHANGED
@@ -113,27 +113,30 @@ describe "Ruby Javascript API" do
|
|
113
113
|
cxt.eval('timesfive(3)').should == 15
|
114
114
|
end
|
115
115
|
end
|
116
|
+
|
117
|
+
it "reports ruby methods that do not exist as undefined" do
|
118
|
+
Context.open(:with => Object.new) do |cxt|
|
119
|
+
cxt.eval('this.foobar').should be_nil
|
120
|
+
end
|
121
|
+
end
|
116
122
|
|
117
123
|
it "can call public locally defined ruby methods" do
|
118
124
|
class_eval do
|
119
|
-
def voo
|
120
|
-
"
|
125
|
+
def voo(str)
|
126
|
+
"voo#{str}"
|
121
127
|
end
|
122
128
|
end
|
123
|
-
evaljs("o.voo").
|
124
|
-
evaljs("o.voo()").should == "doo"
|
129
|
+
evaljs("o.voo('doo')").should == "voodoo"
|
125
130
|
end
|
126
131
|
|
127
132
|
it "translates ruby naming conventions into javascript naming conventions, but you can still access them by their original names" do
|
128
133
|
class_eval do
|
129
|
-
def my_special_method
|
130
|
-
"hello"
|
134
|
+
def my_special_method(to)
|
135
|
+
"hello #{to}"
|
131
136
|
end
|
132
137
|
end
|
133
|
-
evaljs("o.mySpecialMethod").
|
134
|
-
evaljs("o.
|
135
|
-
evaljs("o.my_special_method").should_not be_nil
|
136
|
-
evaljs("o.my_special_method()").should == "hello"
|
138
|
+
evaljs("o.mySpecialMethod('Frank')").should == "hello Frank"
|
139
|
+
evaljs("o.my_special_method('Jack')").should == "hello Jack"
|
137
140
|
end
|
138
141
|
|
139
142
|
it "hides methods not defined directly on this instance's class" do
|
@@ -152,8 +155,8 @@ describe "Ruby Javascript API" do
|
|
152
155
|
def baz_bang
|
153
156
|
end
|
154
157
|
end
|
155
|
-
|
156
|
-
evaljs(<<-EOJS).should == ["fooBar,bazBang"]
|
158
|
+
require 'set'
|
159
|
+
evaljs(<<-EOJS).to_set.should == Set.new(["fooBar","bazBang"])
|
157
160
|
var names = [];
|
158
161
|
for (var p in o) {
|
159
162
|
names.push(p);
|
@@ -166,18 +169,49 @@ describe "Ruby Javascript API" do
|
|
166
169
|
Context.open do |cxt|
|
167
170
|
cxt['o'] = @instance
|
168
171
|
class_eval do
|
169
|
-
def
|
170
|
-
"
|
172
|
+
def whiz(str)
|
173
|
+
"whiz#{str}!"
|
171
174
|
end
|
172
175
|
end
|
173
|
-
cxt.eval("o.
|
174
|
-
cxt.eval("o.bar()").should == "baz!"
|
176
|
+
cxt.eval("o.whiz('bang')").should == "whizbang!"
|
175
177
|
end
|
176
178
|
end
|
177
179
|
|
178
|
-
it "treats ruby methods that have an arity of 0 as javascript properties by default"
|
180
|
+
it "treats ruby methods that have an arity of 0 as javascript properties by default" do
|
181
|
+
class_eval do
|
182
|
+
def property
|
183
|
+
"flan!"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
evaljs('o.property').should == 'flan!'
|
187
|
+
end
|
179
188
|
|
180
|
-
it "will call ruby accesssor function when setting a property from javascript"
|
189
|
+
it "will call ruby accesssor function when setting a property from javascript" do
|
190
|
+
class_eval do
|
191
|
+
def dollars
|
192
|
+
@dollars
|
193
|
+
end
|
194
|
+
|
195
|
+
def dollars=(amount)
|
196
|
+
@dollars = amount
|
197
|
+
end
|
198
|
+
end
|
199
|
+
evaljs('o.dollars = 50')
|
200
|
+
@instance.dollars.should == 50
|
201
|
+
end
|
202
|
+
|
203
|
+
it "will accept expando properties by default for properties on ruby object that are not implemented in ruby" do
|
204
|
+
evaljs('o.five = 5; o.five').should == 5
|
205
|
+
end
|
206
|
+
|
207
|
+
it "it silently fails to replace properties which are defined on ruby objects but which are read-only" do
|
208
|
+
class_eval do
|
209
|
+
def bar
|
210
|
+
"baz"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
evaljs('o.bar = "bing"; o.bar').should == "baz"
|
214
|
+
end
|
181
215
|
|
182
216
|
def evaljs(str)
|
183
217
|
Context.open do |cxt|
|
@@ -245,6 +279,7 @@ describe "Ruby Javascript API" do
|
|
245
279
|
end
|
246
280
|
|
247
281
|
it "can limit the number of instructions that are executed in the context" do
|
282
|
+
pending "haven't figured out how to constrain resources in V8"
|
248
283
|
lambda {
|
249
284
|
Context.open do |cxt|
|
250
285
|
cxt.instruction_limit = 100 * 1000
|
@@ -345,9 +380,7 @@ end
|
|
345
380
|
describe "Exception Handling" do
|
346
381
|
it "raises javascript exceptions as ruby exceptions" do
|
347
382
|
lambda {
|
348
|
-
Context.
|
349
|
-
cxt.eval('foo')
|
350
|
-
end
|
383
|
+
Context.new.eval('foo')
|
351
384
|
}.should raise_error(JavascriptError)
|
352
385
|
end
|
353
386
|
end
|
data/spec/v8/to_spec.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
include V8
|
4
|
+
|
5
|
+
describe V8::To do
|
6
|
+
|
7
|
+
it "can convert into perl case" do
|
8
|
+
To.perl_case("foo").should == "foo"
|
9
|
+
To.perl_case("fooBar").should == "foo_bar"
|
10
|
+
To.perl_case("fooBarBaz").should == "foo_bar_baz"
|
11
|
+
To.perl_case("XMLDocument").should == "xml_document"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
end
|
data/therubyracer.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{therubyracer}
|
5
|
-
s.version = "0.4.
|
5
|
+
s.version = "0.4.5"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Charles Lowell", "Bill Robertson"]
|
9
|
-
s.date = %q{2010-01-
|
9
|
+
s.date = %q{2010-01-18}
|
10
10
|
s.description = %q{Embed the V8 Javascript interpreter into Ruby.}
|
11
11
|
s.email = ["cowboyd@thefrontside.net", "billrobertson42@gmail.com"]
|
12
12
|
s.extensions = ["ext/v8/extconf.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.4.
|
4
|
+
version: 0.4.5
|
5
5
|
platform: ruby
|
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-01-
|
13
|
+
date: 2010-01-18 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- spec/redjs_helper.rb
|
87
87
|
- spec/spec.opts
|
88
88
|
- spec/spec_helper.rb
|
89
|
+
- spec/v8/to_spec.rb
|
89
90
|
- tasks/rspec.rake
|
90
91
|
- therubyracer.gemspec
|
91
92
|
has_rdoc: true
|