opal 0.5.0 → 0.5.2

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -2
  3. data/README.md +1 -1
  4. data/Rakefile +11 -8
  5. data/lib/opal.rb +1 -1
  6. data/lib/opal/version.rb +1 -1
  7. data/opal.gemspec +1 -1
  8. data/{corelib → opal/core}/array.rb +47 -40
  9. data/{corelib → opal/core}/basic_object.rb +4 -0
  10. data/{corelib → opal/core}/boolean.rb +2 -6
  11. data/{corelib → opal/core}/class.rb +0 -0
  12. data/{corelib → opal/core}/comparable.rb +0 -0
  13. data/{corelib → opal/core}/encoding.rb +0 -0
  14. data/{corelib → opal/core}/enumerable.rb +160 -38
  15. data/opal/core/enumerator.rb +416 -0
  16. data/{corelib → opal/core}/error.rb +0 -0
  17. data/{corelib → opal/core}/hash.rb +38 -48
  18. data/{corelib → opal/core}/io.rb +13 -9
  19. data/{corelib → opal/core}/kernel.rb +75 -49
  20. data/{corelib → opal/core}/main.rb +0 -0
  21. data/{corelib → opal/core}/match_data.rb +0 -4
  22. data/{corelib → opal/core}/method.rb +0 -0
  23. data/{corelib → opal/core}/module.rb +24 -3
  24. data/{corelib → opal/core}/nil_class.rb +0 -4
  25. data/{corelib → opal/core}/numeric.rb +3 -4
  26. data/{corelib → opal/core}/proc.rb +0 -4
  27. data/{corelib → opal/core}/range.rb +0 -0
  28. data/{corelib → opal/core}/regexp.rb +0 -4
  29. data/{corelib → opal/core}/runtime.js +0 -0
  30. data/{corelib → opal/core}/string.rb +4 -6
  31. data/{corelib → opal/core}/struct.rb +3 -21
  32. data/{corelib → opal/core}/time.rb +0 -4
  33. data/opal/opal.rb +121 -0
  34. data/spec/corelib/array/select_spec.rb +14 -0
  35. data/spec/filters/20.rb +4 -0
  36. data/spec/filters/bugs/enumerable.rb +1 -48
  37. data/spec/filters/unsupported/enumerator.rb +13 -0
  38. data/spec/opal/compiler/irb_spec.rb +1 -0
  39. data/spec/rubyspecs +1 -0
  40. data/spec/{corelib → stdlib}/native/alias_native_spec.rb +6 -4
  41. data/spec/{corelib → stdlib}/native/each_spec.rb +3 -1
  42. data/spec/{corelib → stdlib}/native/element_reference_spec.rb +3 -1
  43. data/spec/stdlib/native/ext_spec.rb +19 -0
  44. data/spec/{corelib → stdlib}/native/initialize_spec.rb +4 -4
  45. data/spec/{corelib → stdlib}/native/method_missing_spec.rb +13 -1
  46. data/spec/{corelib → stdlib}/native/new_spec.rb +3 -1
  47. data/stdlib/enumerator.rb +1 -0
  48. data/stdlib/json.rb +1 -1
  49. data/stdlib/native.rb +483 -0
  50. metadata +52 -47
  51. data/corelib/enumerator.rb +0 -55
  52. data/corelib/native.rb +0 -270
  53. data/corelib/opal.rb +0 -88
  54. data/spec/corelib/native/ext_spec.rb +0 -5
  55. data/spec/filters/bugs/enumerator.rb +0 -6
@@ -0,0 +1,416 @@
1
+ class Enumerator
2
+ include Enumerable
3
+
4
+ def self.for(object, method = :each, *args, &block)
5
+ %x{
6
+ var obj = #{allocate};
7
+
8
+ obj.object = object;
9
+ obj.size = block;
10
+ obj.method = method;
11
+ obj.args = args;
12
+
13
+ return obj;
14
+ }
15
+
16
+ end
17
+
18
+ def initialize(*, &block)
19
+ if block
20
+ @object = Generator.new(&block)
21
+ @method = :each
22
+ @args = []
23
+ @size = `arguments[0] || nil`
24
+
25
+ if @size
26
+ @size = Opal.coerce_to @size, Integer, :to_int
27
+ end
28
+ else
29
+ @object = `arguments[0]`
30
+ @method = `arguments[1] || "each"`
31
+ @args = `$slice.call(arguments, 2)`
32
+ @size = nil
33
+ end
34
+ end
35
+
36
+ def each(&block)
37
+ return self unless block
38
+
39
+ @object.__send__(@method, *@args, &block)
40
+ end
41
+
42
+ def size
43
+ Proc === @size ? @size.call(*@args) : @size
44
+ end
45
+
46
+ def with_index(offset = 0, &block)
47
+ if offset
48
+ offset = Opal.coerce_to offset, Integer, :to_int
49
+ else
50
+ offset = 0
51
+ end
52
+
53
+ return enum_for :with_index, offset unless block
54
+
55
+ %x{
56
+ var result
57
+
58
+ self.$each._p = function() {
59
+ var param = #{Opal.destructure(`arguments`)},
60
+ value = block(param, index);
61
+
62
+ if (value === $breaker) {
63
+ result = $breaker.$v;
64
+ return $breaker;
65
+ }
66
+
67
+ index++;
68
+ }
69
+
70
+ self.$each();
71
+
72
+ if (result !== undefined) {
73
+ return result;
74
+ }
75
+ }
76
+ end
77
+
78
+ alias with_object each_with_object
79
+
80
+ def inspect
81
+ result = "#<#{self.class.name}: #{@object.inspect}:#{@method}"
82
+
83
+ unless @args.empty?
84
+ result += "(#{@args.inspect[Range.new(1, -2)]})"
85
+ end
86
+
87
+ result + ">"
88
+ end
89
+
90
+ class Generator
91
+ include Enumerable
92
+
93
+ def initialize(&block)
94
+ raise LocalJumpError, 'no block given' unless block
95
+
96
+ @block = block
97
+ end
98
+
99
+ def each(*args, &block)
100
+ yielder = Yielder.new(&block)
101
+
102
+ %x{
103
+ try {
104
+ args.unshift(#{yielder});
105
+
106
+ if ($opal.$yieldX(#@block, args) === $breaker) {
107
+ return $breaker.$v;
108
+ }
109
+ }
110
+ catch (e) {
111
+ if (e === $breaker) {
112
+ return $breaker.$v;
113
+ }
114
+ else {
115
+ throw e;
116
+ }
117
+ }
118
+ }
119
+
120
+ self
121
+ end
122
+ end
123
+
124
+ class Yielder
125
+ def initialize(&block)
126
+ @block = block
127
+ end
128
+
129
+ def yield(*values)
130
+ %x{
131
+ var value = $opal.$yieldX(#@block, values);
132
+
133
+ if (value === $breaker) {
134
+ throw $breaker;
135
+ }
136
+
137
+ return value;
138
+ }
139
+ end
140
+
141
+ def <<(*values)
142
+ self.yield(*values)
143
+
144
+ self
145
+ end
146
+ end
147
+
148
+ class Lazy < self
149
+ class StopLazyError < Exception; end
150
+
151
+ def initialize(object, size = nil, &block)
152
+ unless block_given?
153
+ raise ArgumentError, 'tried to call lazy new without a block'
154
+ end
155
+
156
+ @enumerator = object
157
+
158
+ super size do |yielder, *each_args|
159
+ begin
160
+ object.each(*each_args) {|*args|
161
+ %x{
162
+ args.unshift(#{yielder});
163
+
164
+ if ($opal.$yieldX(block, args) === $breaker) {
165
+ return $breaker;
166
+ }
167
+ }
168
+ }
169
+ rescue Exception
170
+ nil
171
+ end
172
+ end
173
+ end
174
+
175
+ alias force to_a
176
+
177
+ def lazy
178
+ self
179
+ end
180
+
181
+ def collect(&block)
182
+ unless block
183
+ raise ArgumentError, 'tried to call lazy map without a block'
184
+ end
185
+
186
+ Lazy.new(self, enumerator_size) {|enum, *args|
187
+ %x{
188
+ var value = $opal.$yieldX(block, args);
189
+
190
+ if (value === $breaker) {
191
+ return $breaker;
192
+ }
193
+
194
+ #{enum.yield `value`};
195
+ }
196
+ }
197
+ end
198
+
199
+ def collect_concat(&block)
200
+ unless block
201
+ raise ArgumentError, 'tried to call lazy map without a block'
202
+ end
203
+
204
+ Lazy.new(self, nil) {|enum, *args|
205
+ %x{
206
+ var value = $opal.$yieldX(block, args);
207
+
208
+ if (value === $breaker) {
209
+ return $breaker;
210
+ }
211
+
212
+ if (#{`value`.respond_to? :force} && #{`value`.respond_to? :each}) {
213
+ #{`value`.each { |v| enum.yield v }}
214
+ }
215
+ else {
216
+ var array = #{Opal.try_convert `value`, Array, :to_ary};
217
+
218
+ if (array === nil) {
219
+ #{enum.yield `value`};
220
+ }
221
+ else {
222
+ #{`value`.each { |v| enum.yield v }};
223
+ }
224
+ }
225
+ }
226
+ }
227
+ end
228
+
229
+ def drop(n)
230
+ n = Opal.coerce_to n, Integer, :to_int
231
+
232
+ if n < 0
233
+ raise ArgumentError, "attempt to drop negative size"
234
+ end
235
+
236
+ current_size = enumerator_size
237
+ set_size = if Integer === current_size
238
+ n < current_size ? n : current_size
239
+ else
240
+ current_size
241
+ end
242
+
243
+ dropped = 0
244
+ Lazy.new(self, set_size) {|enum, *args|
245
+ if dropped < n
246
+ dropped += 1
247
+ else
248
+ enum.yield(*args)
249
+ end
250
+ }
251
+ end
252
+
253
+ def drop_while(&block)
254
+ unless block
255
+ raise ArgumentError, 'tried to call lazy drop_while without a block'
256
+ end
257
+
258
+ succeeding = true
259
+ Lazy.new(self, nil) {|enum, *args|
260
+ if succeeding
261
+ %x{
262
+ var value = $opal.$yieldX(block, args);
263
+
264
+ if (value === $breaker) {
265
+ return $breaker;
266
+ }
267
+
268
+ if (#{Opal.falsy?(`value`)}) {
269
+ succeeding = false;
270
+
271
+ #{enum.yield(*args)};
272
+ }
273
+ }
274
+ else
275
+ enum.yield(*args)
276
+ end
277
+ }
278
+ end
279
+
280
+ def enum_for(method = :each, *args, &block)
281
+ self.class.for(self, method, *args, &block)
282
+ end
283
+
284
+ def find_all(&block)
285
+ unless block
286
+ raise ArgumentError, 'tried to call lazy select without a block'
287
+ end
288
+
289
+ Lazy.new(self, nil) {|enum, *args|
290
+ %x{
291
+ var value = $opal.$yieldX(block, args);
292
+
293
+ if (value === $breaker) {
294
+ return $breaker;
295
+ }
296
+
297
+ if (#{Opal.truthy?(`value`)}) {
298
+ #{enum.yield(*args)};
299
+ }
300
+ }
301
+ }
302
+ end
303
+
304
+ alias flat_map collect_concat
305
+
306
+ def grep(pattern, &block)
307
+ if block
308
+ Lazy.new(self, nil) {|enum, *args|
309
+ %x{
310
+ var param = #{Opal.destructure(args)},
311
+ value = #{pattern === `param`};
312
+
313
+ if (#{Opal.truthy?(`value`)}) {
314
+ value = $opal.$yield1(block, param);
315
+
316
+ if (value === $breaker) {
317
+ return $breaker;
318
+ }
319
+
320
+ #{enum.yield `$opal.$yield1(block, param)`};
321
+ }
322
+ }
323
+ }
324
+ else
325
+ Lazy.new(self, nil) {|enum, *args|
326
+ %x{
327
+ var param = #{Opal.destructure(args)},
328
+ value = #{pattern === `param`};
329
+
330
+ if (#{Opal.truthy?(`value`)}) {
331
+ #{enum.yield `param`};
332
+ }
333
+ }
334
+ }
335
+ end
336
+ end
337
+
338
+ alias map collect
339
+
340
+ alias select find_all
341
+
342
+ def reject(&block)
343
+ unless block
344
+ raise ArgumentError, 'tried to call lazy reject without a block'
345
+ end
346
+
347
+ Lazy.new(self, nil) {|enum, *args|
348
+ %x{
349
+ var value = $opal.$yieldX(block, args);
350
+
351
+ if (value === $breaker) {
352
+ return $breaker;
353
+ }
354
+
355
+ if (#{Opal.falsy?(`value`)}) {
356
+ #{enum.yield(*args)};
357
+ }
358
+ }
359
+ }
360
+ end
361
+
362
+ def take(n)
363
+ n = Opal.coerce_to n, Integer, :to_int
364
+
365
+ if n < 0
366
+ raise ArgumentError, "attempt to take negative size"
367
+ end
368
+
369
+ current_size = enumerator_size
370
+ set_size = if Integer === current_size
371
+ n < current_size ? n : current_size
372
+ else
373
+ current_size
374
+ end
375
+
376
+ taken = 0
377
+ Lazy.new(self, set_size) {|enum, *args|
378
+ if taken < n
379
+ enum.yield(*args)
380
+ taken += 1
381
+ else
382
+ raise StopLazyError
383
+ end
384
+ }
385
+ end
386
+
387
+ def take_while(&block)
388
+ unless block
389
+ raise ArgumentError, 'tried to call lazy take_while without a block'
390
+ end
391
+
392
+ Lazy.new(self, nil) {|enum, *args|
393
+ %x{
394
+ var value = $opal.$yieldX(block, args);
395
+
396
+ if (value === $breaker) {
397
+ return $breaker;
398
+ }
399
+
400
+ if (#{Opal.truthy?(`value`)}) {
401
+ #{enum.yield(*args)};
402
+ }
403
+ else {
404
+ #{raise StopLazyError};
405
+ }
406
+ }
407
+ }
408
+ end
409
+
410
+ alias to_enum enum_for
411
+
412
+ def inspect
413
+ "#<#{self.class.name}: #{@enumerator.inspect}>"
414
+ end
415
+ end
416
+ end
File without changes
@@ -28,8 +28,9 @@ class Hash
28
28
  }
29
29
  }
30
30
  else {
31
- for (var i = 0, length = arguments.length, key; i < length; i++) {
32
- var key = arguments[i], obj = arguments[++i];
31
+ for (var i = 0, length = arguments.length; i < length; i++) {
32
+ var key = arguments[i],
33
+ obj = arguments[++i];
33
34
 
34
35
  if (assocs[key] == null) {
35
36
  keys.push(key);
@@ -50,8 +51,10 @@ class Hash
50
51
  %x{
51
52
  var $hash2 = Opal.hash2 = function(keys, map) {
52
53
  var hash = new Hash._alloc;
54
+
53
55
  hash.keys = keys;
54
- hash.map = map;
56
+ hash.map = map;
57
+
55
58
  return hash;
56
59
  };
57
60
  }
@@ -65,8 +68,10 @@ class Hash
65
68
  def self.allocate
66
69
  %x{
67
70
  var hash = new self._alloc;
68
- hash.map = {};
71
+
72
+ hash.map = {};
69
73
  hash.keys = [];
74
+
70
75
  return hash;
71
76
  }
72
77
  end
@@ -74,20 +79,10 @@ class Hash
74
79
  def initialize(defaults = undefined, &block)
75
80
  %x{
76
81
  if (defaults != null) {
77
- if (defaults.constructor == Object) {
78
- var map = self.map, keys = self.keys;
79
-
80
- for (var key in defaults) {
81
- keys.push(key);
82
- map[key] = defaults[key];
83
- }
84
- }
85
- else {
86
- self.none = defaults;
87
- }
82
+ self.none = defaults;
88
83
  }
89
84
  else if (block !== nil) {
90
- self.proc = block;
85
+ self.proc = block;
91
86
  }
92
87
 
93
88
  return self;
@@ -181,20 +176,25 @@ class Hash
181
176
 
182
177
  def clone
183
178
  %x{
184
- var result = new self._klass._alloc();
185
-
186
- result.map = {}; result.keys = [];
187
-
188
- var map = self.map,
189
- map2 = result.map,
190
- keys2 = result.keys;
179
+ var map = {},
180
+ keys = [];
191
181
 
192
182
  for (var i = 0, length = self.keys.length; i < length; i++) {
193
- keys2.push(self.keys[i]);
194
- map2[self.keys[i]] = map[self.keys[i]];
183
+ var key = self.keys[i],
184
+ value = self.map[key];
185
+
186
+ keys.push(key);
187
+ map[key] = value;
195
188
  }
196
189
 
197
- return result;
190
+ var hash = new self._klass._alloc();
191
+
192
+ hash.map = map;
193
+ hash.keys = keys;
194
+ hash.none = self.none;
195
+ hash.proc = self.proc;
196
+
197
+ return hash;
198
198
  }
199
199
  end
200
200
 
@@ -720,34 +720,24 @@ class Hash
720
720
  }
721
721
  end
722
722
 
723
- def to_hash
724
- self
725
- end
726
-
727
- def to_n
723
+ def to_h
728
724
  %x{
729
- var result = {},
730
- keys = self.keys,
731
- map = self.map,
732
- bucket,
733
- value;
734
-
735
- for (var i = 0, length = keys.length; i < length; i++) {
736
- var key = keys[i],
737
- obj = map[key];
725
+ var hash = new Hash._alloc,
726
+ cloned = #{clone};
738
727
 
739
- if (#{`obj`.respond_to? :to_n}) {
740
- result[key] = #{`obj`.to_n};
741
- }
742
- else {
743
- result[key] = obj;
744
- }
745
- }
728
+ hash.map = cloned.map;
729
+ hash.keys = cloned.keys;
730
+ hash.none = cloned.none;
731
+ hash.proc = cloned.proc;
746
732
 
747
- return result;
733
+ return hash;
748
734
  }
749
735
  end
750
736
 
737
+ def to_hash
738
+ self
739
+ end
740
+
751
741
  alias to_s inspect
752
742
 
753
743
  alias update merge!