opal 1.5.1 → 1.6.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +4 -0
  3. data/.github/workflows/build.yml +17 -3
  4. data/HACKING.md +23 -0
  5. data/README.md +3 -3
  6. data/UNRELEASED.md +47 -0
  7. data/benchmark/run.rb +1 -0
  8. data/docs/compiled_ruby.md +8 -0
  9. data/docs/compiler.md +1 -1
  10. data/docs/compiler_directives.md +1 -1
  11. data/docs/getting_started.md +17 -0
  12. data/docs/headless_chrome.md +1 -1
  13. data/docs/index.md +123 -0
  14. data/docs/jquery.md +5 -5
  15. data/docs/templates.md +37 -37
  16. data/docs/unsupported_features.md +0 -4
  17. data/lib/opal/builder.rb +59 -39
  18. data/lib/opal/builder_processors.rb +24 -0
  19. data/lib/opal/builder_scheduler/prefork.rb +262 -0
  20. data/lib/opal/builder_scheduler/sequential.rb +13 -0
  21. data/lib/opal/builder_scheduler.rb +29 -0
  22. data/lib/opal/cache/file_cache.rb +13 -2
  23. data/lib/opal/cli.rb +36 -19
  24. data/lib/opal/cli_options.rb +4 -0
  25. data/lib/opal/cli_runners/chrome.rb +17 -13
  26. data/lib/opal/cli_runners/chrome_cdp_interface.rb +19 -2
  27. data/lib/opal/cli_runners/compiler.rb +1 -1
  28. data/lib/opal/cli_runners/gjs.rb +3 -1
  29. data/lib/opal/cli_runners/mini_racer.rb +5 -3
  30. data/lib/opal/cli_runners/nodejs.rb +3 -3
  31. data/lib/opal/cli_runners/server.rb +13 -28
  32. data/lib/opal/cli_runners/system_runner.rb +5 -3
  33. data/lib/opal/cli_runners.rb +7 -6
  34. data/lib/opal/compiler.rb +25 -2
  35. data/lib/opal/config.rb +10 -0
  36. data/lib/opal/eof_content.rb +5 -2
  37. data/lib/opal/nodes/args/ensure_kwargs_are_kwargs.rb +2 -6
  38. data/lib/opal/nodes/args/extract_kwarg.rb +3 -4
  39. data/lib/opal/nodes/args/extract_kwargs.rb +3 -1
  40. data/lib/opal/nodes/args/extract_kwoptarg.rb +1 -1
  41. data/lib/opal/nodes/args/extract_kwrestarg.rb +4 -1
  42. data/lib/opal/nodes/args/extract_optarg.rb +1 -1
  43. data/lib/opal/nodes/args/extract_post_arg.rb +1 -1
  44. data/lib/opal/nodes/args/extract_post_optarg.rb +1 -1
  45. data/lib/opal/nodes/args/extract_restarg.rb +2 -2
  46. data/lib/opal/nodes/args/initialize_iterarg.rb +1 -1
  47. data/lib/opal/nodes/args/initialize_shadowarg.rb +1 -1
  48. data/lib/opal/nodes/args/prepare_post_args.rb +4 -2
  49. data/lib/opal/nodes/base.rb +14 -3
  50. data/lib/opal/nodes/call.rb +13 -16
  51. data/lib/opal/nodes/class.rb +3 -1
  52. data/lib/opal/nodes/closure.rb +250 -0
  53. data/lib/opal/nodes/def.rb +7 -11
  54. data/lib/opal/nodes/definitions.rb +4 -2
  55. data/lib/opal/nodes/if.rb +12 -2
  56. data/lib/opal/nodes/iter.rb +11 -17
  57. data/lib/opal/nodes/logic.rb +15 -63
  58. data/lib/opal/nodes/module.rb +3 -1
  59. data/lib/opal/nodes/rescue.rb +23 -15
  60. data/lib/opal/nodes/scope.rb +7 -1
  61. data/lib/opal/nodes/top.rb +27 -4
  62. data/lib/opal/nodes/while.rb +42 -26
  63. data/lib/opal/nodes.rb +1 -0
  64. data/lib/opal/os.rb +59 -0
  65. data/lib/opal/rewriter.rb +2 -0
  66. data/lib/opal/rewriters/returnable_logic.rb +14 -0
  67. data/lib/opal/rewriters/thrower_finder.rb +90 -0
  68. data/lib/opal/simple_server.rb +12 -6
  69. data/lib/opal/source_map/file.rb +4 -3
  70. data/lib/opal/source_map/map.rb +9 -1
  71. data/lib/opal/util.rb +1 -1
  72. data/lib/opal/version.rb +1 -1
  73. data/opal/corelib/array.rb +68 -3
  74. data/opal/corelib/basic_object.rb +1 -0
  75. data/opal/corelib/comparable.rb +1 -1
  76. data/opal/corelib/complex.rb +1 -0
  77. data/opal/corelib/constants.rb +2 -2
  78. data/opal/corelib/enumerable.rb +4 -2
  79. data/opal/corelib/enumerator/chain.rb +4 -0
  80. data/opal/corelib/enumerator/generator.rb +5 -3
  81. data/opal/corelib/enumerator/lazy.rb +3 -1
  82. data/opal/corelib/enumerator/yielder.rb +2 -4
  83. data/opal/corelib/enumerator.rb +3 -1
  84. data/opal/corelib/error/errno.rb +3 -1
  85. data/opal/corelib/error.rb +13 -2
  86. data/opal/corelib/hash.rb +39 -1
  87. data/opal/corelib/io.rb +1 -1
  88. data/opal/corelib/kernel.rb +56 -5
  89. data/opal/corelib/module.rb +60 -4
  90. data/opal/corelib/proc.rb +8 -5
  91. data/opal/corelib/rational.rb +1 -0
  92. data/opal/corelib/regexp.rb +15 -1
  93. data/opal/corelib/runtime.js +307 -238
  94. data/opal/corelib/string/encoding.rb +0 -6
  95. data/opal/corelib/string.rb +28 -7
  96. data/opal/corelib/time.rb +5 -2
  97. data/opal/corelib/unsupported.rb +2 -14
  98. data/opal.gemspec +2 -2
  99. data/spec/filters/bugs/delegate.rb +11 -0
  100. data/spec/filters/bugs/kernel.rb +1 -3
  101. data/spec/filters/bugs/language.rb +3 -23
  102. data/spec/filters/bugs/method.rb +0 -1
  103. data/spec/filters/bugs/module.rb +0 -3
  104. data/spec/filters/bugs/proc.rb +0 -3
  105. data/spec/filters/bugs/set.rb +4 -16
  106. data/spec/filters/bugs/unboundmethod.rb +0 -2
  107. data/spec/filters/unsupported/array.rb +0 -58
  108. data/spec/filters/unsupported/freeze.rb +8 -192
  109. data/spec/filters/unsupported/hash.rb +0 -25
  110. data/spec/filters/unsupported/kernel.rb +0 -1
  111. data/spec/filters/unsupported/privacy.rb +17 -0
  112. data/spec/lib/builder_spec.rb +14 -0
  113. data/spec/lib/cli_runners/server_spec.rb +2 -3
  114. data/spec/lib/cli_spec.rb +15 -1
  115. data/spec/lib/compiler_spec.rb +1 -1
  116. data/spec/opal/core/language/DATA/characters_support_crlf_spec.rb +9 -0
  117. data/spec/opal/core/language/DATA/multiple___END___crlf_spec.rb +10 -0
  118. data/spec/opal/core/language/if_spec.rb +13 -0
  119. data/spec/opal/core/language/safe_navigator_spec.rb +10 -0
  120. data/spec/opal/core/module_spec.rb +8 -0
  121. data/spec/ruby_specs +2 -1
  122. data/stdlib/await.rb +44 -7
  123. data/stdlib/delegate.rb +427 -6
  124. data/stdlib/headless_chrome.rb +6 -2
  125. data/stdlib/nodejs/file.rb +2 -1
  126. data/stdlib/opal-parser.rb +1 -1
  127. data/stdlib/opal-platform.rb +1 -1
  128. data/stdlib/opal-replutils.rb +5 -3
  129. data/stdlib/promise.rb +3 -0
  130. data/stdlib/rbconfig.rb +4 -1
  131. data/stdlib/ruby2_keywords.rb +60 -0
  132. data/stdlib/set.rb +21 -0
  133. data/tasks/performance.rake +41 -35
  134. data/tasks/releasing.rake +1 -0
  135. data/tasks/testing/mspec_special_calls.rb +1 -0
  136. data/tasks/testing.rake +13 -12
  137. data/test/nodejs/test_await.rb +39 -1
  138. data/test/nodejs/test_file.rb +3 -2
  139. metadata +37 -22
  140. data/docs/faq.md +0 -17
  141. data/lib/opal/rewriters/break_finder.rb +0 -36
  142. data/spec/opal/core/kernel/freeze_spec.rb +0 -15
data/stdlib/await.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # helpers: coerce_to
2
- # await: true
2
+ # await: await
3
3
 
4
4
  if `Opal.config.experimental_features_severity == 'warning'`
5
5
  warn 'Await functionality is a technology preview, which means it may change its behavior ' \
@@ -19,21 +19,25 @@ class Array
19
19
  i = 0
20
20
  results = []
21
21
  while i < `self.length`
22
- results << yield(self[i]).__await__
22
+ results << yield(self[i]).await
23
23
  i += 1
24
24
  end
25
25
  results
26
26
  end
27
27
 
28
28
  def each_await(&block)
29
- map_await(&block).__await__
29
+ i = 0
30
+ while i < `self.length`
31
+ yield(self[i]).await
32
+ i += 1
33
+ end
30
34
  self
31
35
  end
32
36
  end
33
37
 
34
38
  module Enumerable
35
39
  def each_async(&block)
36
- PromiseV2.when(*map(&block)).__await__
40
+ PromiseV2.when(*map(&block)).await
37
41
  end
38
42
  end
39
43
 
@@ -44,7 +48,7 @@ module Kernel
44
48
 
45
49
  until $__at_exit__.empty?
46
50
  block = $__at_exit__.pop
47
- block.call.__await__
51
+ block.call.await
48
52
  end
49
53
 
50
54
  %x{
@@ -64,9 +68,7 @@ module Kernel
64
68
  `setTimeout(#{proc { prom.resolve }}, #{seconds * 1000})`
65
69
  prom
66
70
  end
67
- end
68
71
 
69
- module Kernel
70
72
  alias await itself
71
73
  end
72
74
 
@@ -81,3 +83,38 @@ class Method
81
83
  @method.async?
82
84
  end
83
85
  end
86
+
87
+ class BasicObject
88
+ def instance_exec_await(*args, &block)
89
+ ::Kernel.raise ::ArgumentError, 'no block given' unless block
90
+
91
+ # The awaits are defined inside an x-string. Opal can't find them
92
+ # reliably and async-ify a method. Therefore, let's make Opal know
93
+ # this is an async method.
94
+ nil.__await__
95
+
96
+ %x{
97
+ var block_self = block.$$s,
98
+ result;
99
+
100
+ block.$$s = null;
101
+
102
+ if (self.$$is_a_module) {
103
+ self.$$eval = true;
104
+ try {
105
+ result = await block.apply(self, args);
106
+ }
107
+ finally {
108
+ self.$$eval = false;
109
+ }
110
+ }
111
+ else {
112
+ result = await block.apply(self, args);
113
+ }
114
+
115
+ block.$$s = block_self;
116
+
117
+ return result;
118
+ }
119
+ end
120
+ end
data/stdlib/delegate.rb CHANGED
@@ -1,13 +1,99 @@
1
+ # frozen_string_literal: true
2
+ # helpers: freeze, freeze_props
3
+ # = delegate -- Support for the Delegation Pattern
4
+ #
5
+ # This file ended up in Opal as a port of the following file:
6
+ # https://github.com/ruby/ruby/blob/master/lib/delegate.rb
7
+ #
8
+ # Documentation by James Edward Gray II and Gavin Sinclair
9
+
10
+ ##
11
+ # This library provides three different ways to delegate method calls to an
12
+ # object. The easiest to use is SimpleDelegator. Pass an object to the
13
+ # constructor and all methods supported by the object will be delegated. This
14
+ # object can be changed later.
15
+ #
16
+ # Going a step further, the top level DelegateClass method allows you to easily
17
+ # setup delegation through class inheritance. This is considerably more
18
+ # flexible and thus probably the most common use for this library.
19
+ #
20
+ # Finally, if you need full control over the delegation scheme, you can inherit
21
+ # from the abstract class Delegator and customize as needed. (If you find
22
+ # yourself needing this control, have a look at Forwardable which is also in
23
+ # the standard library. It may suit your needs better.)
24
+ #
25
+ # SimpleDelegator's implementation serves as a nice example of the use of
26
+ # Delegator:
27
+ #
28
+ # require 'delegate'
29
+ #
30
+ # class SimpleDelegator < Delegator
31
+ # def __getobj__
32
+ # @delegate_sd_obj # return object we are delegating to, required
33
+ # end
34
+ #
35
+ # def __setobj__(obj)
36
+ # @delegate_sd_obj = obj # change delegation object,
37
+ # # a feature we're providing
38
+ # end
39
+ # end
40
+ #
41
+ # == Notes
42
+ #
43
+ # Be advised, RDoc will not detect delegated methods.
44
+ #
45
+ require 'ruby2_keywords'
46
+
1
47
  class Delegator < BasicObject
48
+ VERSION = '0.2.0'
49
+
50
+ kernel = ::Kernel.dup
51
+ kernel.class_eval do
52
+ alias_method :__raise__, :raise
53
+ # somehow this doesn't work in Opal:
54
+ # %i[to_s inspect !~ === <=> hash].each do |m|
55
+ # undef_method m
56
+ # end
57
+ private_instance_methods.each do |m|
58
+ if /\Ablock_given\?\z|\Aiterator\?\z|\A__.*__\z/ =~ m
59
+ next
60
+ end
61
+ undef_method m
62
+ end
63
+ end
64
+ include kernel
65
+
66
+ # :stopdoc:
67
+ def self.const_missing(n)
68
+ ::Object.const_get(n)
69
+ end
70
+ # :startdoc:
71
+
72
+ ##
73
+ # :method: raise
74
+ # Use #__raise__ if your Delegator does not have a object to delegate the
75
+ # #raise method call.
76
+ #
77
+
78
+ #
79
+ # Pass in the _obj_ to delegate method calls to. All methods supported by
80
+ # _obj_ will be delegated to.
81
+ #
2
82
  def initialize(obj)
3
83
  __setobj__(obj)
4
84
  end
5
85
 
6
- def method_missing(m, *args, &block)
7
- target = __getobj__
86
+ #
87
+ # Handles the magic of delegation through \_\_getobj\_\_.
88
+ #
89
+ ruby2_keywords def method_missing(m, *args, &block) # rubocop:disable Style/MissingRespondToMissing
90
+ r = true
91
+ target = __getobj__ { r = false }
8
92
 
9
- if target.respond_to?(m)
93
+ if r && target_respond_to?(target, m, false)
10
94
  target.__send__(m, *args, &block)
95
+ elsif ::Kernel.method_defined?(m) || ::Kernel.private_method_defined?(m)
96
+ ::Kernel.instance_method(m).bind_call(self, *args, &block)
11
97
  else
12
98
  super(m, *args, &block)
13
99
  end
@@ -18,20 +104,355 @@ class Delegator < BasicObject
18
104
  # call through \_\_getobj\_\_.
19
105
  #
20
106
  def respond_to_missing?(m, include_private)
21
- __getobj__.respond_to?(m, include_private)
107
+ r = true
108
+ target = __getobj__ { r = false }
109
+ r &&= target_respond_to?(target, m, include_private)
110
+ if r && include_private && !target_respond_to?(target, m, false)
111
+ warn "delegator does not forward private method \##{m}", uplevel: 3
112
+ return false
113
+ end
114
+ r
115
+ end
116
+
117
+ KERNEL_RESPOND_TO = ::Kernel.instance_method(:respond_to?)
118
+ private_constant :KERNEL_RESPOND_TO
119
+
120
+ # Handle BasicObject instances
121
+ private def target_respond_to?(target, m, include_private)
122
+ case target
123
+ when Object
124
+ target.respond_to?(m, include_private)
125
+ else
126
+ if KERNEL_RESPOND_TO.bind_call(target, :respond_to?)
127
+ target.respond_to?(m, include_private)
128
+ else
129
+ KERNEL_RESPOND_TO.bind_call(target, m, include_private)
130
+ end
131
+ end
132
+ end
133
+
134
+ #
135
+ # Returns the methods available to this delegate object as the union
136
+ # of this object's and \_\_getobj\_\_ methods.
137
+ #
138
+ def methods(all = true)
139
+ __getobj__.methods(all) | super
140
+ end
141
+
142
+ #
143
+ # Returns the methods available to this delegate object as the union
144
+ # of this object's and \_\_getobj\_\_ public methods.
145
+ #
146
+ def public_methods(all = true)
147
+ __getobj__.public_methods(all) | super
148
+ end
149
+
150
+ #
151
+ # Returns the methods available to this delegate object as the union
152
+ # of this object's and \_\_getobj\_\_ protected methods.
153
+ #
154
+ def protected_methods(all = true)
155
+ __getobj__.protected_methods(all) | super
156
+ end
157
+
158
+ # Note: no need to specialize private_methods, since they are not forwarded
159
+
160
+ #
161
+ # Returns true if two objects are considered of equal value.
162
+ #
163
+ def ==(obj)
164
+ return true if obj.equal?(self)
165
+ __getobj__ == obj
166
+ end
167
+
168
+ #
169
+ # Returns true if two objects are not considered of equal value.
170
+ #
171
+ def !=(obj)
172
+ return false if obj.equal?(self)
173
+ __getobj__ != obj
174
+ end
175
+
176
+ #
177
+ # Returns true if two objects are considered of equal value.
178
+ #
179
+ def eql?(obj)
180
+ return true if obj.equal?(self)
181
+ obj.eql?(__getobj__)
182
+ end
183
+
184
+ #
185
+ # Delegates ! to the \_\_getobj\_\_
186
+ #
187
+ def !
188
+ !__getobj__
189
+ end
190
+
191
+ #
192
+ # This method must be overridden by subclasses and should return the object
193
+ # method calls are being delegated to.
194
+ #
195
+ def __getobj__
196
+ __raise__ ::NotImplementedError, "need to define `__getobj__'"
197
+ end
198
+
199
+ #
200
+ # This method must be overridden by subclasses and change the object delegate
201
+ # to _obj_.
202
+ #
203
+ def __setobj__(obj)
204
+ __raise__ ::NotImplementedError, "need to define `__setobj__'"
205
+ end
206
+
207
+ #
208
+ # Serialization support for the object returned by \_\_getobj\_\_.
209
+ #
210
+ def marshal_dump
211
+ ivars = instance_variables.reject { |var| /\A@delegate_/ =~ var }
212
+ [
213
+ :__v2__,
214
+ ivars, ivars.map { |var| instance_variable_get(var) },
215
+ __getobj__
216
+ ]
217
+ end
218
+
219
+ #
220
+ # Reinitializes delegation from a serialized object.
221
+ #
222
+ def marshal_load(data)
223
+ version, vars, values, obj = data
224
+ if version == :__v2__
225
+ vars.each_with_index { |var, i| instance_variable_set(var, values[i]) }
226
+ __setobj__(obj)
227
+ else
228
+ __setobj__(data)
229
+ end
230
+ end
231
+
232
+ def initialize_clone(obj, freeze: nil) # :nodoc:
233
+ __setobj__(obj.__getobj__.clone(freeze: freeze))
234
+ end
235
+
236
+ def initialize_dup(obj) # :nodoc:
237
+ __setobj__(obj.__getobj__.dup)
238
+ end
239
+ private :initialize_clone, :initialize_dup
240
+
241
+ ##
242
+ # :method: freeze
243
+ # Freeze both the object returned by \_\_getobj\_\_ and self.
244
+ #
245
+ def freeze
246
+ __getobj__.freeze
247
+ `$freeze_props(self)`
248
+ `$freeze(self)`
249
+ end
250
+
251
+ def frozen?
252
+ `(self.$$frozen || false)`
253
+ end
254
+
255
+ @delegator_api = public_instance_methods
256
+ def self.public_api # :nodoc:
257
+ @delegator_api
22
258
  end
23
259
  end
24
260
 
261
+ ##
262
+ # A concrete implementation of Delegator, this class provides the means to
263
+ # delegate all supported method calls to the object passed into the constructor
264
+ # and even to change the object being delegated to at a later time with
265
+ # #__setobj__.
266
+ #
267
+ # class User
268
+ # def born_on
269
+ # Date.new(1989, 9, 10)
270
+ # end
271
+ # end
272
+ #
273
+ # require 'delegate'
274
+ #
275
+ # class UserDecorator < SimpleDelegator
276
+ # def birth_year
277
+ # born_on.year
278
+ # end
279
+ # end
280
+ #
281
+ # decorated_user = UserDecorator.new(User.new)
282
+ # decorated_user.birth_year #=> 1989
283
+ # decorated_user.__getobj__ #=> #<User: ...>
284
+ #
285
+ # A SimpleDelegator instance can take advantage of the fact that SimpleDelegator
286
+ # is a subclass of +Delegator+ to call <tt>super</tt> to have methods called on
287
+ # the object being delegated to.
288
+ #
289
+ # class SuperArray < SimpleDelegator
290
+ # def [](*args)
291
+ # super + 1
292
+ # end
293
+ # end
294
+ #
295
+ # SuperArray.new([1])[0] #=> 2
296
+ #
297
+ # Here's a simple example that takes advantage of the fact that
298
+ # SimpleDelegator's delegation object can be changed at any time.
299
+ #
300
+ # class Stats
301
+ # def initialize
302
+ # @source = SimpleDelegator.new([])
303
+ # end
304
+ #
305
+ # def stats(records)
306
+ # @source.__setobj__(records)
307
+ #
308
+ # "Elements: #{@source.size}\n" +
309
+ # " Non-Nil: #{@source.compact.size}\n" +
310
+ # " Unique: #{@source.uniq.size}\n"
311
+ # end
312
+ # end
313
+ #
314
+ # s = Stats.new
315
+ # puts s.stats(%w{James Edward Gray II})
316
+ # puts
317
+ # puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])
318
+ #
319
+ # Prints:
320
+ #
321
+ # Elements: 4
322
+ # Non-Nil: 4
323
+ # Unique: 4
324
+ #
325
+ # Elements: 8
326
+ # Non-Nil: 7
327
+ # Unique: 6
328
+ #
25
329
  class SimpleDelegator < Delegator
330
+ # Returns the current object method calls are being delegated to.
26
331
  def __getobj__
332
+ unless defined?(@delegate_sd_obj)
333
+ return yield if block_given?
334
+ __raise__ ::ArgumentError, 'not delegated'
335
+ end
27
336
  @delegate_sd_obj
28
337
  end
29
338
 
339
+ #
340
+ # Changes the delegate object to _obj_.
341
+ #
342
+ # It's important to note that this does *not* cause SimpleDelegator's methods
343
+ # to change. Because of this, you probably only want to change delegation
344
+ # to objects of the same type as the original delegate.
345
+ #
346
+ # Here's an example of changing the delegation object.
347
+ #
348
+ # names = SimpleDelegator.new(%w{James Edward Gray II})
349
+ # puts names[1] # => Edward
350
+ # names.__setobj__(%w{Gavin Sinclair})
351
+ # puts names[1] # => Sinclair
352
+ #
30
353
  def __setobj__(obj)
354
+ __raise__ ::ArgumentError, 'cannot delegate to self' if equal?(obj)
31
355
  @delegate_sd_obj = obj
32
356
  end
33
357
  end
34
358
 
35
- def DelegateClass(superklass)
36
- SimpleDelegator
359
+ def Delegator.delegating_block(mid) # :nodoc:
360
+ ->(*args, &block) do
361
+ target = __getobj__
362
+ target.__send__(mid, *args, &block)
363
+ end.ruby2_keywords
364
+ end
365
+
366
+ #
367
+ # The primary interface to this library. Use to setup delegation when defining
368
+ # your class.
369
+ #
370
+ # class MyClass < DelegateClass(ClassToDelegateTo) # Step 1
371
+ # def initialize
372
+ # super(obj_of_ClassToDelegateTo) # Step 2
373
+ # end
374
+ # end
375
+ #
376
+ # or:
377
+ #
378
+ # MyClass = DelegateClass(ClassToDelegateTo) do # Step 1
379
+ # def initialize
380
+ # super(obj_of_ClassToDelegateTo) # Step 2
381
+ # end
382
+ # end
383
+ #
384
+ # Here's a sample of use from Tempfile which is really a File object with a
385
+ # few special rules about storage location and when the File should be
386
+ # deleted. That makes for an almost textbook perfect example of how to use
387
+ # delegation.
388
+ #
389
+ # class Tempfile < DelegateClass(File)
390
+ # # constant and class member data initialization...
391
+ #
392
+ # def initialize(basename, tmpdir=Dir::tmpdir)
393
+ # # build up file path/name in var tmpname...
394
+ #
395
+ # @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
396
+ #
397
+ # # ...
398
+ #
399
+ # super(@tmpfile)
400
+ #
401
+ # # below this point, all methods of File are supported...
402
+ # end
403
+ #
404
+ # # ...
405
+ # end
406
+ #
407
+ def DelegateClass(superclass, &block)
408
+ klass = Class.new(Delegator)
409
+ ignores = [*::Delegator.public_api, :to_s, :inspect, :=~, :!~, :===]
410
+ protected_instance_methods = superclass.protected_instance_methods
411
+ protected_instance_methods -= ignores
412
+ public_instance_methods = superclass.public_instance_methods
413
+ public_instance_methods -= ignores
414
+ klass.module_eval do
415
+ def __getobj__ # :nodoc:
416
+ unless defined?(@delegate_dc_obj)
417
+ return yield if block_given?
418
+ __raise__ ::ArgumentError, 'not delegated'
419
+ end
420
+ @delegate_dc_obj
421
+ end
422
+
423
+ def __setobj__(obj) # :nodoc:
424
+ __raise__ ::ArgumentError, 'cannot delegate to self' if equal?(obj)
425
+ @delegate_dc_obj = obj
426
+ end
427
+ protected_instance_methods.each do |method|
428
+ define_method(method, Delegator.delegating_block(method))
429
+ protected method
430
+ end
431
+ public_instance_methods.each do |method|
432
+ define_method(method, Delegator.delegating_block(method))
433
+ end
434
+ end
435
+ klass.define_singleton_method :public_instance_methods do |all = true|
436
+ super(all) | superclass.public_instance_methods
437
+ end
438
+ klass.define_singleton_method :protected_instance_methods do |all = true|
439
+ super(all) | superclass.protected_instance_methods
440
+ end
441
+ klass.define_singleton_method :instance_methods do |all = true|
442
+ super(all) | superclass.instance_methods
443
+ end
444
+ klass.define_singleton_method :public_instance_method do |name|
445
+ super(name)
446
+ rescue NameError
447
+ raise unless self.public_instance_methods.include?(name)
448
+ superclass.public_instance_method(name)
449
+ end
450
+ klass.define_singleton_method :instance_method do |name|
451
+ super(name)
452
+ rescue NameError
453
+ raise unless instance_methods.include?(name)
454
+ superclass.instance_method(name)
455
+ end
456
+ klass.module_eval(&block) if block
457
+ klass
37
458
  end
@@ -1,11 +1,15 @@
1
1
  %x{
2
+ // Inhibit the default exit behavior
3
+ window.OPAL_EXIT_CODE = "noexit";
4
+
2
5
  Opal.exit = function(code) {
3
- // You can't exit from the browser.
4
6
  // The first call to Opal.exit should save an exit code.
5
7
  // All next invocations must be ignored.
8
+ // Then we send an event to Chrome CDP Interface that we are finished
6
9
 
7
- if (typeof(window.OPAL_EXIT_CODE) === "undefined") {
10
+ if (window.OPAL_EXIT_CODE === "noexit") {
8
11
  window.OPAL_EXIT_CODE = code;
12
+ window.alert("opalheadlesschromeexit");
9
13
  }
10
14
  }
11
15
  }
@@ -103,7 +103,7 @@ require 'corelib/file'
103
103
  var error_class = #{Errno.const_get(`error.code`)}
104
104
  #{Kernel.raise `error_class`.new(`error.message`)}
105
105
  }
106
- #{Kernel.raise error}
106
+ #{Kernel.raise `error`}
107
107
  }
108
108
  }
109
109
  }
@@ -165,6 +165,7 @@ class File < IO
165
165
  def self.join(*paths)
166
166
  # by itself, `path.posix.join` normalizes leading // to /.
167
167
  # restore the leading / on UNC paths (i.e., paths starting with //).
168
+ paths = paths.map(&:to_s)
168
169
  prefix = paths.first&.start_with?('//') ? '/' : ''
169
170
  `#{prefix} + __path__.posix.join.apply(__path__, #{paths})`
170
171
  end
@@ -50,7 +50,7 @@ end
50
50
  };
51
51
 
52
52
  Opal['eval'] = function(str, options) {
53
- return eval(Opal.compile(str, options));
53
+ return eval(Opal.compile(str, options));
54
54
  };
55
55
 
56
56
  function run_ruby_scripts() {
@@ -3,7 +3,7 @@
3
3
  browser = `typeof(document) !== "undefined"`
4
4
  node = `typeof(process) !== "undefined" && process.versions && process.versions.node`
5
5
  nashorn = `typeof(Java) !== "undefined" && Java.type`
6
- headless_chrome = `typeof(navigator) !== "undefined" && /\bHeadlessChrome\//.test(navigator.userAgent)`
6
+ headless_chrome = `typeof(opalheadlesschrome) !== 'undefined'`
7
7
  gjs = `typeof(window) !== "undefined" && typeof(GjsFileImporter) !== 'undefined'`
8
8
  quickjs = `typeof(window) === "undefined" && typeof(__loadScript) !== 'undefined'`
9
9
  opal_miniracer = `typeof(opalminiracer) !== 'undefined'`
@@ -212,8 +212,10 @@ module REPLUtils
212
212
  },
213
213
  head: {
214
214
  self: "\e[45m",
215
- filename: "\e[37;45m"
215
+ filename: "\e[37;45m",
216
216
  },
217
+
218
+ reset: "\e[0m",
217
219
  }
218
220
 
219
221
  TOKEN_COLORS[:keyword] = TOKEN_COLORS[:reserved]
@@ -238,7 +240,7 @@ module REPLUtils
238
240
  end
239
241
 
240
242
  def self.token(string, *name)
241
- TOKEN_COLORS.dig(*name) + string + "\e[0m"
243
+ TOKEN_COLORS.dig(*name) + string + TOKEN_COLORS[:reset]
242
244
  end
243
245
 
244
246
  NUMBER = '[+-]?(?:0x[0-9a-fA-F]+|[0-9.]+(?:e[+-][0-9]+|i)?)'
@@ -274,7 +276,7 @@ module REPLUtils
274
276
  when 'true', 'false', 'nil'
275
277
  token(tok, :predefined_constant)
276
278
  else
277
- tok
279
+ token(tok, :reset)
278
280
  end
279
281
  end.join
280
282
  end
data/stdlib/promise.rb CHANGED
@@ -332,6 +332,9 @@ class Promise
332
332
  v2
333
333
  end
334
334
 
335
+ # PromiseV1 is not a native construct, we must convert it to a v2 promise
336
+ alias await to_v2
337
+
335
338
  alias catch fail
336
339
  alias catch! fail!
337
340
  alias do then
data/stdlib/rbconfig.rb CHANGED
@@ -7,10 +7,13 @@ module RbConfig
7
7
  'TEENY' => versions[2],
8
8
  'RUBY' => RUBY_ENGINE,
9
9
  'RUBY_INSTALL_NAME' => RUBY_ENGINE,
10
+ 'ruby_install_name' => RUBY_ENGINE,
10
11
  'RUBY_SO_NAME' => RUBY_ENGINE,
11
12
  'target_os' => 'ECMA-262',
12
13
  'host_os' => 'ECMA-262',
13
- 'PATH_SEPARATOR' => ':'
14
+ 'PATH_SEPARATOR' => ':',
15
+ 'EXEEXT' => '',
16
+ 'bindir' => '',
14
17
  }
15
18
  end
16
19