opal 1.3.0.alpha1 → 1.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +3 -1
  3. data/UNRELEASED.md +29 -6
  4. data/examples/rack/Gemfile +1 -0
  5. data/examples/rack/Gemfile.lock +11 -7
  6. data/examples/rack-esm/.gitignore +1 -0
  7. data/examples/rack-esm/Gemfile +5 -0
  8. data/examples/rack-esm/app/application.rb +27 -0
  9. data/examples/rack-esm/app/user.rb +24 -0
  10. data/examples/rack-esm/config.ru +25 -0
  11. data/examples/rack-esm/index.html.erb +11 -0
  12. data/examples/sinatra/Gemfile.lock +21 -19
  13. data/lib/opal/builder.rb +39 -23
  14. data/lib/opal/builder_processors.rb +6 -1
  15. data/lib/opal/cache/file_cache.rb +7 -6
  16. data/lib/opal/cli_runners/chrome.rb +20 -15
  17. data/lib/opal/cli_runners/chrome_cdp_interface.rb +1 -1
  18. data/lib/opal/cli_runners/nodejs.rb +3 -2
  19. data/lib/opal/cli_runners/quickjs.rb +28 -0
  20. data/lib/opal/cli_runners.rb +1 -0
  21. data/lib/opal/compiler.rb +8 -2
  22. data/lib/opal/config.rb +5 -0
  23. data/lib/opal/nodes/call.rb +45 -26
  24. data/lib/opal/nodes/helpers.rb +1 -1
  25. data/lib/opal/nodes/top.rb +5 -8
  26. data/lib/opal/rewriters/rubyspec/filters_rewriter.rb +16 -0
  27. data/lib/opal/simple_server.rb +7 -2
  28. data/lib/opal/util.rb +1 -1
  29. data/lib/opal/version.rb +1 -1
  30. data/opal/corelib/complex/base.rb +15 -0
  31. data/opal/corelib/complex.rb +3 -15
  32. data/opal/corelib/constants.rb +2 -2
  33. data/opal/corelib/error.rb +1 -1
  34. data/opal/corelib/helpers.rb +10 -0
  35. data/opal/corelib/io.rb +4 -0
  36. data/opal/corelib/kernel.rb +21 -5
  37. data/opal/corelib/main.rb +4 -0
  38. data/opal/corelib/method.rb +4 -0
  39. data/opal/corelib/module.rb +39 -16
  40. data/opal/corelib/pattern_matching/base.rb +35 -0
  41. data/opal/corelib/pattern_matching.rb +2 -36
  42. data/opal/corelib/process/base.rb +9 -0
  43. data/opal/corelib/process.rb +1 -11
  44. data/opal/corelib/random.rb +4 -0
  45. data/opal/corelib/rational/base.rb +11 -0
  46. data/opal/corelib/rational.rb +3 -10
  47. data/opal/corelib/regexp.rb +1 -1
  48. data/opal/corelib/runtime.js +38 -3
  49. data/opal/opal/full.rb +5 -4
  50. data/opal/opal.rb +12 -11
  51. data/package.json +1 -1
  52. data/spec/filters/bugs/bigdecimal.rb +0 -1
  53. data/spec/filters/bugs/enumerator.rb +5 -0
  54. data/spec/filters/bugs/float.rb +3 -0
  55. data/spec/filters/bugs/kernel.rb +2 -9
  56. data/spec/filters/bugs/language.rb +0 -1
  57. data/spec/filters/bugs/marshal.rb +3 -0
  58. data/spec/filters/bugs/method.rb +1 -2
  59. data/spec/filters/bugs/module.rb +0 -6
  60. data/spec/filters/bugs/rational.rb +1 -0
  61. data/spec/filters/bugs/regexp.rb +0 -1
  62. data/spec/lib/compiler_spec.rb +2 -2
  63. data/spec/mspec-opal/runner.rb +1 -0
  64. data/stdlib/benchmark.rb +14 -0
  65. data/stdlib/buffer.rb +4 -0
  66. data/stdlib/nashorn/file.rb +2 -0
  67. data/stdlib/native.rb +63 -58
  68. data/stdlib/nodejs/argf.rb +110 -0
  69. data/stdlib/nodejs/env.rb +12 -0
  70. data/stdlib/nodejs/file.rb +10 -0
  71. data/stdlib/nodejs/kernel.rb +56 -0
  72. data/stdlib/nodejs.rb +1 -0
  73. data/stdlib/opal/platform.rb +2 -0
  74. data/stdlib/opal-platform.rb +5 -2
  75. data/stdlib/pathname.rb +4 -0
  76. data/stdlib/quickjs/io.rb +22 -0
  77. data/stdlib/quickjs/kernel.rb +5 -0
  78. data/stdlib/quickjs.rb +2 -0
  79. data/stdlib/securerandom.rb +2 -0
  80. data/tasks/performance.rake +2 -1
  81. data/tasks/testing.rake +1 -1
  82. metadata +36 -8
  83. data/lib/opal/cli_runners/chrome_cdp_interface.js +0 -30285
data/lib/opal/compiler.rb CHANGED
@@ -477,6 +477,12 @@ module Opal
477
477
  @required_trees ||= []
478
478
  end
479
479
 
480
+ # An array of things (requires, trees) which don't need to success in
481
+ # loading compile-time.
482
+ def autoloads
483
+ @autoloads ||= []
484
+ end
485
+
480
486
  # The last sexps in method bodies, for example, need to be returned
481
487
  # in the compiled javascript. Due to syntax differences between
482
488
  # javascript any ruby, some sexps need to be handled specially. For
@@ -573,13 +579,13 @@ module Opal
573
579
  def marshal_dump
574
580
  [@options, @option_values, @source_map ||= source_map.cache,
575
581
  @magic_comments, @result,
576
- @required_trees, @requires]
582
+ @required_trees, @requires, @autoloads]
577
583
  end
578
584
 
579
585
  def marshal_load(src)
580
586
  @options, @option_values, @source_map,
581
587
  @magic_comments, @result,
582
- @required_trees, @requires = src
588
+ @required_trees, @requires, @autoloads = src
583
589
  end
584
590
  end
585
591
  end
data/lib/opal/config.rb CHANGED
@@ -93,6 +93,11 @@ module Opal
93
93
  # @return [true, false]
94
94
  config_option :freezing_stubs_enabled, true, compiler_option: :freezing
95
95
 
96
+ # Build ECMAScript modules, instead of legacy JS
97
+ #
98
+ # @return [true, false]
99
+ config_option :esm, false, compiler_option: :esm
100
+
96
101
  # Set the error severity for when a require can't be parsed at compile time.
97
102
  #
98
103
  # @example
@@ -287,11 +287,17 @@ module Opal
287
287
  end
288
288
 
289
289
  add_special :autoload do |compile_default|
290
- if scope.class_scope?
291
- str = DependencyResolver.new(compiler, arglist.children[1]).resolve
292
- compiler.requires << str unless str.nil?
293
- compile_default.call
290
+ args = arglist.children
291
+ if args.length == 2 && args[0].type == :sym
292
+ str = DependencyResolver.new(compiler, args[1], :ignore).resolve
293
+ if str.nil?
294
+ compiler.warning "File for autoload of constant '#{args[0].children[0]}' could not be bundled!"
295
+ else
296
+ compiler.requires << str
297
+ compiler.autoloads << str
298
+ end
294
299
  end
300
+ compile_default.call
295
301
  end
296
302
 
297
303
  add_special :require_tree do |compile_default|
@@ -329,6 +335,10 @@ module Opal
329
335
  end
330
336
  end
331
337
 
338
+ add_special :__dir__ do
339
+ push File.dirname(Opal::Compiler.module_name(compiler.file)).inspect
340
+ end
341
+
332
342
  # Refinements support
333
343
  add_special :using do |compile_default|
334
344
  if scope.accepts_using? && arglist.children.count == 1
@@ -428,42 +438,51 @@ module Opal
428
438
  end
429
439
 
430
440
  class DependencyResolver
431
- def initialize(compiler, sexp)
441
+ def initialize(compiler, sexp, missing_dynamic_require = nil)
432
442
  @compiler = compiler
433
443
  @sexp = sexp
444
+ @missing_dynamic_require = missing_dynamic_require || @compiler.dynamic_require_severity
434
445
  end
435
446
 
436
447
  def resolve
437
448
  handle_part @sexp
438
449
  end
439
450
 
440
- def handle_part(sexp)
441
- type = sexp.type
442
-
443
- if type == :str
444
- return sexp.children[0]
445
- elsif type == :send
446
- recv, meth, *args = sexp.children
447
-
448
- parts = args.map { |s| handle_part s }
449
-
450
- if recv.is_a?(::Opal::AST::Node) && recv.type == :const && recv.children.last == :File
451
- if meth == :expand_path
452
- return expand_path(*parts)
453
- elsif meth == :join
454
- return expand_path parts.join('/')
455
- elsif meth == :dirname
456
- return expand_path parts[0].split('/')[0...-1].join('/')
451
+ def handle_part(sexp, missing_dynamic_require = @missing_dynamic_require)
452
+ if sexp
453
+ case sexp.type
454
+ when :str
455
+ return sexp.children[0]
456
+ when :dstr
457
+ return sexp.children.map { |i| handle_part i }.join
458
+ when :begin
459
+ return handle_part sexp.children[0] if sexp.children.length == 1
460
+ when :send
461
+ recv, meth, *args = sexp.children
462
+
463
+ parts = args.map { |s| handle_part(s, :ignore) }
464
+
465
+ return nil if parts.include? nil
466
+
467
+ if recv.is_a?(::Opal::AST::Node) && recv.type == :const && recv.children.last == :File
468
+ if meth == :expand_path
469
+ return expand_path(*parts)
470
+ elsif meth == :join
471
+ return expand_path parts.join('/')
472
+ elsif meth == :dirname
473
+ return expand_path parts[0].split('/')[0...-1].join('/')
474
+ end
475
+ elsif meth == :__dir__
476
+ return File.dirname(Opal::Compiler.module_name(@compiler.file))
457
477
  end
458
478
  end
459
479
  end
460
480
 
461
- msg = 'Cannot handle dynamic require'
462
- case @compiler.dynamic_require_severity
481
+ case missing_dynamic_require
463
482
  when :error
464
- @compiler.error msg, @sexp.line
483
+ @compiler.error 'Cannot handle dynamic require', @sexp.line
465
484
  when :warning
466
- @compiler.warning msg, @sexp.line
485
+ @compiler.warning 'Cannot handle dynamic require', @sexp.line
467
486
  end
468
487
  end
469
488
 
@@ -19,7 +19,7 @@ module Opal
19
19
  # have a '.' prefix (for dot-calling), otherwise it will be
20
20
  # wrapped in brackets to use reference notation calling.
21
21
  def mid_to_jsid(mid)
22
- if %r{\=|\+|\-|\*|\/|\!|\?|<|\>|\&|\||\^|\%|\~|\[} =~ mid.to_s
22
+ if %r{\=|\+|\-|\*|\/|\!|\?|<|\>|\&|\||\^|\%|\~|\[|`} =~ mid.to_s
23
23
  "['$#{mid}']"
24
24
  else
25
25
  '.$' + mid
@@ -46,19 +46,16 @@ module Opal
46
46
  end
47
47
 
48
48
  def opening
49
- as = ""
50
- if await_encountered
51
- as = "async "
52
- end
49
+ async_prefix = "async " if await_encountered
53
50
 
54
51
  if compiler.requirable?
55
- unshift "Opal.modules[#{Opal::Compiler.module_name(compiler.file).inspect}] = #{as}function(Opal) {"
52
+ unshift "Opal.modules[#{Opal::Compiler.module_name(compiler.file).inspect}] = #{async_prefix}function(Opal) {"
56
53
  elsif compiler.eval?
57
- unshift "(#{as}function(Opal, self) {"
54
+ unshift "(#{async_prefix}function(Opal, self) {"
58
55
  elsif compiler.esm?
59
- unshift "export default Opal.queue(#{as}function(Opal) {"
56
+ unshift "export default Opal.queue(#{async_prefix}function(Opal) {"
60
57
  else
61
- unshift "Opal.queue(#{as}function(Opal) {"
58
+ unshift "Opal.queue(#{async_prefix}function(Opal) {"
62
59
  end
63
60
  end
64
61
 
@@ -47,6 +47,14 @@ module Opal
47
47
  ensure
48
48
  @specs_stack.pop
49
49
  end
50
+ elsif method_name == :fixture
51
+ # We want to expand the fixture paths before autoload happens.
52
+ if args.all? { |i| i.type == :str }
53
+ as = args.map { |i| i.children.first }
54
+ s(:str, fixture(*as))
55
+ else
56
+ super
57
+ end
50
58
  else
51
59
  super
52
60
  end
@@ -63,6 +71,14 @@ module Opal
63
71
  def current_spec_name
64
72
  @specs_stack.join(' ')
65
73
  end
74
+
75
+ # Adapted from: spec/mspec/lib/mspec/helpers/fixture.rb
76
+ def fixture(file, *args)
77
+ path = File.dirname(file)
78
+ path = path[0..-7] if path[-7..-1] == '/shared'
79
+ fixtures = path[-9..-1] == '/fixtures' ? '' : 'fixtures'
80
+ File.join(path, fixtures, args)
81
+ end
66
82
  end
67
83
  end
68
84
  end
@@ -36,7 +36,7 @@ class Opal::SimpleServer
36
36
 
37
37
  def call(env)
38
38
  case env['PATH_INFO']
39
- when %r{\A/#{@prefix}/(.*)\.js\z}
39
+ when %r{\A/#{@prefix}/(.*)\.m?js\z}
40
40
  path, _cache_invalidator = Regexp.last_match(1).split('?', 2)
41
41
  call_js(path)
42
42
  else call_index
@@ -65,7 +65,12 @@ class Opal::SimpleServer
65
65
  end
66
66
 
67
67
  def javascript_include_tag(path)
68
- %{<script src="/#{@prefix}/#{path}.js#{cache_invalidator}"></script>}
68
+ case Opal::Config.esm
69
+ when true
70
+ %{<script src="/#{@prefix}/#{path}.mjs#{cache_invalidator}" type="module"></script>}
71
+ when false
72
+ %{<script src="/#{@prefix}/#{path}.js#{cache_invalidator}"></script>}
73
+ end
69
74
  end
70
75
 
71
76
  def cache_invalidator
data/lib/opal/util.rb CHANGED
@@ -15,7 +15,7 @@ module Opal
15
15
  # @param str [String] string to minify
16
16
  # @return [String]
17
17
  def uglify(source)
18
- sh 'bin/yarn -s run uglifyjs -c', data: source
18
+ sh 'bin/yarn -s run terser -c', data: source
19
19
  end
20
20
 
21
21
  # Gzip code to check file size.
data/lib/opal/version.rb CHANGED
@@ -3,5 +3,5 @@
3
3
  module Opal
4
4
  # WHEN RELEASING:
5
5
  # Remember to update RUBY_ENGINE_VERSION in opal/corelib/constants.rb too!
6
- VERSION = '1.3.0.alpha1'
6
+ VERSION = '1.3.0.rc1'
7
7
  end
@@ -0,0 +1,15 @@
1
+ module Kernel
2
+ def Complex(real, imag = nil)
3
+ if imag
4
+ Complex.new(real, imag)
5
+ else
6
+ Complex.new(real, 0)
7
+ end
8
+ end
9
+ end
10
+
11
+ class String
12
+ def to_c
13
+ Complex.from_string(self)
14
+ end
15
+ end
@@ -1,4 +1,5 @@
1
1
  require 'corelib/numeric'
2
+ require 'corelib/complex/base'
2
3
 
3
4
  class Complex < Numeric
4
5
  def self.rect(real, imag = 0)
@@ -291,23 +292,10 @@ class Complex < Numeric
291
292
  end
292
293
 
293
294
  I = new(0, 1)
294
- end
295
-
296
- module Kernel
297
- def Complex(real, imag = nil)
298
- if imag
299
- Complex.new(real, imag)
300
- else
301
- Complex.new(real, 0)
302
- end
303
- end
304
- end
305
295
 
306
- class String
307
- def to_c
296
+ def self.from_string(str)
308
297
  %x{
309
- var str = self,
310
- re = /[+-]?[\d_]+(\.[\d_]+)?(e\d+)?/,
298
+ var re = /[+-]?[\d_]+(\.[\d_]+)?(e\d+)?/,
311
299
  match = str.match(re),
312
300
  real, imag, denominator;
313
301
 
@@ -1,8 +1,8 @@
1
1
  RUBY_PLATFORM = 'opal'
2
2
  RUBY_ENGINE = 'opal'
3
3
  RUBY_VERSION = '3.0.2'
4
- RUBY_ENGINE_VERSION = '1.3.0.alpha1'
5
- RUBY_RELEASE_DATE = '2021-09-29'
4
+ RUBY_ENGINE_VERSION = '1.3.0.rc1'
5
+ RUBY_RELEASE_DATE = '2021-10-20'
6
6
  RUBY_PATCHLEVEL = 0
7
7
  RUBY_REVISION = '0'
8
8
  RUBY_COPYRIGHT = 'opal - Copyright (C) 2013-2021 Adam Beynon and the Opal contributors'
@@ -74,7 +74,7 @@ class Exception < `Error`
74
74
 
75
75
  var backtrace = self.stack;
76
76
 
77
- if (backtrace.$$is_string) {
77
+ if (typeof(backtrace) !== 'undefined' && backtrace.$$is_string) {
78
78
  return self.backtrace = correct_backtrace(backtrace.split("\n").slice(0, 15));
79
79
  }
80
80
  else if (backtrace) {
@@ -94,6 +94,16 @@ module Opal
94
94
  name
95
95
  end
96
96
 
97
+ def self.const_name?(const_name)
98
+ %x{
99
+ if (typeof const_name !== 'string') {
100
+ #{const_name = Opal.coerce_to!(const_name, String, :to_str)}
101
+ }
102
+
103
+ return #{const_name}[0] === #{const_name}[0].toUpperCase()
104
+ }
105
+ end
106
+
97
107
  def self.const_name!(const_name)
98
108
  const_name = Opal.coerce_to!(const_name, String, :to_str)
99
109
 
data/opal/corelib/io.rb CHANGED
@@ -20,6 +20,10 @@ class IO
20
20
  end
21
21
  end
22
22
 
23
+ def fileno
24
+ @fd
25
+ end
26
+
23
27
  def tty?
24
28
  `self.tty == true`
25
29
  end
@@ -252,9 +252,11 @@ module Kernel
252
252
  def inspect
253
253
  ivs = ''
254
254
  instance_variables.each do |i|
255
- ivs += " #{i}=#{instance_variable_get(i)}"
255
+ ivs += " #{i}=#{instance_variable_get(i).inspect}"
256
256
  end
257
257
  "#<#{self.class}:0x#{__id__.to_s(16)}#{ivs}>"
258
+ rescue
259
+ "#<#{self.class}:0x#{__id__.to_s(16)}>"
258
260
  end
259
261
 
260
262
  def instance_of?(klass)
@@ -628,8 +630,14 @@ module Kernel
628
630
  Opal.pristine(self, :respond_to?, :respond_to_missing?)
629
631
 
630
632
  def require(file)
631
- file = Opal.coerce_to!(file, String, :to_str)
632
- `Opal.require(#{file})`
633
+ %x{
634
+ // As Object.require refers to Kernel.require once Kernel has been loaded the String
635
+ // class may not be available yet, the coercion requires both String and Array to be loaded.
636
+ if (typeof #{file} !== 'string' && Opal.String && Opal.Array) {
637
+ #{file = Opal.coerce_to!(file, String, :to_str) }
638
+ }
639
+ Opal.require(#{file})
640
+ }
633
641
  end
634
642
 
635
643
  def require_relative(file)
@@ -640,7 +648,7 @@ module Kernel
640
648
  end
641
649
 
642
650
  # `path` should be the full path to be found in registered modules (`Opal.modules`)
643
- def require_tree(path)
651
+ def require_tree(path, autoload: false)
644
652
  %x{
645
653
  var result = [];
646
654
 
@@ -649,7 +657,11 @@ module Kernel
649
657
  if (path === '.') path = '';
650
658
  for (var name in Opal.modules) {
651
659
  if (#{`name`.start_with?(path)}) {
652
- result.push([name, Opal.require(name)]);
660
+ if(!#{autoload}) {
661
+ result.push([name, Opal.require(name)]);
662
+ } else {
663
+ result.push([name, true]); // do nothing, delegated to a autoloading
664
+ }
653
665
  }
654
666
  }
655
667
 
@@ -735,5 +747,9 @@ module Kernel
735
747
  end
736
748
 
737
749
  class Object
750
+ # Object.require has been set to runtime.js Opal.require
751
+ # Now we have Kernel loaded, make sure Object.require refers to Kernel.require
752
+ # which is what ruby does and allows for overwriting by autoloaders
753
+ `delete Opal.Object.$$prototype.$require`
738
754
  include Kernel
739
755
  end
data/opal/corelib/main.rb CHANGED
@@ -6,6 +6,10 @@ def self.include(mod)
6
6
  Object.include mod
7
7
  end
8
8
 
9
+ def self.autoload(*args)
10
+ Object.autoload(*args)
11
+ end
12
+
9
13
  # Compiler overrides this method
10
14
  def self.using(mod)
11
15
  raise 'main.using is permitted only at toplevel'
@@ -32,6 +32,10 @@ class Method
32
32
  }
33
33
  end
34
34
 
35
+ def curry(arity = undefined)
36
+ @method.curry(arity)
37
+ end
38
+
35
39
  alias [] call
36
40
  alias === call
37
41
 
@@ -191,9 +191,38 @@ class Module
191
191
 
192
192
  def autoload(const, path)
193
193
  %x{
194
- if (self.$$autoload == null) self.$$autoload = {};
195
- Opal.const_cache_version++;
196
- self.$$autoload[#{const}] = #{path};
194
+ if (!#{Opal.const_name?(const)}) {
195
+ #{raise NameError, "autoload must be constant name: #{const}"}
196
+ }
197
+
198
+ if (path == "") {
199
+ #{raise ArgumentError, 'empty file name'}
200
+ }
201
+
202
+ if (!self.$$const.hasOwnProperty(#{const})) {
203
+ if (!self.$$autoload) {
204
+ self.$$autoload = {};
205
+ }
206
+ Opal.const_cache_version++;
207
+ self.$$autoload[#{const}] = { path: #{path}, loaded: false, required: false, success: false, exception: false };
208
+ }
209
+ return nil;
210
+ }
211
+ end
212
+
213
+ def autoload?(const)
214
+ %x{
215
+ if (self.$$autoload && self.$$autoload[#{const}] && !self.$$autoload[#{const}].required && !self.$$autoload[#{const}].success) {
216
+ return self.$$autoload[#{const}].path;
217
+ }
218
+
219
+ var ancestors = self.$ancestors();
220
+
221
+ for (var i = 0, length = ancestors.length; i < length; i++) {
222
+ if (ancestors[i].$$autoload && ancestors[i].$$autoload[#{const}] && !ancestors[i].$$autoload[#{const}].required && !ancestors[i].$$autoload[#{const}].success) {
223
+ return ancestors[i].$$autoload[#{const}].path;
224
+ }
225
+ }
197
226
  return nil;
198
227
  }
199
228
  end
@@ -283,7 +312,13 @@ class Module
283
312
 
284
313
  for (i = 0, ii = modules.length; i < ii; i++) {
285
314
  module = modules[i];
286
- if (module.$$const[name] != null) {
315
+ if (module.$$const[#{name}] != null) { return true; }
316
+ if (
317
+ module.$$autoload &&
318
+ module.$$autoload[#{name}] &&
319
+ !module.$$autoload[#{name}].required &&
320
+ !module.$$autoload[#{name}].success
321
+ ) {
287
322
  return true;
288
323
  }
289
324
  }
@@ -317,18 +352,6 @@ class Module
317
352
  end
318
353
 
319
354
  def const_missing(name)
320
- %x{
321
- if (self.$$autoload) {
322
- var file = self.$$autoload[name];
323
-
324
- if (file) {
325
- self.$require(file);
326
-
327
- return #{const_get name};
328
- }
329
- }
330
- }
331
-
332
355
  full_const_name = self == Object ? name : "#{self}::#{name}"
333
356
 
334
357
  raise NameError.new("uninitialized constant #{full_const_name}", name)
@@ -0,0 +1,35 @@
1
+ class Array
2
+ def deconstruct
3
+ self
4
+ end
5
+ end
6
+
7
+ class Hash
8
+ def deconstruct_keys(_)
9
+ self
10
+ end
11
+ end
12
+
13
+ class Struct
14
+ alias deconstruct to_a
15
+ # This function is specified in a very weird way...
16
+ def deconstruct_keys(keys)
17
+ return to_h if keys.nil?
18
+ raise TypeError, 'expected Array or nil' unless Array === keys
19
+ return {} if keys.length > values.length
20
+ out = {}
21
+ keys.each do |key|
22
+ should_break = case key
23
+ when Integer
24
+ values.length < key
25
+ when Symbol # Or String? Doesn't matter, we're in Opal.
26
+ !members.include?(key)
27
+ end
28
+ break if should_break
29
+ out[key] = self[key]
30
+ end
31
+ out
32
+ end
33
+ end
34
+
35
+ class NoMatchingPatternError < StandardError; end
@@ -1,3 +1,5 @@
1
+ require 'corelib/pattern_matching/base'
2
+
1
3
  # A "userland" implementation of pattern matching for Opal
2
4
 
3
5
  class PatternMatching
@@ -121,39 +123,3 @@ class PatternMatching
121
123
  end
122
124
  end
123
125
  end
124
-
125
- class Array
126
- def deconstruct
127
- self
128
- end
129
- end
130
-
131
- class Hash
132
- def deconstruct_keys(_)
133
- self
134
- end
135
- end
136
-
137
- class Struct
138
- alias deconstruct to_a
139
- # This function is specified in a very weird way...
140
- def deconstruct_keys(keys)
141
- return to_h if keys.nil?
142
- raise TypeError, 'expected Array or nil' unless Array === keys
143
- return {} if keys.length > values.length
144
- out = {}
145
- keys.each do |key|
146
- should_break = case key
147
- when Integer
148
- values.length < key
149
- when Symbol # Or String? Doesn't matter, we're in Opal.
150
- !members.include?(key)
151
- end
152
- break if should_break
153
- out[key] = self[key]
154
- end
155
- out
156
- end
157
- end
158
-
159
- class NoMatchingPatternError < StandardError; end
@@ -0,0 +1,9 @@
1
+ class Signal
2
+ def self.trap(*)
3
+ end
4
+ end
5
+
6
+ class GC
7
+ def self.start
8
+ end
9
+ end
@@ -1,4 +1,4 @@
1
- class Process
1
+ module Process
2
2
  @__clocks__ = []
3
3
  def self.__register_clock__(name, func)
4
4
  const_set name, @__clocks__.size
@@ -55,13 +55,3 @@ class Process
55
55
  }
56
56
  end
57
57
  end
58
-
59
- class Signal
60
- def self.trap(*)
61
- end
62
- end
63
-
64
- class GC
65
- def self.start
66
- end
67
- end
@@ -1,5 +1,7 @@
1
1
  # helpers: falsy
2
2
 
3
+ require 'corelib/random/formatter'
4
+
3
5
  class Random
4
6
  attr_reader :seed, :state
5
7
 
@@ -88,3 +90,5 @@ class Random
88
90
  end
89
91
  end
90
92
  end
93
+
94
+ require 'corelib/random/mersenne_twister'
@@ -0,0 +1,11 @@
1
+ module Kernel
2
+ def Rational(numerator, denominator = 1)
3
+ Rational.convert(numerator, denominator)
4
+ end
5
+ end
6
+
7
+ class String
8
+ def to_r
9
+ Rational.from_string(self)
10
+ end
11
+ end