mini_racer 0.1.15 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ require 'mkmf'
2
+
3
+ extension_name = 'mini_racer_loader'
4
+ dir_config extension_name
5
+
6
+ $CPPFLAGS += " -fvisibility=hidden "
7
+
8
+ create_makefile extension_name
@@ -0,0 +1,123 @@
1
+ #include <ruby.h>
2
+ #include <dlfcn.h>
3
+ #include <string.h>
4
+ #include <stdint.h>
5
+ #include <stdlib.h>
6
+
7
+ // Load a Ruby extension like Ruby does, only with flags that:
8
+ // a) hide symbols from other extensions (RTLD_LOCAL)
9
+ // b) bind symbols tightly (RTLD_DEEPBIND, when available)
10
+
11
+ void Init_mini_racer_loader(void);
12
+
13
+ static void *_dln_load(const char *file);
14
+
15
+ static VALUE _load_shared_lib(VALUE self, volatile VALUE fname)
16
+ {
17
+ (void) self;
18
+
19
+ // check that path is not tainted
20
+ SafeStringValue(fname);
21
+
22
+ FilePathValue(fname);
23
+ VALUE path = rb_str_encode_ospath(fname);
24
+
25
+ char *loc = StringValueCStr(path);
26
+ void *handle = _dln_load(loc);
27
+
28
+ return handle ? Qtrue : Qfalse;
29
+ }
30
+
31
+ // adapted from Ruby's dln.c
32
+ #define INIT_FUNC_PREFIX ((char[]) {'I', 'n', 'i', 't', '_'})
33
+ #define INIT_FUNCNAME(buf, file) do { \
34
+ const char *base = (file); \
35
+ const size_t flen = _init_funcname(&base); \
36
+ const size_t plen = sizeof(INIT_FUNC_PREFIX); \
37
+ char *const tmp = ALLOCA_N(char, plen + flen + 1); \
38
+ memcpy(tmp, INIT_FUNC_PREFIX, plen); \
39
+ memcpy(tmp+plen, base, flen); \
40
+ tmp[plen+flen] = '\0'; \
41
+ *(buf) = tmp; \
42
+ } while(0)
43
+
44
+ // adapted from Ruby's dln.c
45
+ static size_t _init_funcname(const char **file)
46
+ {
47
+ const char *p = *file,
48
+ *base,
49
+ *dot = NULL;
50
+
51
+ for (base = p; *p; p++) { /* Find position of last '/' */
52
+ if (*p == '.' && !dot) {
53
+ dot = p;
54
+ }
55
+ if (*p == '/') {
56
+ base = p + 1;
57
+ dot = NULL;
58
+ }
59
+ }
60
+ *file = base;
61
+ return (uintptr_t) ((dot ? dot : p) - base);
62
+ }
63
+
64
+ // adapted from Ruby's dln.c
65
+ static void *_dln_load(const char *file)
66
+ {
67
+ char *buf;
68
+ const char *error;
69
+ #define DLN_ERROR() (error = dlerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
70
+
71
+ void *handle;
72
+ void (*init_fct)(void);
73
+
74
+ INIT_FUNCNAME(&buf, file);
75
+
76
+ #ifndef RTLD_DEEPBIND
77
+ # define RTLD_DEEPBIND 0
78
+ #endif
79
+ /* Load file */
80
+ if ((handle = dlopen(file, RTLD_LAZY|RTLD_LOCAL|RTLD_DEEPBIND)) == NULL) {
81
+ DLN_ERROR();
82
+ goto failed;
83
+ }
84
+ #if defined(RUBY_EXPORT)
85
+ {
86
+ static const char incompatible[] = "incompatible library version";
87
+ void *ex = dlsym(handle, "ruby_xmalloc");
88
+ if (ex && ex != (void *) &ruby_xmalloc) {
89
+
90
+ # if defined __APPLE__
91
+ /* dlclose() segfaults */
92
+ rb_fatal("%s - %s", incompatible, file);
93
+ # else
94
+ dlclose(handle);
95
+ error = incompatible;
96
+ goto failed;
97
+ #endif
98
+ }
99
+ }
100
+ # endif
101
+
102
+ init_fct = (void (*)(void)) dlsym(handle, buf);
103
+ if (init_fct == NULL) {
104
+ error = DLN_ERROR();
105
+ dlclose(handle);
106
+ goto failed;
107
+ }
108
+
109
+ /* Call the init code */
110
+ (*init_fct)();
111
+
112
+ return handle;
113
+
114
+ failed:
115
+ rb_raise(rb_eLoadError, "%s", error);
116
+ }
117
+
118
+ __attribute__((visibility("default"))) void Init_mini_racer_loader()
119
+ {
120
+ VALUE mMiniRacer = rb_define_module("MiniRacer");
121
+ VALUE mLoader = rb_define_module_under(mMiniRacer, "Loader");
122
+ rb_define_singleton_method(mLoader, "load", _load_shared_lib, 1);
123
+ }
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MiniRacer
2
- VERSION = "0.1.15"
4
+ VERSION = "0.5.0"
5
+ LIBV8_NODE_VERSION = "~> 16.10.0.0"
3
6
  end
data/lib/mini_racer.rb CHANGED
@@ -1,10 +1,23 @@
1
1
  require "mini_racer/version"
2
- require "mini_racer_extension"
2
+ require "mini_racer_loader"
3
+ require "pathname"
4
+
5
+ ext_filename = "mini_racer_extension.#{RbConfig::CONFIG['DLEXT']}"
6
+ ext_path = Gem.loaded_specs['mini_racer'].require_paths
7
+ .map { |p| (p = Pathname.new(p)).absolute? ? p : Pathname.new(__dir__).parent + p }
8
+ ext_found = ext_path.map { |p| p + ext_filename }.find { |p| p.file? }
9
+
10
+ raise LoadError, "Could not find #{ext_filename} in #{ext_path.map(&:to_s)}" unless ext_found
11
+ MiniRacer::Loader.load(ext_found.to_s)
12
+
3
13
  require "thread"
4
14
  require "json"
5
15
 
6
16
  module MiniRacer
7
17
 
18
+ MARSHAL_STACKDEPTH_DEFAULT = 2**9-2
19
+ MARSHAL_STACKDEPTH_MAX_VALUE = 2**10-2
20
+
8
21
  class Error < ::StandardError; end
9
22
 
10
23
  class ContextDisposedError < Error; end
@@ -59,15 +72,9 @@ module MiniRacer
59
72
  raise ArgumentError, "snapshot must be a Snapshot object, passed a #{snapshot.inspect}"
60
73
  end
61
74
 
62
- @lock = Mutex.new
63
-
64
75
  # defined in the C class
65
76
  init_with_snapshot(snapshot)
66
77
  end
67
-
68
- def with_lock
69
- @lock.synchronize { yield }
70
- end
71
78
  end
72
79
 
73
80
  class Platform
@@ -136,22 +143,30 @@ module MiniRacer
136
143
  end
137
144
  end
138
145
 
139
- attr_reader :isolate
140
-
141
- def initialize(options = nil)
146
+ def initialize(max_memory: nil, timeout: nil, isolate: nil, ensure_gc_after_idle: nil, snapshot: nil, marshal_stack_depth: nil)
142
147
  options ||= {}
143
148
 
144
- check_init_options!(options)
149
+ check_init_options!(isolate: isolate, snapshot: snapshot, max_memory: max_memory, marshal_stack_depth: marshal_stack_depth, ensure_gc_after_idle: ensure_gc_after_idle, timeout: timeout)
145
150
 
146
151
  @functions = {}
147
152
  @timeout = nil
148
153
  @max_memory = nil
149
154
  @current_exception = nil
150
- @timeout = options[:timeout]
151
- if options[:max_memory].is_a?(Numeric) && options[:max_memory] > 0
152
- @max_memory = options[:max_memory]
155
+ @timeout = timeout
156
+ @max_memory = max_memory
157
+ @marshal_stack_depth = marshal_stack_depth
158
+
159
+ # false signals it should be fetched if requested
160
+ @isolate = isolate || false
161
+
162
+ @ensure_gc_after_idle = ensure_gc_after_idle
163
+
164
+ if @ensure_gc_after_idle
165
+ @last_eval = nil
166
+ @ensure_gc_thread = nil
167
+ @ensure_gc_mutex = Mutex.new
153
168
  end
154
- @isolate = options[:isolate] || Isolate.new(options[:snapshot])
169
+
155
170
  @disposed = false
156
171
 
157
172
  @callback_mutex = Mutex.new
@@ -159,10 +174,14 @@ module MiniRacer
159
174
  @thread_raise_called = false
160
175
  @eval_thread = nil
161
176
 
162
- isolate.with_lock do
163
- # defined in the C class
164
- init_with_isolate(@isolate)
165
- end
177
+ # defined in the C class
178
+ init_unsafe(isolate, snapshot)
179
+ end
180
+
181
+ def isolate
182
+ return @isolate if @isolate != false
183
+ # defined in the C class
184
+ @isolate = create_isolate_value
166
185
  end
167
186
 
168
187
  def load(filename)
@@ -170,13 +189,35 @@ module MiniRacer
170
189
  eval(File.read(filename))
171
190
  end
172
191
 
192
+ def write_heap_snapshot(file_or_io)
193
+ f = nil
194
+ implicit = false
195
+
196
+
197
+ if String === file_or_io
198
+ f = File.open(file_or_io, "w")
199
+ implicit = true
200
+ else
201
+ f = file_or_io
202
+ end
203
+
204
+ if !(File === f)
205
+ raise ArgumentError("file_or_io")
206
+ end
207
+
208
+ write_heap_snapshot_unsafe(f)
209
+
210
+ ensure
211
+ f.close if implicit
212
+ end
213
+
173
214
  def eval(str, options=nil)
174
215
  raise(ContextDisposedError, 'attempted to call eval on a disposed context!') if @disposed
175
216
 
176
217
  filename = options && options[:filename].to_s
177
218
 
178
219
  @eval_thread = Thread.current
179
- isolate.with_lock do
220
+ isolate_mutex.synchronize do
180
221
  @current_exception = nil
181
222
  timeout do
182
223
  eval_unsafe(str, filename)
@@ -184,43 +225,72 @@ module MiniRacer
184
225
  end
185
226
  ensure
186
227
  @eval_thread = nil
228
+ ensure_gc_thread if @ensure_gc_after_idle
187
229
  end
188
230
 
189
- def dispose
190
- if !@disposed
191
- isolate.with_lock do
192
- dispose_unsafe
231
+ def call(function_name, *arguments)
232
+ raise(ContextDisposedError, 'attempted to call function on a disposed context!') if @disposed
233
+
234
+ @eval_thread = Thread.current
235
+ isolate_mutex.synchronize do
236
+ timeout do
237
+ call_unsafe(function_name, *arguments)
193
238
  end
239
+ end
240
+ ensure
241
+ @eval_thread = nil
242
+ ensure_gc_thread if @ensure_gc_after_idle
243
+ end
244
+
245
+ def dispose
246
+ return if @disposed
247
+ isolate_mutex.synchronize do
248
+ return if @disposed
249
+ dispose_unsafe
194
250
  @disposed = true
251
+ @isolate = nil # allow it to be garbage collected, if set
195
252
  end
196
253
  end
197
254
 
198
255
 
199
256
  def attach(name, callback)
257
+ raise(ContextDisposedError, 'attempted to call function on a disposed context!') if @disposed
200
258
 
201
259
  wrapped = lambda do |*args|
202
260
  begin
203
- @callback_mutex.synchronize{
204
- @callback_running = true
205
- }
206
261
 
207
- callback.call(*args)
208
- ensure
209
- @callback_mutex.synchronize {
210
- @callback_running = false
262
+ r = nil
263
+
264
+ begin
265
+ @callback_mutex.synchronize{
266
+ @callback_running = true
267
+ }
268
+ r = callback.call(*args)
269
+ ensure
270
+ @callback_mutex.synchronize{
271
+ @callback_running = false
272
+ }
273
+ end
211
274
 
212
- # this is some odd code, but it is required
213
- # if we raised on this thread we better wait for it
214
- # otherwise we may end up raising in an unsafe spot
275
+ # wait up to 2 seconds for this to be interrupted
276
+ # will very rarely be called cause #raise is called
277
+ # in another mutex
278
+ @callback_mutex.synchronize {
215
279
  if @thread_raise_called
216
- sleep 0.1
280
+ sleep 2
217
281
  end
282
+ }
283
+
284
+ r
285
+
286
+ ensure
287
+ @callback_mutex.synchronize {
218
288
  @thread_raise_called = false
219
289
  }
220
290
  end
221
291
  end
222
292
 
223
- isolate.with_lock do
293
+ isolate_mutex.synchronize do
224
294
  external = ExternalFunction.new(name, wrapped, self)
225
295
  @functions["#{name}"] = external
226
296
  end
@@ -228,6 +298,38 @@ module MiniRacer
228
298
 
229
299
  private
230
300
 
301
+ def ensure_gc_thread
302
+ @last_eval = Process.clock_gettime(Process::CLOCK_MONOTONIC)
303
+ @ensure_gc_mutex.synchronize do
304
+ @ensure_gc_thread = nil if !@ensure_gc_thread&.alive?
305
+ @ensure_gc_thread ||= Thread.new do
306
+ ensure_gc_after_idle_seconds = @ensure_gc_after_idle / 1000.0
307
+ done = false
308
+ while !done
309
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
310
+
311
+ if @disposed
312
+ @ensure_gc_thread = nil
313
+ break
314
+ end
315
+
316
+ if !@eval_thread && ensure_gc_after_idle_seconds < now - @last_eval
317
+ @ensure_gc_mutex.synchronize do
318
+ isolate_mutex.synchronize do
319
+ if !@eval_thread
320
+ isolate.low_memory_notification if !@disposed
321
+ @ensure_gc_thread = nil
322
+ done = true
323
+ end
324
+ end
325
+ end
326
+ end
327
+ sleep ensure_gc_after_idle_seconds if !done
328
+ end
329
+ end
330
+ end
331
+ end
332
+
231
333
  def stop_attached
232
334
  @callback_mutex.synchronize{
233
335
  if @callback_running
@@ -245,7 +347,7 @@ module MiniRacer
245
347
 
246
348
  rp,wp = IO.pipe
247
349
 
248
- Thread.new do
350
+ t = Thread.new do
249
351
  begin
250
352
  result = IO.select([rp],[],[],(@timeout/1000.0))
251
353
  if !result
@@ -265,19 +367,50 @@ module MiniRacer
265
367
  end
266
368
 
267
369
  wp.write("done")
268
- rval
269
370
 
371
+ # ensure we do not leak a thread in state
372
+ t.join
373
+ t = nil
374
+
375
+ rval
376
+ ensure
377
+ # exceptions need to be handled
378
+ if t && wp
379
+ wp.write("done")
380
+ t.join
381
+ end
382
+ wp.close if wp
383
+ rp.close if rp
270
384
  end
271
385
 
272
- def check_init_options!(options)
273
- assert_option_is_nil_or_a('isolate', options[:isolate], Isolate)
274
- assert_option_is_nil_or_a('snapshot', options[:snapshot], Snapshot)
386
+ def check_init_options!(isolate:, snapshot:, max_memory:, marshal_stack_depth:, ensure_gc_after_idle:, timeout:)
387
+ assert_option_is_nil_or_a('isolate', isolate, Isolate)
388
+ assert_option_is_nil_or_a('snapshot', snapshot, Snapshot)
389
+
390
+ assert_numeric_or_nil('max_memory', max_memory, min_value: 10_000, max_value: 2**32-1)
391
+ assert_numeric_or_nil('marshal_stack_depth', marshal_stack_depth, min_value: 1, max_value: MARSHAL_STACKDEPTH_MAX_VALUE)
392
+ assert_numeric_or_nil('ensure_gc_after_idle', ensure_gc_after_idle, min_value: 1)
393
+ assert_numeric_or_nil('timeout', timeout, min_value: 1)
275
394
 
276
- if options[:isolate] && options[:snapshot]
395
+ if isolate && snapshot
277
396
  raise ArgumentError, 'can only pass one of isolate and snapshot options'
278
397
  end
279
398
  end
280
399
 
400
+ def assert_numeric_or_nil(option_name, object, min_value:, max_value: nil)
401
+ if max_value && object.is_a?(Numeric) && object > max_value
402
+ raise ArgumentError, "#{option_name} must be less than or equal to #{max_value}"
403
+ end
404
+
405
+ if object.is_a?(Numeric) && object < min_value
406
+ raise ArgumentError, "#{option_name} must be larger than or equal to #{min_value}"
407
+ end
408
+
409
+ if !object.nil? && !object.is_a?(Numeric)
410
+ raise ArgumentError, "#{option_name} must be a number, passed a #{object.inspect}"
411
+ end
412
+ end
413
+
281
414
  def assert_option_is_nil_or_a(option_name, object, klass)
282
415
  unless object.nil? || object.is_a?(klass)
283
416
  raise ArgumentError, "#{option_name} must be a #{klass} object, passed a #{object.inspect}"
@@ -288,8 +421,33 @@ module MiniRacer
288
421
  # `size` and `warmup!` public methods are defined in the C class
289
422
  class Snapshot
290
423
  def initialize(str = '')
424
+ # ensure it first can load
425
+ begin
426
+ ctx = MiniRacer::Context.new
427
+ ctx.eval(str)
428
+ rescue MiniRacer::RuntimeError => e
429
+ raise MiniRacer::SnapshotError.new, e.message, e.backtrace
430
+ end
431
+
432
+ @source = str
433
+
291
434
  # defined in the C class
292
435
  load(str)
293
436
  end
437
+
438
+ def warmup!(src)
439
+ # we have to do something here
440
+ # we are bloating memory a bit but it is more correct
441
+ # than hitting an exception when attempty to compile invalid source
442
+ begin
443
+ ctx = MiniRacer::Context.new
444
+ ctx.eval(@source)
445
+ ctx.eval(src)
446
+ rescue MiniRacer::RuntimeError => e
447
+ raise MiniRacer::SnapshotError.new, e.message, e.backtrace
448
+ end
449
+
450
+ warmup_unsafe!(src)
451
+ end
294
452
  end
295
453
  end
data/mini_racer.gemspec CHANGED
@@ -14,21 +14,26 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = "https://github.com/discourse/mini_racer"
15
15
  spec.license = "MIT"
16
16
 
17
-
18
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(benchmark|test|spec|features)/}) }
19
- spec.bindir = "exe"
20
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
17
+ spec.metadata = {
18
+ "bug_tracker_uri" => "https://github.com/discourse/mini_racer/issues",
19
+ "changelog_uri" => "https://github.com/discourse/mini_racer/blob/v#{spec.version}/CHANGELOG",
20
+ "documentation_uri" => "https://www.rubydoc.info/gems/mini_racer/#{spec.version}",
21
+ "source_code_uri" => "https://github.com/discourse/mini_racer/tree/v#{spec.version}",
22
+ }
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(benchmark|test|spec|features|examples)/}) }
21
25
  spec.require_paths = ["lib"]
22
26
 
23
- spec.add_development_dependency "bundler", "~> 1.12"
24
- spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "bundler"
28
+ spec.add_development_dependency "rake", ">= 12.3.3"
25
29
  spec.add_development_dependency "minitest", "~> 5.0"
26
30
  spec.add_development_dependency "rake-compiler"
31
+ spec.add_development_dependency "m"
27
32
 
28
- spec.add_dependency 'libv8', '~> 6.3'
33
+ spec.add_dependency 'libv8-node', MiniRacer::LIBV8_NODE_VERSION
29
34
  spec.require_paths = ["lib", "ext"]
30
35
 
31
- spec.extensions = ["ext/mini_racer_extension/extconf.rb"]
36
+ spec.extensions = ["ext/mini_racer_loader/extconf.rb", "ext/mini_racer_extension/extconf.rb"]
32
37
 
33
- spec.required_ruby_version = '>= 2.0'
38
+ spec.required_ruby_version = '>= 2.6'
34
39
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_racer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.15
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-27 00:00:00.000000000 Z
11
+ date: 2021-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.12'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.12'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: 12.3.3
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: 12.3.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -67,31 +67,49 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: libv8
70
+ name: m
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: libv8-node
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '6.3'
89
+ version: 16.10.0.0
76
90
  type: :runtime
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '6.3'
96
+ version: 16.10.0.0
83
97
  description: Minimal embedded v8 engine for Ruby
84
98
  email:
85
99
  - sam.saffron@gmail.com
86
100
  executables: []
87
101
  extensions:
102
+ - ext/mini_racer_loader/extconf.rb
88
103
  - ext/mini_racer_extension/extconf.rb
89
104
  extra_rdoc_files: []
90
105
  files:
106
+ - ".dockerignore"
107
+ - ".github/workflows/ci.yml"
91
108
  - ".gitignore"
92
109
  - ".travis.yml"
93
110
  - CHANGELOG
94
111
  - CODE_OF_CONDUCT.md
112
+ - Dockerfile
95
113
  - Gemfile
96
114
  - LICENSE.txt
97
115
  - README.md
@@ -100,13 +118,19 @@ files:
100
118
  - bin/setup
101
119
  - ext/mini_racer_extension/extconf.rb
102
120
  - ext/mini_racer_extension/mini_racer_extension.cc
121
+ - ext/mini_racer_loader/extconf.rb
122
+ - ext/mini_racer_loader/mini_racer_loader.c
103
123
  - lib/mini_racer.rb
104
124
  - lib/mini_racer/version.rb
105
125
  - mini_racer.gemspec
106
126
  homepage: https://github.com/discourse/mini_racer
107
127
  licenses:
108
128
  - MIT
109
- metadata: {}
129
+ metadata:
130
+ bug_tracker_uri: https://github.com/discourse/mini_racer/issues
131
+ changelog_uri: https://github.com/discourse/mini_racer/blob/v0.5.0/CHANGELOG
132
+ documentation_uri: https://www.rubydoc.info/gems/mini_racer/0.5.0
133
+ source_code_uri: https://github.com/discourse/mini_racer/tree/v0.5.0
110
134
  post_install_message:
111
135
  rdoc_options: []
112
136
  require_paths:
@@ -116,15 +140,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
140
  requirements:
117
141
  - - ">="
118
142
  - !ruby/object:Gem::Version
119
- version: '2.0'
143
+ version: '2.6'
120
144
  required_rubygems_version: !ruby/object:Gem::Requirement
121
145
  requirements:
122
146
  - - ">="
123
147
  - !ruby/object:Gem::Version
124
148
  version: '0'
125
149
  requirements: []
126
- rubyforge_project:
127
- rubygems_version: 2.6.13
150
+ rubygems_version: 3.1.6
128
151
  signing_key:
129
152
  specification_version: 4
130
153
  summary: Minimal embedded v8 for Ruby