opal 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (257) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +40 -9
  3. data/CHANGELOG.md +349 -0
  4. data/Gemfile +7 -8
  5. data/README.md +25 -3
  6. data/Rakefile +4 -2
  7. data/bin/opal +1 -1
  8. data/examples/rack/Gemfile +3 -0
  9. data/examples/rack/app/application.rb +13 -0
  10. data/examples/rack/app/user.rb +21 -0
  11. data/examples/rack/config.ru +7 -0
  12. data/examples/rack/index.html.erb +10 -0
  13. data/examples/sinatra/Gemfile +4 -0
  14. data/examples/sinatra/app/application.rb +7 -0
  15. data/examples/sinatra/config.ru +21 -0
  16. data/lib/mspec/opal/rake_task.rb +29 -8
  17. data/lib/mspec/opal/runner.rb +5 -4
  18. data/lib/opal.rb +1 -0
  19. data/lib/opal/builder.rb +0 -28
  20. data/lib/opal/cli.rb +0 -14
  21. data/lib/opal/compiler.rb +12 -11
  22. data/lib/opal/fragment.rb +8 -1
  23. data/lib/opal/nodes/array.rb +1 -1
  24. data/lib/opal/nodes/base.rb +4 -0
  25. data/lib/opal/nodes/call.rb +6 -2
  26. data/lib/opal/nodes/call_special.rb +1 -1
  27. data/lib/opal/nodes/class.rb +2 -2
  28. data/lib/opal/nodes/constants.rb +3 -1
  29. data/lib/opal/nodes/helpers.rb +23 -14
  30. data/lib/opal/nodes/if.rb +16 -9
  31. data/lib/opal/nodes/literal.rb +37 -5
  32. data/lib/opal/nodes/logic.rb +7 -1
  33. data/lib/opal/nodes/module.rb +2 -2
  34. data/lib/opal/nodes/scope.rb +13 -2
  35. data/lib/opal/nodes/top.rb +9 -0
  36. data/lib/opal/nodes/variables.rb +5 -2
  37. data/lib/opal/parser.rb +306 -71
  38. data/lib/opal/parser/grammar.rb +2667 -2775
  39. data/lib/opal/parser/grammar.y +177 -233
  40. data/lib/opal/parser/lexer.rb +511 -427
  41. data/lib/opal/parser/sexp.rb +15 -3
  42. data/lib/opal/source_map.rb +8 -4
  43. data/lib/opal/sprockets.rb +4 -0
  44. data/lib/opal/sprockets/cache_key_fix.rb +17 -0
  45. data/lib/opal/sprockets/environment.rb +21 -0
  46. data/lib/opal/sprockets/erb.rb +30 -0
  47. data/lib/opal/sprockets/processor.rb +127 -0
  48. data/lib/opal/sprockets/server.rb +166 -0
  49. data/lib/opal/util.rb +29 -0
  50. data/lib/opal/version.rb +1 -1
  51. data/opal.gemspec +1 -1
  52. data/opal/corelib/array.rb +106 -187
  53. data/opal/corelib/array/inheritance.rb +113 -0
  54. data/opal/corelib/basic_object.rb +6 -2
  55. data/opal/corelib/boolean.rb +4 -0
  56. data/opal/corelib/class.rb +2 -0
  57. data/opal/corelib/complex.rb +3 -0
  58. data/opal/corelib/enumerable.rb +75 -8
  59. data/opal/corelib/enumerator.rb +2 -0
  60. data/opal/corelib/error.rb +23 -23
  61. data/opal/corelib/hash.rb +5 -5
  62. data/opal/corelib/helpers.rb +51 -16
  63. data/opal/corelib/io.rb +7 -24
  64. data/opal/corelib/kernel.rb +23 -11
  65. data/opal/corelib/module.rb +44 -47
  66. data/opal/corelib/nil_class.rb +4 -0
  67. data/opal/corelib/numeric.rb +101 -15
  68. data/opal/corelib/range.rb +2 -0
  69. data/opal/corelib/rational.rb +3 -0
  70. data/opal/corelib/regexp.rb +36 -17
  71. data/opal/corelib/runtime.js +22 -7
  72. data/opal/corelib/string.rb +213 -110
  73. data/opal/corelib/string/inheritance.rb +78 -0
  74. data/opal/corelib/struct.rb +8 -0
  75. data/opal/corelib/time.rb +54 -42
  76. data/opal/corelib/variables.rb +24 -0
  77. data/opal/opal.rb +5 -27
  78. data/spec/cli/compiler_spec.rb +136 -0
  79. data/spec/cli/dependency_resolver_spec.rb +40 -0
  80. data/spec/cli/lexer_spec.rb +110 -0
  81. data/spec/cli/parser/alias_spec.rb +26 -0
  82. data/spec/cli/parser/and_spec.rb +13 -0
  83. data/spec/cli/parser/attrasgn_spec.rb +28 -0
  84. data/spec/cli/parser/begin_spec.rb +42 -0
  85. data/spec/cli/parser/block_spec.rb +12 -0
  86. data/spec/cli/parser/break_spec.rb +17 -0
  87. data/spec/cli/parser/call_spec.rb +139 -0
  88. data/spec/cli/parser/class_spec.rb +35 -0
  89. data/spec/cli/parser/comments_spec.rb +11 -0
  90. data/spec/cli/parser/def_spec.rb +61 -0
  91. data/spec/cli/parser/if_spec.rb +26 -0
  92. data/spec/cli/parser/iter_spec.rb +59 -0
  93. data/spec/cli/parser/lambda_spec.rb +64 -0
  94. data/spec/cli/parser/literal_spec.rb +113 -0
  95. data/spec/cli/parser/masgn_spec.rb +37 -0
  96. data/spec/cli/parser/module_spec.rb +27 -0
  97. data/spec/cli/parser/not_spec.rb +27 -0
  98. data/spec/cli/parser/op_asgn1_spec.rb +23 -0
  99. data/spec/cli/parser/op_asgn2_spec.rb +23 -0
  100. data/spec/cli/parser/or_spec.rb +13 -0
  101. data/spec/cli/parser/return_spec.rb +17 -0
  102. data/spec/cli/parser/sclass_spec.rb +21 -0
  103. data/spec/cli/parser/string_spec.rb +269 -0
  104. data/spec/cli/parser/super_spec.rb +20 -0
  105. data/spec/cli/parser/undef_spec.rb +15 -0
  106. data/spec/cli/parser/unless_spec.rb +13 -0
  107. data/spec/cli/parser/variables_spec.rb +92 -0
  108. data/spec/cli/parser/while_spec.rb +15 -0
  109. data/spec/cli/parser/yield_spec.rb +20 -0
  110. data/spec/cli/spec_helper.rb +31 -11
  111. data/spec/opal/core/array/set_range_to_array_spec.rb +7 -0
  112. data/spec/opal/core/date_spec.rb +122 -0
  113. data/spec/opal/core/language/predefined_spec.rb +1 -1
  114. data/spec/opal/core/runtime/operator_call_spec.rb +13 -0
  115. data/spec/opal/core/runtime/truthy_spec.rb +23 -0
  116. data/spec/opal/filters/bugs/array.rb +96 -87
  117. data/spec/opal/filters/bugs/basic_object.rb +9 -0
  118. data/spec/opal/filters/bugs/class.rb +16 -0
  119. data/spec/opal/filters/bugs/enumerable.rb +54 -0
  120. data/spec/opal/filters/bugs/language.rb +37 -3
  121. data/spec/opal/filters/bugs/math.rb +93 -0
  122. data/spec/opal/filters/bugs/nil.rb +7 -0
  123. data/spec/opal/filters/bugs/numeric.rb +19 -0
  124. data/spec/opal/filters/bugs/opal.rb +12 -0
  125. data/spec/opal/filters/bugs/regexp.rb +0 -2
  126. data/spec/opal/filters/bugs/string.rb +317 -19
  127. data/spec/opal/filters/bugs/struct.rb +29 -0
  128. data/spec/opal/filters/bugs/time.rb +130 -9
  129. data/spec/opal/filters/unsupported/encoding.rb +52 -4
  130. data/spec/opal/filters/unsupported/enumerator.rb +0 -3
  131. data/spec/opal/filters/unsupported/integer_size.rb +7 -0
  132. data/spec/opal/filters/unsupported/method_added.rb +10 -0
  133. data/spec/opal/filters/unsupported/mutable_strings.rb +299 -1
  134. data/spec/opal/filters/unsupported/private_constants.rb +30 -0
  135. data/spec/opal/filters/unsupported/private_methods.rb +16 -0
  136. data/spec/opal/filters/unsupported/random.rb +4 -0
  137. data/spec/opal/filters/unsupported/tainted.rb +53 -0
  138. data/spec/opal/filters/unsupported/trusted.rb +5 -0
  139. data/spec/opal/rubyspecs +167 -234
  140. data/spec/opal/spec_helper.rb +3 -0
  141. data/spec/opal/stdlib/promise/error_spec.rb +15 -0
  142. data/spec/opal/stdlib/promise/rescue_spec.rb +35 -0
  143. data/spec/opal/stdlib/promise/then_spec.rb +54 -0
  144. data/spec/opal/stdlib/promise/trace_spec.rb +35 -0
  145. data/spec/opal/stdlib/promise/value_spec.rb +15 -0
  146. data/spec/opal/stdlib/promise/when_spec.rb +34 -0
  147. data/stdlib/base64.rb +152 -0
  148. data/stdlib/date.rb +82 -49
  149. data/{opal/corelib → stdlib}/encoding.rb +3 -1
  150. data/stdlib/erb.rb +0 -1
  151. data/stdlib/json.rb +10 -26
  152. data/stdlib/math.rb +370 -0
  153. data/stdlib/native.rb +40 -33
  154. data/stdlib/opal-parser.rb +7 -4
  155. data/stdlib/promise.rb +292 -0
  156. data/stdlib/strscan.rb +1 -1
  157. data/stdlib/template.rb +1 -3
  158. data/stdlib/time.rb +9 -0
  159. metadata +143 -204
  160. data/doc/compiler.md +0 -42
  161. data/doc/compiler_options.md +0 -5
  162. data/doc/examples/node_http_server.rb +0 -49
  163. data/doc/external_libraries.md +0 -9
  164. data/doc/generated_javascript.md +0 -272
  165. data/doc/home.md +0 -17
  166. data/doc/method_missing.md +0 -58
  167. data/doc/static_applications.md +0 -60
  168. data/doc/using_ruby_from_javascript.md +0 -18
  169. data/doc/using_sprockets.md +0 -65
  170. data/spec/opal/core/numeric/abs_spec.rb +0 -12
  171. data/spec/opal/core/numeric/downto_spec.rb +0 -19
  172. data/spec/opal/core/numeric/equal_value_spec.rb +0 -9
  173. data/spec/opal/core/numeric/even_spec.rb +0 -21
  174. data/spec/opal/core/numeric/magnitude_spec.rb +0 -12
  175. data/spec/opal/core/numeric/odd_spec.rb +0 -21
  176. data/spec/opal/core/string/chop_spec.rb +0 -10
  177. data/spec/opal/core/string/chr_spec.rb +0 -13
  178. data/spec/opal/core/string/clone_spec.rb +0 -8
  179. data/spec/opal/core/string/comparison_spec.rb +0 -13
  180. data/spec/opal/core/string/dup_spec.rb +0 -8
  181. data/spec/opal/core/string/element_reference_spec.rb +0 -96
  182. data/spec/opal/core/string/fixtures/classes.rb +0 -49
  183. data/spec/opal/core/string/format_spec.rb +0 -9
  184. data/spec/opal/core/string/freeze_spec.rb +0 -15
  185. data/spec/opal/core/string/gsub_spec.rb +0 -31
  186. data/spec/opal/core/string/lines_spec.rb +0 -9
  187. data/spec/opal/core/string/ljust_spec.rb +0 -32
  188. data/spec/opal/core/string/lstrip_spec.rb +0 -7
  189. data/spec/opal/core/string/match_spec.rb +0 -49
  190. data/spec/opal/core/string/next_spec.rb +0 -10
  191. data/spec/opal/core/string/ord_spec.rb +0 -9
  192. data/spec/opal/core/string/partition_spec.rb +0 -10
  193. data/spec/opal/core/string/rindex_spec.rb +0 -50
  194. data/spec/opal/core/string/rjust_spec.rb +0 -32
  195. data/spec/opal/core/string/rstrip_spec.rb +0 -7
  196. data/spec/opal/core/string/scan_spec.rb +0 -66
  197. data/spec/opal/core/string/slice_spec.rb +0 -74
  198. data/spec/opal/core/string/split_spec.rb +0 -5
  199. data/spec/opal/core/string/strip_spec.rb +0 -6
  200. data/spec/opal/core/string/sub_spec.rb +0 -38
  201. data/spec/opal/core/string/succ_spec.rb +0 -10
  202. data/spec/opal/core/string/sum_spec.rb +0 -5
  203. data/spec/opal/core/string/to_f_spec.rb +0 -14
  204. data/spec/opal/core/string/to_i_spec.rb +0 -25
  205. data/spec/opal/core/string/tr_s_spec.rb +0 -31
  206. data/spec/opal/core/string/tr_spec.rb +0 -31
  207. data/spec/opal/filters/bugs/parser.rb +0 -10
  208. data/spec/opal/filters/unsupported/immutable_strings.rb +0 -24
  209. data/spec/opal/filters/unsupported/string_subclasses.rb +0 -8
  210. data/spec/opal/parser/alias_spec.rb +0 -26
  211. data/spec/opal/parser/and_spec.rb +0 -13
  212. data/spec/opal/parser/array_spec.rb +0 -22
  213. data/spec/opal/parser/attrasgn_spec.rb +0 -28
  214. data/spec/opal/parser/begin_spec.rb +0 -42
  215. data/spec/opal/parser/block_spec.rb +0 -12
  216. data/spec/opal/parser/break_spec.rb +0 -17
  217. data/spec/opal/parser/call_spec.rb +0 -131
  218. data/spec/opal/parser/class_spec.rb +0 -35
  219. data/spec/opal/parser/const_spec.rb +0 -13
  220. data/spec/opal/parser/cvar_spec.rb +0 -11
  221. data/spec/opal/parser/def_spec.rb +0 -61
  222. data/spec/opal/parser/false_spec.rb +0 -17
  223. data/spec/opal/parser/file_spec.rb +0 -7
  224. data/spec/opal/parser/gvar_spec.rb +0 -13
  225. data/spec/opal/parser/hash_spec.rb +0 -17
  226. data/spec/opal/parser/heredoc_spec.rb +0 -30
  227. data/spec/opal/parser/iasgn_spec.rb +0 -9
  228. data/spec/opal/parser/if_spec.rb +0 -26
  229. data/spec/opal/parser/int_spec.rb +0 -13
  230. data/spec/opal/parser/iter_spec.rb +0 -59
  231. data/spec/opal/parser/ivar_spec.rb +0 -9
  232. data/spec/opal/parser/lambda_spec.rb +0 -64
  233. data/spec/opal/parser/lasgn_spec.rb +0 -8
  234. data/spec/opal/parser/line_spec.rb +0 -8
  235. data/spec/opal/parser/lvar_spec.rb +0 -38
  236. data/spec/opal/parser/masgn_spec.rb +0 -37
  237. data/spec/opal/parser/module_spec.rb +0 -27
  238. data/spec/opal/parser/nil_spec.rb +0 -17
  239. data/spec/opal/parser/not_spec.rb +0 -27
  240. data/spec/opal/parser/nth_ref_spec.rb +0 -13
  241. data/spec/opal/parser/op_asgn1_spec.rb +0 -23
  242. data/spec/opal/parser/op_asgn2_spec.rb +0 -23
  243. data/spec/opal/parser/or_spec.rb +0 -13
  244. data/spec/opal/parser/parse_spec.rb +0 -66
  245. data/spec/opal/parser/regexp_spec.rb +0 -16
  246. data/spec/opal/parser/return_spec.rb +0 -17
  247. data/spec/opal/parser/sclass_spec.rb +0 -21
  248. data/spec/opal/parser/self_spec.rb +0 -17
  249. data/spec/opal/parser/str_spec.rb +0 -107
  250. data/spec/opal/parser/string_spec.rb +0 -8
  251. data/spec/opal/parser/super_spec.rb +0 -20
  252. data/spec/opal/parser/true_spec.rb +0 -17
  253. data/spec/opal/parser/undef_spec.rb +0 -15
  254. data/spec/opal/parser/unless_spec.rb +0 -13
  255. data/spec/opal/parser/while_spec.rb +0 -15
  256. data/spec/opal/parser/xstr_spec.rb +0 -116
  257. data/spec/opal/parser/yield_spec.rb +0 -20
@@ -2,7 +2,7 @@ module Native
2
2
  def self.is_a?(object, klass)
3
3
  %x{
4
4
  try {
5
- return #{object} instanceof #{Native.try_convert(klass)};
5
+ return #{object} instanceof #{try_convert(klass)};
6
6
  }
7
7
  catch (e) {
8
8
  return false;
@@ -33,7 +33,7 @@ module Native
33
33
  return #{value.to_n};
34
34
  }
35
35
  else {
36
- #{raise ArgumentError, "the passed value isn't a native"};
36
+ #{raise ArgumentError, "#{value.inspect} isn't native"};
37
37
  }
38
38
  }
39
39
  end
@@ -42,31 +42,24 @@ module Native
42
42
  %x{
43
43
  var prop = #{obj}[#{key}];
44
44
 
45
- if (prop == null) {
46
- return nil;
47
- }
48
- else if (prop instanceof Function) {
49
- if (block !== nil) {
50
- args.push(block);
51
- }
45
+ if (prop instanceof Function) {
46
+ var converted = new Array(args.length);
52
47
 
53
- args = #{args.map {|value|
54
- native = try_convert(value)
48
+ for (var i = 0, length = args.length; i < length; i++) {
49
+ var item = args[i],
50
+ conv = #{try_convert(`item`)};
55
51
 
56
- if nil === native
57
- value
58
- else
59
- native
60
- end
61
- }};
52
+ converted[i] = conv === nil ? item : conv;
53
+ }
62
54
 
63
- return #{Native(`prop.apply(#{obj}, #{args})`)};
64
- }
65
- else if (#{native?(`prop`)}) {
66
- return #{Native(`prop`)};
55
+ if (block !== nil) {
56
+ converted.push(block);
57
+ }
58
+
59
+ return #{Native(`prop.apply(#{obj}, converted)`)};
67
60
  }
68
61
  else {
69
- return prop;
62
+ return #{Native(`prop`)};
70
63
  }
71
64
  }
72
65
  end
@@ -101,7 +94,7 @@ module Native
101
94
 
102
95
  def initialize(native)
103
96
  unless Kernel.native?(native)
104
- Kernel.raise ArgumentError, "the passed value isn't native"
97
+ Kernel.raise ArgumentError, "#{native.inspect} isn't native"
105
98
  end
106
99
 
107
100
  @native = native
@@ -156,7 +149,7 @@ class Native::Object < BasicObject
156
149
  end
157
150
 
158
151
  def has_key?(name)
159
- `#@native.hasOwnProperty(#{name})`
152
+ `$opal.hasOwnProperty.call(#@native, #{name})`
160
153
  end
161
154
 
162
155
  alias key? has_key?
@@ -200,6 +193,26 @@ class Native::Object < BasicObject
200
193
  end
201
194
  end
202
195
 
196
+ def merge!(other)
197
+ %x{
198
+ var other = #{Native.convert(other)};
199
+
200
+ for (var prop in other) {
201
+ #@native[prop] = other[prop];
202
+ }
203
+ }
204
+
205
+ self
206
+ end
207
+
208
+ def respond_to?(name, include_all = false)
209
+ Kernel.instance_method(:respond_to?).bind(self).call(name, include_all)
210
+ end
211
+
212
+ def respond_to_missing?(name)
213
+ `$opal.hasOwnProperty.call(#@native, #{name})`
214
+ end
215
+
203
216
  def method_missing(mid, *args, &block)
204
217
  %x{
205
218
  if (mid.charAt(mid.length - 1) === '=') {
@@ -216,13 +229,13 @@ class Native::Object < BasicObject
216
229
  end
217
230
 
218
231
  def is_a?(klass)
219
- klass == Native
232
+ `$opal.is_a(self, klass)`
220
233
  end
221
234
 
222
235
  alias kind_of? is_a?
223
236
 
224
237
  def instance_of?(klass)
225
- klass == Native
238
+ `self._klass === klass`
226
239
  end
227
240
 
228
241
  def class
@@ -233,10 +246,6 @@ class Native::Object < BasicObject
233
246
  Native::Array.new(@native, options, &block).to_a
234
247
  end
235
248
 
236
- def to_ary(options = {}, &block)
237
- Native::Array.new(@native, options, &block)
238
- end
239
-
240
249
  def inspect
241
250
  "#<Native:#{`String(#@native)`}>"
242
251
  end
@@ -322,9 +331,7 @@ class Native::Array
322
331
  `#@native[#@length]`
323
332
  end
324
333
 
325
- def to_ary
326
- self
327
- end
334
+ alias to_ary to_a
328
335
 
329
336
  def inspect
330
337
  to_a.inspect
@@ -11,12 +11,15 @@ module Kernel
11
11
  end
12
12
 
13
13
  %x{
14
- Opal.compile = function(str) {
15
- return Opal.Opal.$compile(str);
14
+ Opal.compile = function(str, options) {
15
+ if (options) {
16
+ options = Opal.hash(options);
17
+ }
18
+ return Opal.Opal.$compile(str, options);
16
19
  };
17
20
 
18
- Opal.eval = function(str) {
19
- return eval(Opal.compile(str));
21
+ Opal.eval = function(str, options) {
22
+ return eval(Opal.compile(str, options));
20
23
  };
21
24
 
22
25
  function run_ruby_scripts() {
@@ -0,0 +1,292 @@
1
+ class Promise
2
+ def self.value(value)
3
+ new.resolve(value)
4
+ end
5
+
6
+ def self.error(value)
7
+ new.reject(value)
8
+ end
9
+
10
+ def self.when(*promises)
11
+ When.new(promises)
12
+ end
13
+
14
+ attr_reader :value, :error, :prev, :next
15
+
16
+ def initialize(success = nil, failure = nil)
17
+ @success = success
18
+ @failure = failure
19
+
20
+ @realized = nil
21
+ @exception = false
22
+ @value = nil
23
+ @error = nil
24
+ @delayed = nil
25
+
26
+ @prev = nil
27
+ @next = nil
28
+ end
29
+
30
+ def act?
31
+ @success != nil
32
+ end
33
+
34
+ def exception?
35
+ @exception
36
+ end
37
+
38
+ def realized?
39
+ @realized != nil
40
+ end
41
+
42
+ def resolved?
43
+ @realized == :resolve
44
+ end
45
+
46
+ def rejected?
47
+ @realized == :reject
48
+ end
49
+
50
+ def ^(promise)
51
+ promise << self
52
+ self >> promise
53
+
54
+ promise
55
+ end
56
+
57
+ def <<(promise)
58
+ @prev = promise
59
+
60
+ self
61
+ end
62
+
63
+ def >>(promise)
64
+ @next = promise
65
+
66
+ if exception?
67
+ promise.reject(@delayed)
68
+ elsif resolved?
69
+ promise.resolve(@delayed || value)
70
+ elsif rejected? && (!@failure || Promise === (@delayed || @error))
71
+ promise.reject(@delayed || error)
72
+ end
73
+
74
+ self
75
+ end
76
+
77
+ def resolve(value)
78
+ if realized?
79
+ raise ArgumentError, 'the promise has already been realized'
80
+ end
81
+
82
+ if Promise === value
83
+ value << @prev
84
+
85
+ return value ^ self
86
+ end
87
+
88
+ @realized = :resolve
89
+ @value = value
90
+
91
+ begin
92
+ if @success
93
+ value = @success.call(value)
94
+ end
95
+
96
+ resolve!(value)
97
+ rescue Exception => e
98
+ exception!(e)
99
+ end
100
+
101
+ self
102
+ end
103
+
104
+ def resolve!(value)
105
+ if @next
106
+ @next.resolve(value)
107
+ else
108
+ @delayed = value
109
+ end
110
+ end
111
+
112
+ def reject(value)
113
+ if realized?
114
+ raise ArgumentError, 'the promise has already been realized'
115
+ end
116
+
117
+ if Promise === value
118
+ value << @prev
119
+
120
+ return value ^ self
121
+ end
122
+
123
+ @realized = :reject
124
+ @error = value
125
+
126
+ begin
127
+ if @failure
128
+ value = @failure.call(value)
129
+
130
+ if Promise === value
131
+ reject!(value)
132
+ end
133
+ else
134
+ reject!(value)
135
+ end
136
+ rescue Exception => e
137
+ exception!(e)
138
+ end
139
+
140
+ self
141
+ end
142
+
143
+ def reject!(value)
144
+ if @next
145
+ @next.reject(value)
146
+ else
147
+ @delayed = value
148
+ end
149
+ end
150
+
151
+ def exception!(error)
152
+ @exception = true
153
+
154
+ reject!(error)
155
+ end
156
+
157
+ def then(&block)
158
+ self ^ Promise.new(block)
159
+ end
160
+
161
+ alias do then
162
+
163
+ def fail(&block)
164
+ self ^ Promise.new(nil, block)
165
+ end
166
+
167
+ alias rescue fail
168
+ alias catch fail
169
+
170
+ def always(&block)
171
+ self ^ Promise.new(block, block)
172
+ end
173
+
174
+ alias finally always
175
+ alias ensure always
176
+
177
+ def trace(&block)
178
+ self ^ Trace.new(block)
179
+ end
180
+
181
+ def inspect
182
+ result = "#<#{self.class}(#{object_id})"
183
+
184
+ if @next
185
+ result += " >> #{@next.inspect}"
186
+ end
187
+
188
+ if realized?
189
+ result += ": #{(@value || @error).inspect}>"
190
+ else
191
+ result += ">"
192
+ end
193
+
194
+ result
195
+ end
196
+
197
+ class Trace < self
198
+ def self.it(promise)
199
+ unless promise.realized?
200
+ raise ArgumentError, "the promise hasn't been realized"
201
+ end
202
+
203
+ current = promise.act? ? [promise.value] : []
204
+
205
+ if prev = promise.prev
206
+ current.concat(it(prev))
207
+ else
208
+ current
209
+ end
210
+ end
211
+
212
+ def initialize(block)
213
+ super -> {
214
+ block.call(*Trace.it(self).reverse)
215
+ }
216
+ end
217
+ end
218
+
219
+ class When < self
220
+ def initialize(promises = [])
221
+ super()
222
+
223
+ @wait = []
224
+
225
+ promises.each {|promise|
226
+ wait promise
227
+ }
228
+ end
229
+
230
+ def each(&block)
231
+ raise ArgumentError, 'no block given' unless block
232
+
233
+ self.then {|values|
234
+ values.each(&block)
235
+ }
236
+ end
237
+
238
+ def collect(&block)
239
+ raise ArgumentError, 'no block given' unless block
240
+
241
+ self.then {|values|
242
+ When.new(values.map(&block))
243
+ }
244
+ end
245
+
246
+ def inject(*args, &block)
247
+ self.then {|values|
248
+ values.reduce(*args, &block)
249
+ }
250
+ end
251
+
252
+ alias map collect
253
+
254
+ alias reduce inject
255
+
256
+ def wait(promise)
257
+ unless Promise === promise
258
+ promise = Promise.value(promise)
259
+ end
260
+
261
+ if promise.act?
262
+ promise = promise.then
263
+ end
264
+
265
+ @wait << promise
266
+
267
+ promise.always {
268
+ try if @next
269
+ }
270
+
271
+ self
272
+ end
273
+
274
+ alias and wait
275
+
276
+ def >>(*)
277
+ super.tap {
278
+ try
279
+ }
280
+ end
281
+
282
+ def try
283
+ if @wait.all?(&:realized?)
284
+ if promise = @wait.find(&:rejected?)
285
+ reject(promise.error)
286
+ else
287
+ resolve(@wait.map(&:value))
288
+ end
289
+ end
290
+ end
291
+ end
292
+ end