mini_racer 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +17 -2
- data/README.md +11 -4
- data/ext/mini_racer_extension/mini_racer_extension.cc +77 -17
- data/lib/mini_racer.rb +30 -2
- data/lib/mini_racer/version.rb +1 -1
- data/mini_racer.gemspec +3 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef7d560456c68712a83c6167b76c27fa2f145da2
|
4
|
+
data.tar.gz: f299b830d1df20a115fdc8f63aea4a7c9f0328b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 007738356ef3475876ea8c125cc4ccd487df22c6cbdd1ae5a793865825ffdae79c6b578e9f038845462314ca9fcf1745c75f97818fc36ff4186f58ed202cafa7
|
7
|
+
data.tar.gz: 6f3da0e1c5a6898f63fa625499704a0ed4e31d47af042e90c796dd99d635723522357c7f36e1cf530844b7ff7a8f97ee13efa0d135aca3b53665b82755b6264b
|
data/CHANGELOG
CHANGED
@@ -1,11 +1,26 @@
|
|
1
|
+
19-05-2016
|
2
|
+
|
3
|
+
- 0.1.3
|
4
|
+
|
5
|
+
- Support more conversions from Ruby back to JS (Hash, Symbol, Array)
|
6
|
+
- Support attaching nested objects
|
7
|
+
|
8
|
+
|
9
|
+
17-05-2016
|
10
|
+
|
11
|
+
- 0.1.2
|
12
|
+
|
13
|
+
- Gemspec specifies minimal version of Ruby (2.0)
|
14
|
+
- Implement #load on Context to load files
|
15
|
+
|
1
16
|
17-05-2016
|
2
17
|
|
3
|
-
- 0.
|
18
|
+
- 0.1.1
|
4
19
|
|
5
20
|
- Added unblock function so SIGINT does not lead to a crash
|
6
21
|
|
7
22
|
14-05-2016
|
8
23
|
|
9
|
-
- 0.
|
24
|
+
- 0.1.1.beta.1
|
10
25
|
|
11
26
|
- First release
|
data/README.md
CHANGED
@@ -29,11 +29,18 @@ You can attach one or many ruby proc that can be accessed via JavaScript
|
|
29
29
|
|
30
30
|
```ruby
|
31
31
|
context = MiniRacer::Context.new
|
32
|
-
context.attach("adder", proc{|a,b| a+b})
|
33
|
-
puts context.eval 'adder(20,22)'
|
32
|
+
context.attach("math.adder", proc{|a,b| a+b})
|
33
|
+
puts context.eval 'math.adder(20,22)'
|
34
34
|
# => 42
|
35
35
|
```
|
36
36
|
|
37
|
+
```ruby
|
38
|
+
context = MiniRacer::Context.new
|
39
|
+
context.attach("array_and_hash", proc{{a: 1, b: [1, {a: 1}]}})
|
40
|
+
puts context.eval 'array_and_hash()'
|
41
|
+
# => {"a" => 1, "b" => [1, {"a" => 1}]}
|
42
|
+
```
|
43
|
+
|
37
44
|
### GIL free JavaScript execution
|
38
45
|
|
39
46
|
The Ruby Global interpreter lock is released when scripts are executing
|
@@ -87,7 +94,7 @@ The `bench` folder contains benchmark.
|
|
87
94
|
|
88
95
|
### Benchmark minification of Discourse application.js (both minified and unminified)
|
89
96
|
|
90
|
-
- MiniRacer version 0.1
|
97
|
+
- MiniRacer version 0.1
|
91
98
|
- therubyracer version 0.12.2
|
92
99
|
|
93
100
|
```
|
@@ -173,7 +180,7 @@ Or install it yourself as:
|
|
173
180
|
|
174
181
|
## Contributing
|
175
182
|
|
176
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
183
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/discourse/mini_racer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
177
184
|
|
178
185
|
|
179
186
|
## License
|
@@ -197,6 +197,12 @@ static VALUE convert_v8_to_ruby(Isolate* isolate, Handle<Value> &value) {
|
|
197
197
|
static Handle<Value> convert_ruby_to_v8(Isolate* isolate, VALUE value) {
|
198
198
|
EscapableHandleScope scope(isolate);
|
199
199
|
|
200
|
+
Local<Array> array;
|
201
|
+
Local<Object> object;
|
202
|
+
VALUE hash_as_array;
|
203
|
+
VALUE pair;
|
204
|
+
int length,i;
|
205
|
+
|
200
206
|
switch (TYPE(value)) {
|
201
207
|
case T_FIXNUM:
|
202
208
|
return scope.Escape(Integer::New(isolate, NUM2INT(value)));
|
@@ -210,6 +216,26 @@ static Handle<Value> convert_ruby_to_v8(Isolate* isolate, VALUE value) {
|
|
210
216
|
return scope.Escape(True(isolate));
|
211
217
|
case T_FALSE:
|
212
218
|
return scope.Escape(False(isolate));
|
219
|
+
case T_ARRAY:
|
220
|
+
length = RARRAY_LEN(value);
|
221
|
+
array = Array::New(isolate, length);
|
222
|
+
for(i=0; i<length; i++) {
|
223
|
+
array->Set(i, convert_ruby_to_v8(isolate, rb_ary_entry(value, i)));
|
224
|
+
}
|
225
|
+
return scope.Escape(array);
|
226
|
+
case T_HASH:
|
227
|
+
object = Object::New(isolate);
|
228
|
+
hash_as_array = rb_funcall(value, rb_intern("to_a"), 0);
|
229
|
+
length = RARRAY_LEN(hash_as_array);
|
230
|
+
for(i=0; i<length; i++) {
|
231
|
+
pair = rb_ary_entry(hash_as_array, i);
|
232
|
+
object->Set(convert_ruby_to_v8(isolate, rb_ary_entry(pair, 0)),
|
233
|
+
convert_ruby_to_v8(isolate, rb_ary_entry(pair, 1)));
|
234
|
+
}
|
235
|
+
return scope.Escape(object);
|
236
|
+
case T_SYMBOL:
|
237
|
+
value = rb_funcall(value, rb_intern("to_s"), 0);
|
238
|
+
return scope.Escape(String::NewFromUtf8(isolate, RSTRING_PTR(value), NewStringType::kNormal, (int)RSTRING_LEN(value)).ToLocalChecked());
|
213
239
|
case T_DATA:
|
214
240
|
case T_OBJECT:
|
215
241
|
case T_CLASS:
|
@@ -217,16 +243,12 @@ static Handle<Value> convert_ruby_to_v8(Isolate* isolate, VALUE value) {
|
|
217
243
|
case T_MODULE:
|
218
244
|
case T_REGEXP:
|
219
245
|
case T_MATCH:
|
220
|
-
case T_ARRAY:
|
221
|
-
case T_HASH:
|
222
246
|
case T_STRUCT:
|
223
247
|
case T_BIGNUM:
|
224
248
|
case T_FILE:
|
225
|
-
case T_SYMBOL:
|
226
249
|
case T_UNDEF:
|
227
250
|
case T_NODE:
|
228
251
|
default:
|
229
|
-
// rb_warn("unknown conversion to V8 for: %s", RSTRING_PTR(rb_inspect(value)));
|
230
252
|
return scope.Escape(String::NewFromUtf8(isolate, "Undefined Conversion"));
|
231
253
|
}
|
232
254
|
|
@@ -427,27 +449,65 @@ static VALUE rb_external_function_notify_v8(VALUE self) {
|
|
427
449
|
|
428
450
|
VALUE parent = rb_iv_get(self, "@parent");
|
429
451
|
VALUE name = rb_iv_get(self, "@name");
|
452
|
+
VALUE parent_object = rb_iv_get(self, "@parent_object");
|
453
|
+
VALUE parent_object_eval = rb_iv_get(self, "@parent_object_eval");
|
454
|
+
|
455
|
+
bool parse_error = false;
|
456
|
+
bool attach_error = false;
|
430
457
|
|
431
458
|
Data_Get_Struct(parent, ContextInfo, context_info);
|
432
459
|
|
433
|
-
|
434
|
-
|
435
|
-
|
460
|
+
{
|
461
|
+
Locker lock(context_info->isolate);
|
462
|
+
Isolate::Scope isolate_scope(context_info->isolate);
|
463
|
+
HandleScope handle_scope(context_info->isolate);
|
436
464
|
|
437
|
-
|
438
|
-
|
465
|
+
Local<Context> context = context_info->context->Get(context_info->isolate);
|
466
|
+
Context::Scope context_scope(context);
|
467
|
+
|
468
|
+
Local<String> v8_str = String::NewFromUtf8(context_info->isolate, RSTRING_PTR(name),
|
469
|
+
NewStringType::kNormal, (int)RSTRING_LEN(name)).ToLocalChecked();
|
439
470
|
|
440
|
-
|
441
|
-
|
471
|
+
// copy self so we can access from v8 external
|
472
|
+
VALUE* self_copy;
|
473
|
+
Data_Get_Struct(self, VALUE, self_copy);
|
474
|
+
*self_copy = self;
|
442
475
|
|
476
|
+
Local<Value> external = External::New(context_info->isolate, self_copy);
|
443
477
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
478
|
+
if (parent_object == Qnil) {
|
479
|
+
context->Global()->Set(v8_str, FunctionTemplate::New(context_info->isolate, ruby_callback, external)->GetFunction());
|
480
|
+
} else {
|
481
|
+
|
482
|
+
Local<String> eval = String::NewFromUtf8(context_info->isolate, RSTRING_PTR(parent_object_eval),
|
483
|
+
NewStringType::kNormal, (int)RSTRING_LEN(parent_object_eval)).ToLocalChecked();
|
448
484
|
|
449
|
-
|
450
|
-
|
485
|
+
MaybeLocal<Script> parsed_script = Script::Compile(context, eval);
|
486
|
+
if (parsed_script.IsEmpty()) {
|
487
|
+
parse_error = true;
|
488
|
+
} else {
|
489
|
+
MaybeLocal<Value> maybe_value = parsed_script.ToLocalChecked()->Run(context);
|
490
|
+
attach_error = true;
|
491
|
+
|
492
|
+
if (!maybe_value.IsEmpty()) {
|
493
|
+
Local<Value> value = maybe_value.ToLocalChecked();
|
494
|
+
if (value->IsObject()){
|
495
|
+
value.As<Object>()->Set(v8_str, FunctionTemplate::New(context_info->isolate, ruby_callback, external)->GetFunction());
|
496
|
+
attach_error = false;
|
497
|
+
}
|
498
|
+
}
|
499
|
+
}
|
500
|
+
}
|
501
|
+
}
|
502
|
+
|
503
|
+
// always raise out of V8 context
|
504
|
+
if (parse_error) {
|
505
|
+
rb_raise(rb_eParseError, "Invalid object %s", RSTRING_PTR(parent_object));
|
506
|
+
}
|
507
|
+
|
508
|
+
if (attach_error) {
|
509
|
+
rb_raise(rb_eParseError, "Was expecting %s to be an object", RSTRING_PTR(parent_object));
|
510
|
+
}
|
451
511
|
|
452
512
|
return Qnil;
|
453
513
|
}
|
data/lib/mini_racer.rb
CHANGED
@@ -46,9 +46,33 @@ module MiniRacer
|
|
46
46
|
|
47
47
|
class ExternalFunction
|
48
48
|
def initialize(name, callback, parent)
|
49
|
-
|
49
|
+
unless String === name
|
50
|
+
raise ArgumentError, "parent_object must be a String"
|
51
|
+
end
|
52
|
+
parent_object, _ , @name = name.rpartition(".")
|
50
53
|
@callback = callback
|
51
54
|
@parent = parent
|
55
|
+
@parent_object_eval = nil
|
56
|
+
@parent_object = nil
|
57
|
+
|
58
|
+
unless parent_object.empty?
|
59
|
+
@parent_object = parent_object
|
60
|
+
|
61
|
+
@parent_object_eval = ""
|
62
|
+
prev = ""
|
63
|
+
first = true
|
64
|
+
parent_object.split(".").each do |obj|
|
65
|
+
prev << obj
|
66
|
+
if first
|
67
|
+
@parent_object_eval << "if (typeof #{prev} === 'undefined') { #{prev} = {} };\n"
|
68
|
+
else
|
69
|
+
@parent_object_eval << "#{prev} = #{prev} || {};\n"
|
70
|
+
end
|
71
|
+
prev << "."
|
72
|
+
first = false
|
73
|
+
end
|
74
|
+
@parent_object_eval << "#{parent_object};"
|
75
|
+
end
|
52
76
|
notify_v8
|
53
77
|
end
|
54
78
|
end
|
@@ -62,7 +86,11 @@ module MiniRacer
|
|
62
86
|
if options
|
63
87
|
@timeout = options[:timeout]
|
64
88
|
end
|
89
|
+
end
|
65
90
|
|
91
|
+
def load(filename)
|
92
|
+
# TODO do this native cause no need to allocate VALUE here
|
93
|
+
eval(File.read(filename))
|
66
94
|
end
|
67
95
|
|
68
96
|
def eval(str)
|
@@ -75,7 +103,7 @@ module MiniRacer
|
|
75
103
|
def attach(name, callback)
|
76
104
|
@lock.synchronize do
|
77
105
|
external = ExternalFunction.new(name, callback, self)
|
78
|
-
@functions[name
|
106
|
+
@functions["#{name}"] = external
|
79
107
|
end
|
80
108
|
end
|
81
109
|
|
data/lib/mini_racer/version.rb
CHANGED
data/mini_racer.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
|
12
12
|
spec.summary = %q{Minimal embedded v8 for Ruby}
|
13
13
|
spec.description = %q{Minimal embedded v8 engine for Ruby}
|
14
|
-
spec.homepage = ""
|
14
|
+
spec.homepage = "https://github.com/discourse/mini_racer"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
17
|
|
@@ -30,4 +30,6 @@ Gem::Specification.new do |spec|
|
|
30
30
|
|
31
31
|
spec.extensions = ["ext/mini_racer_extension/extconf.rb"]
|
32
32
|
|
33
|
+
spec.required_ruby_version = '>= 2.0'
|
34
|
+
|
33
35
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_racer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -103,7 +103,7 @@ files:
|
|
103
103
|
- lib/mini_racer.rb
|
104
104
|
- lib/mini_racer/version.rb
|
105
105
|
- mini_racer.gemspec
|
106
|
-
homepage:
|
106
|
+
homepage: https://github.com/discourse/mini_racer
|
107
107
|
licenses:
|
108
108
|
- MIT
|
109
109
|
metadata: {}
|
@@ -116,7 +116,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
116
116
|
requirements:
|
117
117
|
- - ">="
|
118
118
|
- !ruby/object:Gem::Version
|
119
|
-
version: '0'
|
119
|
+
version: '2.0'
|
120
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - ">="
|