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.
- checksums.yaml +4 -4
- data/Gemfile +0 -2
- data/README.md +1 -1
- data/Rakefile +11 -8
- data/lib/opal.rb +1 -1
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +1 -1
- data/{corelib → opal/core}/array.rb +47 -40
- data/{corelib → opal/core}/basic_object.rb +4 -0
- data/{corelib → opal/core}/boolean.rb +2 -6
- data/{corelib → opal/core}/class.rb +0 -0
- data/{corelib → opal/core}/comparable.rb +0 -0
- data/{corelib → opal/core}/encoding.rb +0 -0
- data/{corelib → opal/core}/enumerable.rb +160 -38
- data/opal/core/enumerator.rb +416 -0
- data/{corelib → opal/core}/error.rb +0 -0
- data/{corelib → opal/core}/hash.rb +38 -48
- data/{corelib → opal/core}/io.rb +13 -9
- data/{corelib → opal/core}/kernel.rb +75 -49
- data/{corelib → opal/core}/main.rb +0 -0
- data/{corelib → opal/core}/match_data.rb +0 -4
- data/{corelib → opal/core}/method.rb +0 -0
- data/{corelib → opal/core}/module.rb +24 -3
- data/{corelib → opal/core}/nil_class.rb +0 -4
- data/{corelib → opal/core}/numeric.rb +3 -4
- data/{corelib → opal/core}/proc.rb +0 -4
- data/{corelib → opal/core}/range.rb +0 -0
- data/{corelib → opal/core}/regexp.rb +0 -4
- data/{corelib → opal/core}/runtime.js +0 -0
- data/{corelib → opal/core}/string.rb +4 -6
- data/{corelib → opal/core}/struct.rb +3 -21
- data/{corelib → opal/core}/time.rb +0 -4
- data/opal/opal.rb +121 -0
- data/spec/corelib/array/select_spec.rb +14 -0
- data/spec/filters/20.rb +4 -0
- data/spec/filters/bugs/enumerable.rb +1 -48
- data/spec/filters/unsupported/enumerator.rb +13 -0
- data/spec/opal/compiler/irb_spec.rb +1 -0
- data/spec/rubyspecs +1 -0
- data/spec/{corelib → stdlib}/native/alias_native_spec.rb +6 -4
- data/spec/{corelib → stdlib}/native/each_spec.rb +3 -1
- data/spec/{corelib → stdlib}/native/element_reference_spec.rb +3 -1
- data/spec/stdlib/native/ext_spec.rb +19 -0
- data/spec/{corelib → stdlib}/native/initialize_spec.rb +4 -4
- data/spec/{corelib → stdlib}/native/method_missing_spec.rb +13 -1
- data/spec/{corelib → stdlib}/native/new_spec.rb +3 -1
- data/stdlib/enumerator.rb +1 -0
- data/stdlib/json.rb +1 -1
- data/stdlib/native.rb +483 -0
- metadata +52 -47
- data/corelib/enumerator.rb +0 -55
- data/corelib/native.rb +0 -270
- data/corelib/opal.rb +0 -88
- data/spec/corelib/native/ext_spec.rb +0 -5
- 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
|
32
|
-
var key = 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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
194
|
-
|
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
|
-
|
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
|
724
|
-
self
|
725
|
-
end
|
726
|
-
|
727
|
-
def to_n
|
723
|
+
def to_h
|
728
724
|
%x{
|
729
|
-
var
|
730
|
-
|
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
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
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
|
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!
|