opal 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +4 -4
  3. data/.github/ISSUE_TEMPLATE/bug-report.md +47 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/workflows/build.yml +11 -5
  6. data/.gitignore +1 -0
  7. data/.jshintrc +1 -1
  8. data/.rubocop.yml +2 -1
  9. data/CHANGELOG.md +95 -1
  10. data/Gemfile +0 -4
  11. data/HACKING.md +1 -1
  12. data/README.md +19 -15
  13. data/UNRELEASED.md +37 -96
  14. data/benchmark-ips/bm_array_unshift.rb +7 -0
  15. data/bin/build-browser-source-map-support +2 -3
  16. data/bin/opal-mspec +2 -0
  17. data/docs/compiler.md +1 -1
  18. data/examples/rack/Gemfile +0 -1
  19. data/examples/rack/Gemfile.lock +0 -4
  20. data/lib/opal/cli.rb +1 -0
  21. data/lib/opal/cli_options.rb +4 -0
  22. data/lib/opal/cli_runners/nodejs.rb +5 -1
  23. data/lib/opal/cli_runners/source-map-support-browser.js +8 -2
  24. data/lib/opal/cli_runners/source-map-support-node.js +3706 -0
  25. data/lib/opal/cli_runners/source-map-support.js +3 -1
  26. data/lib/opal/compiler.rb +2 -2
  27. data/lib/opal/nodes/args/arity_check.rb +1 -0
  28. data/lib/opal/nodes/args/parameters.rb +6 -0
  29. data/lib/opal/nodes/class.rb +1 -13
  30. data/lib/opal/nodes/literal.rb +14 -7
  31. data/lib/opal/nodes/module.rb +13 -9
  32. data/lib/opal/nodes/variables.rb +13 -4
  33. data/lib/opal/nodes/while.rb +54 -17
  34. data/lib/opal/parser.rb +1 -5
  35. data/lib/opal/parser/patch.rb +44 -0
  36. data/lib/opal/repl.rb +7 -0
  37. data/lib/opal/rewriter.rb +4 -0
  38. data/lib/opal/rewriters/arguments.rb +4 -1
  39. data/lib/opal/rewriters/forward_args.rb +54 -0
  40. data/lib/opal/rewriters/logical_operator_assignment.rb +5 -2
  41. data/lib/opal/rewriters/opal_engine_check.rb +5 -7
  42. data/lib/opal/rewriters/pattern_matching.rb +287 -0
  43. data/lib/opal/version.rb +1 -1
  44. data/opal/corelib/array.rb +42 -20
  45. data/opal/corelib/array/pack.rb +6 -1
  46. data/opal/corelib/complex.rb +2 -0
  47. data/opal/corelib/constants.rb +3 -3
  48. data/opal/corelib/hash.rb +45 -38
  49. data/opal/corelib/module.rb +2 -7
  50. data/opal/corelib/number.rb +2 -180
  51. data/opal/corelib/numeric.rb +156 -0
  52. data/opal/corelib/object_space.rb +102 -0
  53. data/opal/corelib/pattern_matching.rb +159 -0
  54. data/opal/corelib/random.rb +31 -66
  55. data/opal/corelib/random/formatter.rb +122 -0
  56. data/opal/corelib/range.rb +50 -19
  57. data/opal/corelib/runtime.js +82 -21
  58. data/opal/corelib/string.rb +86 -52
  59. data/opal/corelib/string/encoding.rb +140 -25
  60. data/opal/corelib/string/unpack.rb +26 -40
  61. data/opal/opal.rb +1 -0
  62. data/opal/opal/full.rb +2 -0
  63. data/package.json +1 -1
  64. data/spec/filters/bugs/array.rb +0 -23
  65. data/spec/filters/bugs/basicobject.rb +3 -0
  66. data/spec/filters/bugs/encoding.rb +0 -2
  67. data/spec/filters/bugs/exception.rb +1 -0
  68. data/spec/filters/bugs/float.rb +0 -2
  69. data/spec/filters/bugs/hash.rb +3 -13
  70. data/spec/filters/bugs/integer.rb +0 -2
  71. data/spec/filters/bugs/kernel.rb +16 -3
  72. data/spec/filters/bugs/language.rb +27 -90
  73. data/spec/filters/bugs/marshal.rb +1 -3
  74. data/spec/filters/bugs/module.rb +16 -1
  75. data/spec/filters/bugs/numeric.rb +4 -12
  76. data/spec/filters/bugs/objectspace.rb +67 -0
  77. data/spec/filters/bugs/pack_unpack.rb +0 -9
  78. data/spec/filters/bugs/pathname.rb +1 -0
  79. data/spec/filters/bugs/proc.rb +8 -0
  80. data/spec/filters/bugs/random.rb +3 -6
  81. data/spec/filters/bugs/range.rb +83 -113
  82. data/spec/filters/bugs/set.rb +2 -0
  83. data/spec/filters/bugs/string.rb +32 -70
  84. data/spec/filters/bugs/struct.rb +2 -10
  85. data/spec/filters/bugs/time.rb +8 -2
  86. data/spec/filters/unsupported/float.rb +3 -0
  87. data/spec/filters/unsupported/freeze.rb +1 -0
  88. data/spec/filters/unsupported/integer.rb +3 -0
  89. data/spec/filters/unsupported/refinements.rb +8 -0
  90. data/spec/filters/unsupported/string.rb +100 -95
  91. data/spec/filters/unsupported/time.rb +4 -0
  92. data/spec/lib/compiler_spec.rb +16 -0
  93. data/spec/lib/rewriters/forward_args_spec.rb +61 -0
  94. data/spec/lib/rewriters/logical_operator_assignment_spec.rb +1 -1
  95. data/spec/lib/rewriters/numblocks_spec.rb +44 -0
  96. data/spec/lib/rewriters/opal_engine_check_spec.rb +49 -4
  97. data/spec/opal/core/language/forward_args_spec.rb +53 -0
  98. data/spec/opal/core/language/infinite_range_spec.rb +13 -0
  99. data/spec/opal/core/language/memoization_spec.rb +16 -0
  100. data/spec/opal/core/language/pattern_matching_spec.rb +124 -0
  101. data/spec/opal/core/module_spec.rb +38 -2
  102. data/spec/opal/core/number/to_i_spec.rb +28 -0
  103. data/spec/opal/core/runtime/bridged_classes_spec.rb +16 -0
  104. data/spec/opal/core/runtime/constants_spec.rb +20 -1
  105. data/spec/opal/core/string/subclassing_spec.rb +16 -0
  106. data/spec/opal/core/string/unpack_spec.rb +22 -0
  107. data/spec/opal/core/string_spec.rb +4 -4
  108. data/spec/ruby_specs +4 -1
  109. data/stdlib/json.rb +3 -1
  110. data/stdlib/promise/v1.rb +1 -0
  111. data/stdlib/promise/v2.rb +386 -0
  112. data/stdlib/securerandom.rb +55 -35
  113. data/tasks/releasing.rake +1 -1
  114. data/tasks/testing.rake +6 -4
  115. data/test/nodejs/test_string.rb +25 -0
  116. data/test/opal/promisev2/test_always.rb +63 -0
  117. data/test/opal/promisev2/test_error.rb +16 -0
  118. data/test/opal/promisev2/test_rescue.rb +59 -0
  119. data/test/opal/promisev2/test_then.rb +90 -0
  120. data/test/opal/promisev2/test_trace.rb +52 -0
  121. data/test/opal/promisev2/test_value.rb +16 -0
  122. data/test/opal/promisev2/test_when.rb +35 -0
  123. data/vendored-minitest/minitest/assertions.rb +2 -0
  124. metadata +47 -8
  125. data/lib/opal/parser/with_c_lexer.rb +0 -15
@@ -15,8 +15,30 @@ module ModuleSubclassIncludedSpec
15
15
  M2 = Module2.new
16
16
  end
17
17
 
18
- describe 'Module#included' do
19
- it 'gets called in subclasses (regression for https://github.com/opal/opal/issues/1900)' do
18
+ module ModuleCVarSpec
19
+ module Mod0
20
+ def cvar0; @@cvar; end
21
+ def cvarx0; @@cvarx ||= 5; end
22
+ def cvary0; @@cvary; 0; end
23
+ def cvarz0; @@cvarz = @@cvarz || 5; end
24
+ end
25
+
26
+ module Mod1
27
+ include Mod0
28
+ @@cvar = 10
29
+ def cvar1; @@cvar; end
30
+ def cvar1=(new); @@cvar=new; end
31
+ end
32
+
33
+ module Mod2
34
+ include Mod1
35
+ def cvar2; @@cvar; end
36
+ def cvar2=(new); @@cvar=new; end
37
+ end
38
+ end
39
+
40
+ describe 'Module' do
41
+ it '#included gets called in subclasses (regression for https://github.com/opal/opal/issues/1900)' do
20
42
  $ScratchPad = []
21
43
  klass = Class.new
22
44
  klass.include ::ModuleSubclassIncludedSpec::M0
@@ -24,4 +46,18 @@ describe 'Module#included' do
24
46
  klass.include ::ModuleSubclassIncludedSpec::M2
25
47
  $ScratchPad.should == ['A included', 'B included']
26
48
  end
49
+
50
+ it "can access ancestor's @@cvar" do
51
+ klass = Class.new
52
+ klass.include ::ModuleCVarSpec::Mod2
53
+ klass.new.cvar1.should == 10
54
+ klass.new.cvar2.should == 10
55
+ klass.new.cvar2 = 50
56
+ klass.new.cvar1.should == 50
57
+ klass.new.cvar2.should == 50
58
+ klass.new.cvarx0.should == 5
59
+ klass.new.cvary0.should == 0
60
+ ->{ klass.new.cvarz0 }.should raise_error NameError
61
+ ->{ klass.new.cvar0 }.should raise_error NameError
62
+ end
27
63
  end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Number#to_i' do
4
+ it "should not change huge number" do
5
+ 1504642339053716000000.to_i.should == 1504642339053716000000
6
+ end
7
+
8
+ it "should not change negative huge number" do
9
+ -1504642339053716000000.to_i.should == -1504642339053716000000
10
+ end
11
+
12
+ it "equals Number#truncate(0) with huge number" do
13
+ 1504642339053716000000.to_i.should == 1504642339053716000000.truncate(0)
14
+ end
15
+
16
+ it "should not change Infinity" do
17
+ `Infinity`.to_i.should == `Infinity`
18
+ end
19
+
20
+ it "should not change -Infinity" do
21
+ `-Infinity`.to_i.should == `-Infinity`
22
+ end
23
+
24
+ it "should not change NaN" do
25
+ x = `NaN`.to_i
26
+ `Number.isNaN(x)`.should be_true
27
+ end
28
+ end
@@ -121,3 +121,19 @@ describe 'Bridged classes in different modules' do
121
121
  @bridged.new.some_bridged_method.should == [4, 5, 6]
122
122
  end
123
123
  end
124
+
125
+
126
+ describe "Invalid bridged classes" do
127
+ it "raises a TypeError when trying to extend with non-Class" do
128
+ error_msg = /superclass must be a Class/
129
+ -> { class TestClass < `""`; end }.should raise_error(TypeError, error_msg)
130
+ -> { class TestClass < `3`; end }.should raise_error(TypeError, error_msg)
131
+ -> { class TestClass < `true`; end }.should raise_error(TypeError, error_msg)
132
+ -> { class TestClass < `Math`; end }.should raise_error(TypeError, error_msg)
133
+ -> { class TestClass < `Object.create({})`; end }.should raise_error(TypeError, error_msg)
134
+ -> { class TestClass < `Object.create(null)`; end }.should raise_error(TypeError, error_msg)
135
+ -> { class TestClass < Module.new; end }.should raise_error(TypeError, error_msg)
136
+ -> { class TestClass < BasicObject.new; end }.should raise_error(TypeError, error_msg)
137
+ end
138
+ end
139
+
@@ -4,9 +4,15 @@ module RuntimeFixtures
4
4
 
5
5
  class A::B
6
6
  module C
7
-
8
7
  end
9
8
  end
9
+
10
+ module ModuleB
11
+ end
12
+
13
+ module ModuleA
14
+ include ModuleB
15
+ end
10
16
  end
11
17
 
12
18
  describe "Constants access via .$$ with dots (regression for #1418)" do
@@ -14,3 +20,16 @@ describe "Constants access via .$$ with dots (regression for #1418)" do
14
20
  `Opal.Object.$$.RuntimeFixtures.$$.A.$$.B.$$.C`.should == RuntimeFixtures::A::B::C
15
21
  end
16
22
  end
23
+
24
+ describe "Inclusion of modules" do
25
+ it "that have been included by other modules works" do
26
+ # here ClassC would have failed to be created due to a bug in Opal.append_features
27
+ module RuntimeFixtures
28
+ class ClassC
29
+ include ModuleA
30
+ include ModuleB
31
+ end
32
+ end
33
+ RuntimeFixtures::ClassC.new.class.should == RuntimeFixtures::ClassC
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ class MyStringSubclass < String
4
+ attr_reader :v
5
+ def initialize(s, v)
6
+ super(s)
7
+ @v = v
8
+ end
9
+ end
10
+
11
+ describe "String subclassing" do
12
+ it "should call initialize for subclasses" do
13
+ c = MyStringSubclass.new('s', 5)
14
+ [c, c.v].should == ['s', 5]
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'String#unpack' do
4
+ it 'correctly unpacks with U* strings with latin-1 characters' do
5
+ 'café'.unpack('U*').should == [99, 97, 102, 233]
6
+ [99, 97, 102, 233].pack('U*').unpack('U*').should == [99, 97, 102, 233]
7
+ end
8
+
9
+ it 'correctly unpacks with U* strings with latin-2 characters' do
10
+ 'pół'.unpack('U*').should == [112, 243, 322]
11
+ [112, 243, 322].pack('U*').unpack('U*').should == [112, 243, 322]
12
+ end
13
+
14
+ it 'correctly unpacks with c* strings with latin-2 characters' do
15
+ 'ść'.unpack('c*').should == [-59, -101, -60, -121]
16
+ end
17
+
18
+ it 'correctly unpacks with s* binary strings' do
19
+ "\xc8\x01".unpack('s*').should == [456]
20
+ [678].pack('s').unpack('s').should == [678]
21
+ end
22
+ end
@@ -19,10 +19,10 @@ describe 'Encoding' do
19
19
  Encoding.find('ascii').should == Encoding::ASCII
20
20
  Encoding.find('US-ASCII').should == Encoding::ASCII
21
21
  Encoding.find('us-ascii').should == Encoding::ASCII
22
- Encoding.find('ASCII-8BIT').should == Encoding::ASCII
23
- Encoding.find('ascii-8bit').should == Encoding::ASCII
24
- Encoding.find('BINARY').should == Encoding::ASCII
25
- Encoding.find('binary').should == Encoding::ASCII
22
+ Encoding.find('ASCII-8BIT').should == Encoding::BINARY
23
+ Encoding.find('ascii-8bit').should == Encoding::BINARY
24
+ Encoding.find('BINARY').should == Encoding::BINARY
25
+ Encoding.find('binary').should == Encoding::BINARY
26
26
  end
27
27
  end
28
28
  end
data/spec/ruby_specs CHANGED
@@ -106,6 +106,9 @@ ruby/core/marshal/minor_version_spec
106
106
  ruby/core/nil
107
107
  ruby/core/numeric
108
108
 
109
+ ruby/core/objectspace
110
+ ruby/core/objectspace/weakmap
111
+
109
112
  ruby/core/proc
110
113
 
111
114
  ruby/core/range
@@ -175,7 +178,7 @@ ruby/library/pathname
175
178
  !ruby/library/pathname/empty_spec
176
179
  !ruby/library/pathname/glob_spec
177
180
  ruby/library/pp
178
- ruby/library/securerandom/hex_spec
181
+ ruby/library/securerandom
179
182
  ruby/library/set
180
183
  ruby/library/singleton
181
184
  ruby/library/stringio/each_line_spec
data/stdlib/json.rb CHANGED
@@ -186,7 +186,9 @@ class Numeric
186
186
  end
187
187
 
188
188
  class String
189
- alias to_json inspect
189
+ def to_json
190
+ `JSON.stringify(self)`
191
+ end
190
192
  end
191
193
 
192
194
  class Time
@@ -0,0 +1 @@
1
+ require 'promise'
@@ -0,0 +1,386 @@
1
+ # {Promise} is used to help structure asynchronous code.
2
+ #
3
+ # It is available in the Opal standard library, and can be required in any Opal
4
+ # application:
5
+ #
6
+ # require 'promise/v2'
7
+ #
8
+ # ## Basic Usage
9
+ #
10
+ # Promises are created and returned as objects with the assumption that they
11
+ # will eventually be resolved or rejected, but never both. A {Promise} has
12
+ # a {#then} and {#fail} method (or one of their aliases) that can be used to
13
+ # register a block that gets called once resolved or rejected.
14
+ #
15
+ # promise = PromiseV2.new
16
+ #
17
+ # promise.then {
18
+ # puts "resolved!"
19
+ # }.fail {
20
+ # puts "rejected!"
21
+ # }
22
+ #
23
+ # # some time later
24
+ # promise.resolve
25
+ #
26
+ # # => "resolved!"
27
+ #
28
+ # It is important to remember that a promise can only be resolved or rejected
29
+ # once, so the block will only ever be called once (or not at all).
30
+ #
31
+ # ## Resolving Promises
32
+ #
33
+ # To resolve a promise, means to inform the {Promise} that it has succeeded
34
+ # or evaluated to a useful value. {#resolve} can be passed a value which is
35
+ # then passed into the block handler:
36
+ #
37
+ # def get_json
38
+ # promise = PromiseV2.new
39
+ #
40
+ # HTTP.get("some_url") do |req|
41
+ # promise.resolve req.json
42
+ # end
43
+ #
44
+ # promise
45
+ # end
46
+ #
47
+ # get_json.then do |json|
48
+ # puts "got some JSON from server"
49
+ # end
50
+ #
51
+ # ## Rejecting Promises
52
+ #
53
+ # Promises are also designed to handle error cases, or situations where an
54
+ # outcome is not as expected. Taking the previous example, we can also pass
55
+ # a value to a {#reject} call, which passes that object to the registered
56
+ # {#fail} handler:
57
+ #
58
+ # def get_json
59
+ # promise = PromiseV2.new
60
+ #
61
+ # HTTP.get("some_url") do |req|
62
+ # if req.ok?
63
+ # promise.resolve req.json
64
+ # else
65
+ # promise.reject req
66
+ # end
67
+ #
68
+ # promise
69
+ # end
70
+ #
71
+ # get_json.then {
72
+ # # ...
73
+ # }.fail { |req|
74
+ # puts "it went wrong: #{req.message}"
75
+ # }
76
+ #
77
+ # ## Chaining Promises
78
+ #
79
+ # Promises become even more useful when chained together. Each {#then} or
80
+ # {#fail} call returns a new {PromiseV2} which can be used to chain more and more
81
+ # handlers together.
82
+ #
83
+ # promise.then { wait_for_something }.then { do_something_else }
84
+ #
85
+ # Rejections are propagated through the entire chain, so a "catch all" handler
86
+ # can be attached at the end of the tail:
87
+ #
88
+ # promise.then { ... }.then { ... }.fail { ... }
89
+ #
90
+ # ## Composing Promises
91
+ #
92
+ # {PromiseV2.when} can be used to wait for more than one promise to resolve (or
93
+ # reject). Using the previous example, we could request two different json
94
+ # requests and wait for both to finish:
95
+ #
96
+ # PromiseV2.when(get_json, get_json2).then |first, second|
97
+ # puts "got two json payloads: #{first}, #{second}"
98
+ # end
99
+ #
100
+
101
+ warn 'PromiseV2 is a technology preview, which means it may change its behavior ' \
102
+ 'in the future until this warning is removed. If you are interested in this part, ' \
103
+ 'please make sure you track the async/await/promises tag on Opal issues: ' \
104
+ 'https://github.com/opal/opal/issues?q=label%3Aasync%2Fawait%2Fpromises'
105
+
106
+ class PromiseV2 < `Promise`
107
+ class << self
108
+ def allocate
109
+ ok, fail = nil, nil
110
+
111
+ prom = `new self.$$constructor(function(_ok, _fail) { #{ok} = _ok; #{fail} = _fail; })`
112
+ prom.instance_variable_set(:@type, :opal)
113
+ prom.instance_variable_set(:@resolve_proc, ok)
114
+ prom.instance_variable_set(:@reject_proc, fail)
115
+ prom
116
+ end
117
+
118
+ def when(*promises)
119
+ promises = Array(promises.length == 1 ? promises.first : promises)
120
+ `Promise.all(#{promises})`.tap do |prom|
121
+ prom.instance_variable_set(:@type, :when)
122
+ end
123
+ end
124
+
125
+ alias all when
126
+
127
+ def all_resolved(*promises)
128
+ promises = Array(promises.length == 1 ? promises.first : promises)
129
+ `Promise.allResolved(#{promises})`.tap do |prom|
130
+ prom.instance_variable_set(:@type, :all_resolved)
131
+ end
132
+ end
133
+
134
+ def any(*promises)
135
+ promises = Array(promises.length == 1 ? promises.first : promises)
136
+ `Promise.any(#{promises})`.tap do |prom|
137
+ prom.instance_variable_set(:@type, :any)
138
+ end
139
+ end
140
+
141
+ def race(*promises)
142
+ promises = Array(promises.length == 1 ? promises.first : promises)
143
+ `Promise.race(#{promises})`.tap do |prom|
144
+ prom.instance_variable_set(:@type, :race)
145
+ end
146
+ end
147
+
148
+ def resolve(value = nil)
149
+ `Promise.resolve(#{value})`.tap do |prom|
150
+ prom.instance_variable_set(:@type, :resolve)
151
+ prom.instance_variable_set(:@realized, :resolve)
152
+ prom.instance_variable_set(:@value, value)
153
+ end
154
+ end
155
+ alias value resolve
156
+
157
+ def reject(value = nil)
158
+ `Promise.reject(#{value})`.tap do |prom|
159
+ prom.instance_variable_set(:@type, :reject)
160
+ prom.instance_variable_set(:@realized, :reject)
161
+ prom.instance_variable_set(:@value, value)
162
+ end
163
+ end
164
+ alias error reject
165
+ end
166
+
167
+ attr_reader :prev, :next
168
+
169
+ # Is this promise native to JavaScript? This means, that methods like resolve
170
+ # or reject won't be available.
171
+ def native?
172
+ @type != :opal
173
+ end
174
+
175
+ # Raise an exception when a non-JS-native method is called on a JS-native promise
176
+ def nativity_check!
177
+ raise ArgumentError, 'this promise is native to JavaScript' if native?
178
+ end
179
+
180
+ # Raise an exception when a non-JS-native method is called on a JS-native promise
181
+ # but permits some typed promises
182
+ def light_nativity_check!
183
+ return if %i[reject resolve trace always fail then].include? @type
184
+ raise ArgumentError, 'this promise is native to JavaScript' if native?
185
+ end
186
+
187
+ # Allow only one chain to be present, as needed by the previous implementation.
188
+ # This isn't a strict check - it's always possible on the JS side to chain a
189
+ # given block.
190
+ def there_can_be_only_one!
191
+ raise ArgumentError, 'a promise has already been chained' if @next && @next.any?
192
+ end
193
+
194
+ def gen_tracing_proc(passing, &block)
195
+ proc do |i|
196
+ res = passing.call(i)
197
+ yield(res)
198
+ res
199
+ end
200
+ end
201
+
202
+ def resolve(value = nil)
203
+ nativity_check!
204
+ raise ArgumentError, 'this promise was already resolved' if @realized
205
+ @value = value
206
+ @realized = :resolve
207
+ @resolve_proc.call(value)
208
+ self
209
+ end
210
+ alias resolve! resolve
211
+
212
+ def reject(value = nil)
213
+ nativity_check!
214
+ raise ArgumentError, 'this promise was already resolved' if @realized
215
+ @value = value
216
+ @realized = :reject
217
+ @reject_proc.call(value)
218
+ self
219
+ end
220
+ alias reject! reject
221
+
222
+ def then(&block)
223
+ prom = nil
224
+ blk = gen_tracing_proc(block) do |val|
225
+ prom.instance_variable_set(:@realized, :resolve)
226
+ prom.instance_variable_set(:@value, val)
227
+ end
228
+ prom = `self.then(#{blk})`
229
+ prom.instance_variable_set(:@prev, self)
230
+ prom.instance_variable_set(:@type, :then)
231
+ (@next ||= []) << prom
232
+ prom
233
+ end
234
+
235
+ def then!(&block)
236
+ there_can_be_only_one!
237
+ self.then(&block)
238
+ end
239
+
240
+ alias do then
241
+ alias do! then!
242
+
243
+ def fail(&block)
244
+ prom = nil
245
+ blk = gen_tracing_proc(block) do |val|
246
+ prom.instance_variable_set(:@realized, :resolve)
247
+ prom.instance_variable_set(:@value, val)
248
+ end
249
+ prom = `self.catch(#{blk})`
250
+ prom.instance_variable_set(:@prev, self)
251
+ prom.instance_variable_set(:@type, :fail)
252
+ (@next ||= []) << prom
253
+ prom
254
+ end
255
+
256
+ def fail!(&block)
257
+ there_can_be_only_one!
258
+ fail(&block)
259
+ end
260
+
261
+ alias rescue fail
262
+ alias catch fail
263
+ alias rescue! fail!
264
+ alias catch! fail!
265
+
266
+ def always(&block)
267
+ prom = nil
268
+ blk = gen_tracing_proc(block) do |val|
269
+ prom.instance_variable_set(:@realized, :resolve)
270
+ prom.instance_variable_set(:@value, val)
271
+ end
272
+ prom = `self.finally(#{blk})`
273
+ prom.instance_variable_set(:@prev, self)
274
+ prom.instance_variable_set(:@type, :always)
275
+ (@next ||= []) << prom
276
+ prom
277
+ end
278
+
279
+ def always!(&block)
280
+ there_can_be_only_one!
281
+ always(&block)
282
+ end
283
+
284
+ alias finally always
285
+ alias ensure always
286
+ alias finally! always!
287
+ alias ensure! always!
288
+
289
+ def trace(depth = nil, &block)
290
+ prom = self.then do
291
+ values = []
292
+ prom = self
293
+ while prom && (!depth || depth > 0)
294
+ val = nil
295
+ begin
296
+ val = prom.value
297
+ rescue ArgumentError
298
+ val = :native
299
+ end
300
+ values.unshift(val)
301
+ depth -= 1 if depth
302
+ prom = prom.prev
303
+ end
304
+ yield(*values)
305
+ end
306
+
307
+ prom.instance_variable_set(:@type, :trace)
308
+ prom
309
+ end
310
+
311
+ def trace!(*args, &block)
312
+ there_can_be_only_one!
313
+ trace(*args, &block)
314
+ end
315
+
316
+ def resolved?
317
+ light_nativity_check!
318
+ @realized == :resolve
319
+ end
320
+
321
+ def rejected?
322
+ light_nativity_check!
323
+ @realized == :reject
324
+ end
325
+
326
+ def realized?
327
+ light_nativity_check!
328
+ !@realized.nil?
329
+ end
330
+
331
+ def value
332
+ if resolved?
333
+ if PromiseV2 === @value
334
+ @value.value
335
+ else
336
+ @value
337
+ end
338
+ end
339
+ end
340
+
341
+ def error
342
+ light_nativity_check!
343
+ @value if rejected?
344
+ end
345
+
346
+ def and(*promises)
347
+ promises = promises.map do |i|
348
+ if PromiseV2 === i
349
+ i
350
+ else
351
+ PromiseV2.value(i)
352
+ end
353
+ end
354
+ PromiseV2.when(self, *promises).then do |a, *b|
355
+ [*a, *b]
356
+ end
357
+ end
358
+
359
+ def initialize(&block)
360
+ yield self if block_given?
361
+ end
362
+
363
+ alias to_n itself
364
+
365
+ def inspect
366
+ result = "#<#{self.class}"
367
+
368
+ if @type
369
+ result += ":#{@type}" unless %i[opal resolve reject].include? @type
370
+ else
371
+ result += ':native'
372
+ end
373
+
374
+ result += ":#{@realized}" if @realized
375
+ result += "(#{object_id})"
376
+
377
+ if @next && @next.any?
378
+ result += " >> #{@next.inspect}"
379
+ end
380
+
381
+ result += ": #{@value.inspect}" if @value
382
+ result += '>'
383
+
384
+ result
385
+ end
386
+ end