opal 1.3.0.alpha1 → 1.3.0.rc1

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.
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