opal 0.7.0.beta1 → 0.7.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitmodules +1 -1
  4. data/.inch.yml +19 -0
  5. data/.travis.yml +10 -7
  6. data/CHANGELOG.md +23 -0
  7. data/README.md +2 -2
  8. data/Rakefile +43 -1
  9. data/bin/opal +6 -1
  10. data/lib/mspec/opal/rake_task.rb +10 -31
  11. data/lib/mspec/opal/runner.rb +44 -1
  12. data/lib/mspec/opal/special_calls.rb +25 -0
  13. data/lib/opal/builder.rb +1 -1
  14. data/lib/opal/builder_processors.rb +4 -23
  15. data/lib/opal/cli.rb +17 -11
  16. data/lib/opal/cli_options.rb +1 -1
  17. data/lib/opal/cli_runners.rb +1 -0
  18. data/lib/opal/cli_runners/apple_script.rb +65 -0
  19. data/lib/opal/cli_runners/nodejs.rb +9 -3
  20. data/lib/opal/cli_runners/phantomjs.rb +2 -2
  21. data/lib/opal/cli_runners/server.rb +7 -5
  22. data/lib/opal/compiler.rb +1 -1
  23. data/lib/opal/nodes/call.rb +3 -2
  24. data/lib/opal/nodes/constants.rb +3 -3
  25. data/lib/opal/nodes/def.rb +7 -7
  26. data/lib/opal/nodes/defined.rb +2 -2
  27. data/lib/opal/nodes/definitions.rb +1 -1
  28. data/lib/opal/nodes/literal.rb +1 -1
  29. data/lib/opal/nodes/logic.rb +1 -1
  30. data/lib/opal/nodes/masgn.rb +1 -1
  31. data/lib/opal/nodes/module.rb +1 -1
  32. data/lib/opal/nodes/rescue.rb +1 -1
  33. data/lib/opal/nodes/scope.rb +1 -1
  34. data/lib/opal/nodes/super.rb +3 -3
  35. data/lib/opal/nodes/top.rb +11 -9
  36. data/lib/opal/nodes/variables.rb +39 -6
  37. data/lib/opal/nodes/yield.rb +3 -3
  38. data/lib/opal/parser.rb +3 -1
  39. data/lib/opal/parser/lexer.rb +8 -2
  40. data/lib/opal/paths.rb +13 -3
  41. data/lib/opal/sprockets/server.rb +1 -1
  42. data/lib/opal/version.rb +1 -1
  43. data/opal.gemspec +1 -1
  44. data/opal/corelib/array.rb +29 -20
  45. data/opal/corelib/array/inheritance.rb +3 -3
  46. data/opal/corelib/basic_object.rb +3 -1
  47. data/opal/corelib/class.rb +1 -1
  48. data/opal/corelib/comparable.rb +6 -5
  49. data/opal/corelib/dir.rb +4 -4
  50. data/opal/corelib/enumerable.rb +25 -25
  51. data/opal/corelib/enumerator.rb +16 -14
  52. data/opal/corelib/error.rb +13 -4
  53. data/opal/corelib/hash.rb +511 -162
  54. data/opal/corelib/helpers.rb +1 -1
  55. data/opal/corelib/kernel.rb +60 -44
  56. data/opal/corelib/match_data.rb +1 -10
  57. data/opal/corelib/method.rb +1 -1
  58. data/opal/corelib/module.rb +62 -32
  59. data/opal/corelib/nil_class.rb +1 -6
  60. data/opal/corelib/numeric.rb +6 -3
  61. data/opal/corelib/proc.rb +1 -1
  62. data/opal/corelib/regexp.rb +15 -6
  63. data/opal/corelib/runtime.js +57 -36
  64. data/opal/corelib/string.rb +38 -2
  65. data/opal/corelib/string/inheritance.rb +3 -3
  66. data/opal/corelib/struct.rb +1 -1
  67. data/opal/corelib/time.rb +46 -3
  68. data/spec/filters/bugs/date.rb +15 -0
  69. data/spec/filters/bugs/enumerator.rb +7 -0
  70. data/spec/filters/bugs/exception.rb +12 -0
  71. data/spec/filters/bugs/hash.rb +0 -18
  72. data/spec/filters/bugs/match_data.rb +13 -0
  73. data/spec/filters/bugs/module.rb +13 -0
  74. data/spec/filters/bugs/numeric.rb +2 -0
  75. data/spec/filters/bugs/regexp.rb +0 -2
  76. data/spec/filters/bugs/stringscanner.rb +8 -0
  77. data/spec/filters/bugs/time.rb +1 -1
  78. data/spec/filters/unsupported/float.rb +1 -0
  79. data/spec/filters/unsupported/symbols.rb +10 -0
  80. data/spec/filters/unsupported/tainted.rb +3 -0
  81. data/spec/filters/unsupported/trusted.rb +3 -0
  82. data/spec/lib/compiler_spec.rb +2 -2
  83. data/spec/lib/parser/call_spec.rb +7 -0
  84. data/spec/opal/core/date_spec.rb +49 -8
  85. data/spec/opal/core/exception_spec.rb +13 -0
  86. data/spec/opal/core/fixtures/require_tree_files/nested/nested 1.rb +1 -0
  87. data/spec/opal/core/fixtures/require_tree_files/nested/nested 2.rb +1 -0
  88. data/spec/opal/core/fixtures/require_tree_files/other/other 1.rb +1 -0
  89. data/spec/opal/core/kernel/require_tree_spec.rb +3 -1
  90. data/spec/opal/core/language/predefined_spec.rb +43 -0
  91. data/spec/opal/stdlib/promise/rescue_spec.rb +9 -0
  92. data/spec/opal/stdlib/promise/then_spec.rb +9 -0
  93. data/spec/opal/stdlib/promise/trace_spec.rb +9 -0
  94. data/spec/rubyspecs +40 -19
  95. data/spec/spec_helper.rb +10 -5
  96. data/stdlib/date.rb +68 -8
  97. data/stdlib/fileutils.rb +0 -0
  98. data/stdlib/iconv.rb +0 -0
  99. data/stdlib/json.rb +16 -3
  100. data/stdlib/native.rb +36 -17
  101. data/stdlib/nodejs.rb +3 -0
  102. data/stdlib/nodejs/dir.rb +1 -1
  103. data/stdlib/nodejs/file.rb +2 -2
  104. data/stdlib/nodejs/io.rb +1 -1
  105. data/stdlib/nodejs/process.rb +2 -2
  106. data/stdlib/nodejs/require.rb +5 -7
  107. data/stdlib/nodejs/runtime.rb +3 -2
  108. data/stdlib/pathname.rb +25 -1
  109. data/stdlib/promise.rb +16 -0
  110. data/stdlib/set.rb +48 -4
  111. data/stdlib/strscan.rb +12 -1
  112. data/stdlib/yaml.rb +1 -0
  113. metadata +27 -7
  114. data/spec/opal/core/language/symbol_spec.rb +0 -40
@@ -59,7 +59,7 @@ class Enumerator
59
59
  return enum_for :with_index, offset unless block
60
60
 
61
61
  %x{
62
- var result
62
+ var result, index = 0;
63
63
 
64
64
  self.$each.$$p = function() {
65
65
  var param = #{Opal.destructure(`arguments`)},
@@ -78,13 +78,15 @@ class Enumerator
78
78
  if (result !== undefined) {
79
79
  return result;
80
80
  }
81
+
82
+ return nil;
81
83
  }
82
84
  end
83
85
 
84
86
  alias with_object each_with_object
85
87
 
86
88
  def inspect
87
- result = "#<#{self.class.name}: #{@object.inspect}:#{@method}"
89
+ result = "#<#{self.class}: #{@object.inspect}:#{@method}"
88
90
 
89
91
  unless @args.empty?
90
92
  result += "(#{@args.inspect[Range.new(1, -2)]})"
@@ -109,7 +111,7 @@ class Enumerator
109
111
  try {
110
112
  args.unshift(#{yielder});
111
113
 
112
- if ($opal.$yieldX(#@block, args) === $breaker) {
114
+ if (Opal.yieldX(#@block, args) === $breaker) {
113
115
  return $breaker.$v;
114
116
  }
115
117
  }
@@ -134,7 +136,7 @@ class Enumerator
134
136
 
135
137
  def yield(*values)
136
138
  %x{
137
- var value = $opal.$yieldX(#@block, values);
139
+ var value = Opal.yieldX(#@block, values);
138
140
 
139
141
  if (value === $breaker) {
140
142
  throw $breaker;
@@ -167,7 +169,7 @@ class Enumerator
167
169
  %x{
168
170
  args.unshift(#{yielder});
169
171
 
170
- if ($opal.$yieldX(block, args) === $breaker) {
172
+ if (Opal.yieldX(block, args) === $breaker) {
171
173
  return $breaker;
172
174
  }
173
175
  }
@@ -191,7 +193,7 @@ class Enumerator
191
193
 
192
194
  Lazy.new(self, enumerator_size) {|enum, *args|
193
195
  %x{
194
- var value = $opal.$yieldX(block, args);
196
+ var value = Opal.yieldX(block, args);
195
197
 
196
198
  if (value === $breaker) {
197
199
  return $breaker;
@@ -209,7 +211,7 @@ class Enumerator
209
211
 
210
212
  Lazy.new(self, nil) {|enum, *args|
211
213
  %x{
212
- var value = $opal.$yieldX(block, args);
214
+ var value = Opal.yieldX(block, args);
213
215
 
214
216
  if (value === $breaker) {
215
217
  return $breaker;
@@ -265,7 +267,7 @@ class Enumerator
265
267
  Lazy.new(self, nil) {|enum, *args|
266
268
  if succeeding
267
269
  %x{
268
- var value = $opal.$yieldX(block, args);
270
+ var value = Opal.yieldX(block, args);
269
271
 
270
272
  if (value === $breaker) {
271
273
  return $breaker;
@@ -294,7 +296,7 @@ class Enumerator
294
296
 
295
297
  Lazy.new(self, nil) {|enum, *args|
296
298
  %x{
297
- var value = $opal.$yieldX(block, args);
299
+ var value = Opal.yieldX(block, args);
298
300
 
299
301
  if (value === $breaker) {
300
302
  return $breaker;
@@ -317,13 +319,13 @@ class Enumerator
317
319
  value = #{pattern === `param`};
318
320
 
319
321
  if (#{Opal.truthy?(`value`)}) {
320
- value = $opal.$yield1(block, param);
322
+ value = Opal.yield1(block, param);
321
323
 
322
324
  if (value === $breaker) {
323
325
  return $breaker;
324
326
  }
325
327
 
326
- #{enum.yield `$opal.$yield1(block, param)`};
328
+ #{enum.yield `Opal.yield1(block, param)`};
327
329
  }
328
330
  }
329
331
  }
@@ -352,7 +354,7 @@ class Enumerator
352
354
 
353
355
  Lazy.new(self, nil) {|enum, *args|
354
356
  %x{
355
- var value = $opal.$yieldX(block, args);
357
+ var value = Opal.yieldX(block, args);
356
358
 
357
359
  if (value === $breaker) {
358
360
  return $breaker;
@@ -397,7 +399,7 @@ class Enumerator
397
399
 
398
400
  Lazy.new(self, nil) {|enum, *args|
399
401
  %x{
400
- var value = $opal.$yieldX(block, args);
402
+ var value = Opal.yieldX(block, args);
401
403
 
402
404
  if (value === $breaker) {
403
405
  return $breaker;
@@ -416,7 +418,7 @@ class Enumerator
416
418
  alias to_enum enum_for
417
419
 
418
420
  def inspect
419
- "#<#{self.class.name}: #{@enumerator.inspect}>"
421
+ "#<#{self.class}: #{@enumerator.inspect}>"
420
422
  end
421
423
  end
422
424
  end
@@ -1,15 +1,24 @@
1
1
  class Exception
2
2
  attr_reader :message
3
3
 
4
- def self.new(message = '')
4
+ def self.new(message = 'Exception')
5
5
  %x{
6
- var err = new Error(message);
7
- err.$$class = self;
6
+ var err = new self.$$alloc(message);
7
+
8
+ if (Error.captureStackTrace) {
9
+ Error.captureStackTrace(err);
10
+ }
11
+
8
12
  err.name = self.$$name;
13
+ err.$initialize(message);
9
14
  return err;
10
15
  }
11
16
  end
12
17
 
18
+ def initialize(message)
19
+ `self.message = message`
20
+ end
21
+
13
22
  def backtrace
14
23
  %x{
15
24
  var backtrace = self.stack;
@@ -26,7 +35,7 @@ class Exception
26
35
  end
27
36
 
28
37
  def inspect
29
- "#<#{self.class.name}: '#@message'>"
38
+ "#<#{self.class}: '#@message'>"
30
39
  end
31
40
 
32
41
  alias to_s message
@@ -4,7 +4,7 @@ class Hash
4
4
  include Enumerable
5
5
 
6
6
  def self.[](*objs)
7
- `$opal.hash.apply(null, objs)`
7
+ `Opal.hash.apply(null, objs)`
8
8
  end
9
9
 
10
10
  def self.allocate
@@ -12,6 +12,7 @@ class Hash
12
12
  var hash = new self.$$alloc;
13
13
 
14
14
  hash.map = {};
15
+ hash.smap = {};
15
16
  hash.keys = [];
16
17
  hash.none = nil;
17
18
  hash.proc = nil;
@@ -34,7 +35,7 @@ class Hash
34
35
  return true;
35
36
  }
36
37
 
37
- if (!other.map || !other.keys) {
38
+ if (!other.keys || !other.smap || !other.map) {
38
39
  return false;
39
40
  }
40
41
 
@@ -42,12 +43,30 @@ class Hash
42
43
  return false;
43
44
  }
44
45
 
45
- var map = self.map,
46
- map2 = other.map;
46
+ var _map = self.map,
47
+ smap = self.smap,
48
+ _map2 = other.map,
49
+ smap2 = other.smap,
50
+ map, map2, key, khash, value, value2;
47
51
 
48
52
  for (var i = 0, length = self.keys.length; i < length; i++) {
49
- var key = self.keys[i], obj = map[key], obj2 = map2[key];
50
- if (obj2 === undefined || #{`obj` != `obj2`}) {
53
+ key = self.keys[i];
54
+
55
+ if (key.$$is_string) {
56
+ khash = key;
57
+ map = smap;
58
+ map2 = smap2;
59
+ } else {
60
+ khash = key.$hash();
61
+ map = _map;
62
+ map2 = _map2;
63
+ }
64
+
65
+ value = map[khash];
66
+ if (value === undefined) console.log('==', key, self);
67
+ value2 = map2[khash];
68
+
69
+ if (value2 === undefined || #{not(`value` == `value2`)}) {
51
70
  return false;
52
71
  }
53
72
  }
@@ -58,10 +77,21 @@ class Hash
58
77
 
59
78
  def [](key)
60
79
  %x{
61
- var map = self.map;
80
+ var map, khash;
81
+
82
+ if (key.$$is_string) {
83
+ map = self.smap;
84
+ khash = key;
85
+ } else {
86
+ map = self.map;
87
+ khash = key.$hash();
88
+ }
62
89
 
63
- if ($opal.hasOwnProperty.call(map, key)) {
64
- return map[key];
90
+ if (map === undefined) { console.log(self, '[] --> key:', key, khash, map) }
91
+
92
+
93
+ if (Opal.hasOwnProperty.call(map, khash)) {
94
+ return map[khash];
65
95
  }
66
96
 
67
97
  var proc = #@proc;
@@ -76,13 +106,21 @@ class Hash
76
106
 
77
107
  def []=(key, value)
78
108
  %x{
79
- var map = self.map;
109
+ var map, khash, value;
110
+
111
+ if (key.$$is_string) {
112
+ map = self.smap;
113
+ khash = key;
114
+ } else {
115
+ map = self.map;
116
+ khash = key.$hash();
117
+ }
80
118
 
81
- if (!$opal.hasOwnProperty.call(map, key)) {
119
+ if (!Opal.hasOwnProperty.call(map, khash)) {
82
120
  self.keys.push(key);
83
121
  }
84
122
 
85
- map[key] = value;
123
+ map[khash] = value;
86
124
 
87
125
  return value;
88
126
  }
@@ -90,13 +128,22 @@ class Hash
90
128
 
91
129
  def assoc(object)
92
130
  %x{
93
- var keys = self.keys, key;
131
+ var keys = self.keys,
132
+ map, key, khash;
94
133
 
95
134
  for (var i = 0, length = keys.length; i < length; i++) {
96
135
  key = keys[i];
97
136
 
98
137
  if (#{`key` == object}) {
99
- return [key, self.map[key]];
138
+ if (key.$$is_string) {
139
+ map = self.smap;
140
+ khash = key;
141
+ } else {
142
+ map = self.map;
143
+ khash = key.$hash();
144
+ }
145
+
146
+ return [key, map[khash]];
100
147
  }
101
148
  }
102
149
 
@@ -107,6 +154,7 @@ class Hash
107
154
  def clear
108
155
  %x{
109
156
  self.map = {};
157
+ self.smap = {};
110
158
  self.keys = [];
111
159
  return self;
112
160
  }
@@ -114,25 +162,41 @@ class Hash
114
162
 
115
163
  def clone
116
164
  %x{
117
- var map = {},
118
- keys = [];
165
+ var _map = {},
166
+ smap = {},
167
+ _map2 = self.map,
168
+ smap2 = self.smap,
169
+ keys = [],
170
+ map, map2, key, khash, value;
119
171
 
120
172
  for (var i = 0, length = self.keys.length; i < length; i++) {
121
- var key = self.keys[i],
122
- value = self.map[key];
173
+ key = self.keys[i];
174
+
175
+ if (key.$$is_string) {
176
+ khash = key;
177
+ map = smap;
178
+ map2 = smap2;
179
+ } else {
180
+ khash = key.$hash();
181
+ map = _map;
182
+ map2 = _map2;
183
+ }
184
+
185
+ value = map2[khash];
123
186
 
124
187
  keys.push(key);
125
- map[key] = value;
188
+ map[khash] = value;
126
189
  }
127
190
 
128
- var hash = new self.$$class.$$alloc();
191
+ var clone = new self.$$class.$$alloc();
129
192
 
130
- hash.map = map;
131
- hash.keys = keys;
132
- hash.none = self.none;
133
- hash.proc = self.proc;
193
+ clone.map = _map;
194
+ clone.smap = smap;
195
+ clone.keys = keys;
196
+ clone.none = self.none;
197
+ clone.proc = self.proc;
134
198
 
135
- return hash;
199
+ return clone;
136
200
  }
137
201
  end
138
202
 
@@ -172,10 +236,20 @@ class Hash
172
236
 
173
237
  def delete(key, &block)
174
238
  %x{
175
- var map = self.map, result = map[key];
239
+ var result, map, khash;
240
+
241
+ if (key.$$is_string) {
242
+ map = self.smap;
243
+ khash = key;
244
+ } else {
245
+ map = self.map;
246
+ khash = key.$hash();
247
+ }
248
+
249
+ result = map[khash];
176
250
 
177
251
  if (result != null) {
178
- delete map[key];
252
+ delete map[khash];
179
253
  self.keys.$delete(key);
180
254
 
181
255
  return result;
@@ -192,18 +266,31 @@ class Hash
192
266
  return enum_for :delete_if unless block
193
267
 
194
268
  %x{
195
- var map = self.map, keys = self.keys, value;
269
+ var _map = self.map,
270
+ smap = self.smap,
271
+ keys = self.keys,
272
+ map, key, value, obj, khash;
196
273
 
197
274
  for (var i = 0, length = keys.length; i < length; i++) {
198
- var key = keys[i], obj = map[key];
275
+ key = keys[i];
199
276
 
200
- if ((value = block(key, obj)) === $breaker) {
277
+ if (key.$$is_string) {
278
+ map = smap;
279
+ khash = key;
280
+ } else {
281
+ map = _map;
282
+ khash = key.$hash();
283
+ }
284
+ obj = map[khash];
285
+ value = block(key, obj);
286
+
287
+ if (value === $breaker) {
201
288
  return $breaker.$v;
202
289
  }
203
290
 
204
291
  if (value !== false && value !== nil) {
205
292
  keys.splice(i, 1);
206
- delete map[key];
293
+ delete map[khash];
207
294
 
208
295
  length--;
209
296
  i--;
@@ -220,12 +307,23 @@ class Hash
220
307
  return enum_for :each unless block
221
308
 
222
309
  %x{
223
- var map = self.map,
224
- keys = self.keys;
310
+ var _map = self.map,
311
+ smap = self.smap,
312
+ keys = self.keys,
313
+ map, key, khash, value;
225
314
 
226
315
  for (var i = 0, length = keys.length; i < length; i++) {
227
- var key = keys[i],
228
- value = $opal.$yield1(block, [key, map[key]]);
316
+ key = keys[i];
317
+
318
+ if (key.$$is_string) {
319
+ map = smap;
320
+ khash = key;
321
+ } else {
322
+ map = _map;
323
+ khash = key.$hash();
324
+ }
325
+
326
+ value = Opal.yield1(block, [key, map[khash]]);
229
327
 
230
328
  if (value === $breaker) {
231
329
  return $breaker.$v;
@@ -238,12 +336,12 @@ class Hash
238
336
 
239
337
  def each_key(&block)
240
338
  return enum_for :each_key unless block
241
-
339
+ # @keys.each(&block)
242
340
  %x{
243
- var keys = self.keys;
341
+ var keys = self.keys, key;
244
342
 
245
343
  for (var i = 0, length = keys.length; i < length; i++) {
246
- var key = keys[i];
344
+ key = keys[i];
247
345
 
248
346
  if (block(key) === $breaker) {
249
347
  return $breaker.$v;
@@ -260,10 +358,22 @@ class Hash
260
358
  return enum_for :each_value unless block
261
359
 
262
360
  %x{
263
- var map = self.map, keys = self.keys;
361
+ var _map = self.map,
362
+ smap = self.smap,
363
+ keys = self.keys;
264
364
 
265
365
  for (var i = 0, length = keys.length; i < length; i++) {
266
- if (block(map[keys[i]]) === $breaker) {
366
+ key = keys[i];
367
+
368
+ if (key.$$is_string) {
369
+ map = smap;
370
+ khash = key;
371
+ } else {
372
+ map = _map;
373
+ khash = key.$hash();
374
+ }
375
+
376
+ if (block(map[khash]) === $breaker) {
267
377
  return $breaker.$v;
268
378
  }
269
379
  }
@@ -280,7 +390,17 @@ class Hash
280
390
 
281
391
  def fetch(key, defaults = undefined, &block)
282
392
  %x{
283
- var value = self.map[key];
393
+ var map, khash, value;
394
+
395
+ if (key.$$is_string) {
396
+ khash = key;
397
+ map = self.smap;
398
+ } else {
399
+ khash = key.$hash();
400
+ map = self.map;
401
+ }
402
+
403
+ value = map[khash];
284
404
 
285
405
  if (value != null) {
286
406
  return value;
@@ -306,10 +426,24 @@ class Hash
306
426
 
307
427
  def flatten(level=undefined)
308
428
  %x{
309
- var map = self.map, keys = self.keys, result = [];
429
+ var _map = self.map,
430
+ smap = self.smap,
431
+ keys = self.keys,
432
+ result = [],
433
+ map, key, khash, value;
310
434
 
311
435
  for (var i = 0, length = keys.length; i < length; i++) {
312
- var key = keys[i], value = map[key];
436
+ key = keys[i];
437
+
438
+ if (key.$$is_string) {
439
+ khash = key;
440
+ map = smap;
441
+ } else {
442
+ khash = key.$hash();
443
+ map = _map;
444
+ }
445
+
446
+ value = map[khash];
313
447
 
314
448
  result.push(key);
315
449
 
@@ -331,13 +465,34 @@ class Hash
331
465
  end
332
466
 
333
467
  def has_key?(key)
334
- `$opal.hasOwnProperty.call(self.map, key)`
468
+ %x{
469
+ var keys = self.keys,
470
+ map, khash;
471
+
472
+ if (key.$$is_string) {
473
+ khash = key;
474
+ map = self.smap;
475
+ } else {
476
+ khash = key.$hash();
477
+ map = self.map;
478
+ }
479
+
480
+ if (Opal.hasOwnProperty.call(map, khash)) {
481
+ for (var i = 0, length = keys.length; i < length; i++) {
482
+ if (!#{not(key.eql?(`keys[i]`))}) {
483
+ return true;
484
+ }
485
+ }
486
+ }
487
+
488
+ return false;
489
+ }
335
490
  end
336
491
 
337
492
  def has_value?(value)
338
493
  %x{
339
- for (var assoc in self.map) {
340
- if (#{`self.map[assoc]` == value}) {
494
+ for (var khash in self.map) {
495
+ if (#{`self.map[khash]` == value}) {
341
496
  return true;
342
497
  }
343
498
  }
@@ -346,20 +501,27 @@ class Hash
346
501
  }
347
502
  end
348
503
 
349
- def hash
350
- `self.$$id`
351
- end
352
-
353
504
  alias include? has_key?
354
505
 
355
506
  def index(object)
356
507
  %x{
357
- var map = self.map, keys = self.keys;
508
+ var _map = self.map,
509
+ smap = self.smap,
510
+ keys = self.keys,
511
+ map, khash, key;
358
512
 
359
513
  for (var i = 0, length = keys.length; i < length; i++) {
360
- var key = keys[i];
514
+ key = keys[i];
515
+
516
+ if (key.$$is_string) {
517
+ map = smap;
518
+ khash = key;
519
+ } else {
520
+ map = _map;
521
+ khash = key.$hash();
522
+ }
361
523
 
362
- if (#{`map[key]` == object}) {
524
+ if (#{`map[khash]` == object}) {
363
525
  return key;
364
526
  }
365
527
  }
@@ -370,13 +532,26 @@ class Hash
370
532
 
371
533
  def indexes(*keys)
372
534
  %x{
373
- var result = [], map = self.map, val;
535
+ var result = [],
536
+ _map = self.map,
537
+ smap = self.smap,
538
+ map, key, khash, value;
374
539
 
375
540
  for (var i = 0, length = keys.length; i < length; i++) {
376
- var key = keys[i], val = map[key];
541
+ key = keys[i];
542
+
543
+ if (key.$$is_string) {
544
+ khash = key;
545
+ map = smap;
546
+ } else {
547
+ khash = key.$hash();
548
+ map = _map;
549
+ }
550
+
551
+ value = map[khash];
377
552
 
378
- if (val != null) {
379
- result.push(val);
553
+ if (value != null) {
554
+ result.push(value);
380
555
  }
381
556
  else {
382
557
  result.push(self.none);
@@ -389,34 +564,80 @@ class Hash
389
564
 
390
565
  alias indices indexes
391
566
 
567
+ `var inspect_ids = null;`
392
568
  def inspect
393
569
  %x{
394
- var inspect = [], keys = self.keys, map = self.map;
570
+ var top = (inspect_ids === null);
571
+ try {
572
+ var inspect = [],
573
+ keys = self.keys
574
+ _map = self.map,
575
+ smap = self.smap,
576
+ id = #{object_id};
577
+
578
+ if (top) {
579
+ inspect_ids = {}
580
+ }
395
581
 
396
- for (var i = 0, length = keys.length; i < length; i++) {
397
- var key = keys[i], val = map[key];
582
+ if (inspect_ids.hasOwnProperty(id)) {
583
+ return '{...}';
584
+ }
398
585
 
399
- if (val === self) {
400
- inspect.push(#{`key`.inspect} + '=>' + '{...}');
401
- } else {
402
- inspect.push(#{`key`.inspect} + '=>' + #{`map[key]`.inspect});
586
+ inspect_ids[id] = true;
587
+
588
+ for (var i = 0, length = keys.length; i < length; i++) {
589
+ var key = keys[i],
590
+ value = key.$$is_string ? smap[key] : _map[key.$hash()];
591
+
592
+ value = value;
593
+ key = key;
594
+ inspect.push(key.$inspect() + '=>' + value.$inspect());
403
595
  }
404
- }
405
596
 
406
- return '{' + inspect.join(', ') + '}';
597
+ return '{' + inspect.join(', ') + '}';
598
+ } finally {
599
+
600
+ if (top) {
601
+ inspect_ids = null;
602
+ }
603
+ }
407
604
  }
408
605
  end
409
606
 
410
607
  def invert
411
608
  %x{
412
- var result = $opal.hash(), keys = self.keys, map = self.map,
413
- keys2 = result.keys, map2 = result.map;
609
+ var result = Opal.hash(),
610
+ keys = self.keys,
611
+ _map = self.map,
612
+ smap = self.smap,
613
+ keys2 = result.keys,
614
+ _map2 = result.map,
615
+ smap2 = result.smap,
616
+ map, map2, key, khash, value;
414
617
 
415
618
  for (var i = 0, length = keys.length; i < length; i++) {
416
- var key = keys[i], obj = map[key];
619
+ key = keys[i];
620
+
621
+ if (key.$$is_string) {
622
+ map = smap;
623
+ khash = key;
624
+ } else {
625
+ map = _map;
626
+ khash = key.$hash();
627
+ }
628
+
629
+ value = map[khash];
630
+ keys2.push(value);
631
+
632
+ if (value.$$is_string) {
633
+ map2 = smap2;
634
+ khash = value;
635
+ } else {
636
+ map2 = _map2;
637
+ khash = value.$hash();
638
+ }
417
639
 
418
- keys2.push(obj);
419
- map2[obj] = key;
640
+ map2[khash] = key;
420
641
  }
421
642
 
422
643
  return result;
@@ -427,18 +648,32 @@ class Hash
427
648
  return enum_for :keep_if unless block
428
649
 
429
650
  %x{
430
- var map = self.map, keys = self.keys, value;
651
+ var _map = self.map,
652
+ smap = self.smap,
653
+ keys = self.keys,
654
+ map, key, khash, value, keep;
431
655
 
432
656
  for (var i = 0, length = keys.length; i < length; i++) {
433
- var key = keys[i], obj = map[key];
657
+ key = keys[i];
434
658
 
435
- if ((value = block(key, obj)) === $breaker) {
659
+ if (key.$$is_string) {
660
+ khash = key;
661
+ map = smap;
662
+ } else {
663
+ khash = key.$hash();
664
+ map = _map;
665
+ }
666
+
667
+ value = map[khash];
668
+ keep = block(key, value);
669
+
670
+ if (keep === $breaker) {
436
671
  return $breaker.$v;
437
672
  }
438
673
 
439
- if (value === false || value === nil) {
674
+ if (keep === false || keep === nil) {
440
675
  keys.splice(i, 1);
441
- delete map[key];
676
+ delete map[khash];
442
677
 
443
678
  length--;
444
679
  i--;
@@ -464,50 +699,13 @@ class Hash
464
699
  alias member? has_key?
465
700
 
466
701
  def merge(other, &block)
467
- %x{
468
- if (! #{Hash === other}) {
469
- other = #{Opal.coerce_to!(other, Hash, :to_hash)};
470
- }
471
-
472
- var keys = self.keys, map = self.map,
473
- result = $opal.hash(), keys2 = result.keys, map2 = result.map;
474
-
475
- for (var i = 0, length = keys.length; i < length; i++) {
476
- var key = keys[i];
477
-
478
- keys2.push(key);
479
- map2[key] = map[key];
480
- }
481
-
482
- var keys = other.keys, map = other.map;
702
+ unless Hash === other
703
+ other = Opal.coerce_to!(other, Hash, :to_hash)
704
+ end
483
705
 
484
- if (block === nil) {
485
- for (var i = 0, length = keys.length; i < length; i++) {
486
- var key = keys[i];
487
-
488
- if (map2[key] == null) {
489
- keys2.push(key);
490
- }
491
-
492
- map2[key] = map[key];
493
- }
494
- }
495
- else {
496
- for (var i = 0, length = keys.length; i < length; i++) {
497
- var key = keys[i];
498
-
499
- if (map2[key] == null) {
500
- keys2.push(key);
501
- map2[key] = map[key];
502
- }
503
- else {
504
- map2[key] = block(key, map2[key], map[key]);
505
- }
506
- }
507
- }
508
-
509
- return result;
510
- }
706
+ cloned = clone
707
+ cloned.merge!(other, &block)
708
+ cloned
511
709
  end
512
710
 
513
711
  def merge!(other, &block)
@@ -516,30 +714,58 @@ class Hash
516
714
  other = #{Opal.coerce_to!(other, Hash, :to_hash)};
517
715
  }
518
716
 
519
- var keys = self.keys, map = self.map,
520
- keys2 = other.keys, map2 = other.map;
717
+ var keys = self.keys,
718
+ _map = self.map,
719
+ smap = self.smap,
720
+ keys2 = other.keys,
721
+ _map2 = other.map,
722
+ smap2 = other.smap,
723
+ map, map2, key, khash, value, value2;
521
724
 
522
725
  if (block === nil) {
523
726
  for (var i = 0, length = keys2.length; i < length; i++) {
524
- var key = keys2[i];
727
+ key = keys2[i];
728
+
729
+ if (key.$$is_string) {
730
+ khash = key;
731
+ map = smap;
732
+ map2 = smap2;
733
+ } else {
734
+ khash = key.$hash();
735
+ map = _map;
736
+ map2 = _map2;
737
+ }
525
738
 
526
- if (map[key] == null) {
739
+ if (map[khash] == null) {
527
740
  keys.push(key);
528
741
  }
529
742
 
530
- map[key] = map2[key];
743
+ map[khash] = map2[khash];
531
744
  }
532
745
  }
533
746
  else {
534
747
  for (var i = 0, length = keys2.length; i < length; i++) {
535
- var key = keys2[i];
748
+ key = keys2[i];
749
+
750
+ if (key.$$is_string) {
751
+ khash = key;
752
+ map = smap;
753
+ map2 = smap2;
754
+ } else {
755
+ khash = key.$hash();
756
+ map = _map;
757
+ map2 = _map2;
758
+ }
536
759
 
537
- if (map[key] == null) {
760
+ value = map[khash];
761
+ value2 = map2[khash];
762
+
763
+ if (value == null) {
538
764
  keys.push(key);
539
- map[key] = map2[key];
765
+ map[khash] = value2;
540
766
  }
541
767
  else {
542
- map[key] = block(key, map[key], map2[key]);
768
+ map[khash] = block(key, value, value2);
543
769
  }
544
770
  }
545
771
  }
@@ -550,13 +776,26 @@ class Hash
550
776
 
551
777
  def rassoc(object)
552
778
  %x{
553
- var keys = self.keys, map = self.map;
779
+ var keys = self.keys,
780
+ _map = self.map,
781
+ smap = self.smap,
782
+ key, khash, value;
554
783
 
555
784
  for (var i = 0, length = keys.length; i < length; i++) {
556
- var key = keys[i], obj = map[key];
785
+ key = keys[i]
786
+
787
+ if (key.$$is_string) {
788
+ khash = key;
789
+ map = smap;
790
+ } else {
791
+ khash = key.$hash();
792
+ map = _map;
793
+ }
794
+
795
+ value = map[khash];
557
796
 
558
- if (#{`obj` == object}) {
559
- return [key, obj];
797
+ if (#{`value` == object}) {
798
+ return [key, value];
560
799
  }
561
800
  }
562
801
 
@@ -568,19 +807,37 @@ class Hash
568
807
  return enum_for :reject unless block
569
808
 
570
809
  %x{
571
- var keys = self.keys, map = self.map,
572
- result = $opal.hash(), map2 = result.map, keys2 = result.keys;
810
+ var keys = self.keys,
811
+ _map = self.map,
812
+ smap = self.smap,
813
+ result = Opal.hash(),
814
+ _map2 = result.map,
815
+ smap2 = result.smap,
816
+ keys2 = result.keys,
817
+ map, map2, key, khash, object, value;
573
818
 
574
819
  for (var i = 0, length = keys.length; i < length; i++) {
575
- var key = keys[i], obj = map[key], value;
820
+ key = keys[i];
576
821
 
577
- if ((value = block(key, obj)) === $breaker) {
822
+ if (key.$$is_string) {
823
+ khash = key;
824
+ map = smap;
825
+ map2 = smap2;
826
+ } else {
827
+ khash = key.$hash();
828
+ map = _map;
829
+ map2 = _map2;
830
+ }
831
+
832
+ object = map[khash];
833
+
834
+ if ((value = block(key, object)) === $breaker) {
578
835
  return $breaker.$v;
579
836
  }
580
837
 
581
838
  if (value === false || value === nil) {
582
839
  keys2.push(key);
583
- map2[key] = obj;
840
+ map2[khash] = object;
584
841
  }
585
842
  }
586
843
 
@@ -590,12 +847,28 @@ class Hash
590
847
 
591
848
  def replace(other)
592
849
  %x{
593
- var map = self.map = {}, keys = self.keys = [];
850
+ var keys = self.keys = [],
851
+ _map = self.map = {},
852
+ smap = self.smap = {},
853
+ _map2 = other.map,
854
+ smap2 = other.smap,
855
+ key, khash, map, map2;
594
856
 
595
857
  for (var i = 0, length = other.keys.length; i < length; i++) {
596
- var key = other.keys[i];
858
+ key = other.keys[i];
859
+
860
+ if (key.$$is_string) {
861
+ khash = key;
862
+ map = smap;
863
+ map2 = smap2;
864
+ } else {
865
+ khash = key.$hash();
866
+ map = _map;
867
+ map2 = _map2;
868
+ }
869
+
597
870
  keys.push(key);
598
- map[key] = other.map[key];
871
+ map[khash] = map2[khash];
599
872
  }
600
873
 
601
874
  return self;
@@ -606,19 +879,38 @@ class Hash
606
879
  return enum_for :select unless block
607
880
 
608
881
  %x{
609
- var keys = self.keys, map = self.map,
610
- result = $opal.hash(), map2 = result.map, keys2 = result.keys;
882
+ var keys = self.keys,
883
+ _map = self.map,
884
+ smap = self.smap,
885
+ result = Opal.hash(),
886
+ _map2 = result.map,
887
+ smap2 = result.smap,
888
+ keys2 = result.keys,
889
+ map, map2, key, khash, value, object;
611
890
 
612
891
  for (var i = 0, length = keys.length; i < length; i++) {
613
- var key = keys[i], obj = map[key], value;
892
+ key = keys[i];
893
+
894
+ if (key.$$is_string) {
895
+ khash = key;
896
+ map = smap;
897
+ map2 = smap2;
898
+ } else {
899
+ khash = key.$hash();
900
+ map = _map;
901
+ map2 = _map2;
902
+ }
903
+
904
+ value = map[khash];
905
+ object = block(key, value);
614
906
 
615
- if ((value = block(key, obj)) === $breaker) {
907
+ if (object === $breaker) {
616
908
  return $breaker.$v;
617
909
  }
618
910
 
619
- if (value !== false && value !== nil) {
911
+ if (object !== false && object !== nil) {
620
912
  keys2.push(key);
621
- map2[key] = obj;
913
+ map2[khash] = value;
622
914
  }
623
915
  }
624
916
 
@@ -630,18 +922,33 @@ class Hash
630
922
  return enum_for :select! unless block
631
923
 
632
924
  %x{
633
- var map = self.map, keys = self.keys, value, result = nil;
925
+ var _map = self.map,
926
+ smap = self.smap,
927
+ keys = self.keys,
928
+ result = nil,
929
+ key, khash, value, object;
634
930
 
635
931
  for (var i = 0, length = keys.length; i < length; i++) {
636
- var key = keys[i], obj = map[key];
932
+ key = keys[i];
637
933
 
638
- if ((value = block(key, obj)) === $breaker) {
934
+ if (key.$$is_string) {
935
+ khash = key;
936
+ map = smap;
937
+ } else {
938
+ khash = key.$hash();
939
+ map = _map;
940
+ }
941
+
942
+ value = map[khash];
943
+ object = block(key, value);
944
+
945
+ if (object === $breaker) {
639
946
  return $breaker.$v;
640
947
  }
641
948
 
642
- if (value === false || value === nil) {
949
+ if (object === false || object === nil) {
643
950
  keys.splice(i, 1);
644
- delete map[key];
951
+ delete map[khash];
645
952
 
646
953
  length--;
647
954
  i--;
@@ -655,15 +962,26 @@ class Hash
655
962
 
656
963
  def shift
657
964
  %x{
658
- var keys = self.keys, map = self.map;
965
+ var keys = self.keys,
966
+ _map = self.map,
967
+ smap = self.smap,
968
+ map, key, khash, value;
659
969
 
660
970
  if (keys.length) {
661
- var key = keys[0], obj = map[key];
971
+ key = keys[0];
972
+ if (key.$$is_string) {
973
+ khash = key;
974
+ map = smap;
975
+ } else {
976
+ khash = key.$hash();
977
+ map = _map;
978
+ }
979
+ value = map[khash];
662
980
 
663
- delete map[key];
981
+ delete map[khash];
664
982
  keys.splice(0, 1);
665
983
 
666
- return [key, obj];
984
+ return [key, value];
667
985
  }
668
986
 
669
987
  return nil;
@@ -676,11 +994,24 @@ class Hash
676
994
 
677
995
  def to_a
678
996
  %x{
679
- var keys = self.keys, map = self.map, result = [];
997
+ var keys = self.keys,
998
+ _map = self.map,
999
+ smap = self.smap,
1000
+ result = [],
1001
+ map, key;
680
1002
 
681
1003
  for (var i = 0, length = keys.length; i < length; i++) {
682
- var key = keys[i];
683
- result.push([key, map[key]]);
1004
+ key = keys[i];
1005
+
1006
+ if (key.$$is_string) {
1007
+ khash = key;
1008
+ map = smap;
1009
+ } else {
1010
+ khash = key.$hash();
1011
+ map = _map;
1012
+ }
1013
+
1014
+ result.push([key, map[khash]]);
684
1015
  }
685
1016
 
686
1017
  return result;
@@ -689,10 +1020,15 @@ class Hash
689
1020
 
690
1021
  def to_h
691
1022
  %x{
1023
+ if (self.$$class === Opal.Hash) {
1024
+ return self
1025
+ }
1026
+
692
1027
  var hash = new Opal.Hash.$$alloc,
693
1028
  cloned = #{clone};
694
1029
 
695
1030
  hash.map = cloned.map;
1031
+ hash.smap = cloned.smap;
696
1032
  hash.keys = cloned.keys;
697
1033
  hash.none = cloned.none;
698
1034
  hash.proc = cloned.proc;
@@ -715,11 +1051,24 @@ class Hash
715
1051
 
716
1052
  def values
717
1053
  %x{
718
- var map = self.map,
719
- result = [];
1054
+ var _map = self.map,
1055
+ smap = self.smap,
1056
+ keys = self.keys,
1057
+ result = [],
1058
+ map, khash;
1059
+
1060
+ for (var i = 0, length = keys.length; i < length; i++) {
1061
+ key = keys[i];
1062
+
1063
+ if (key.$$is_string) {
1064
+ khash = key;
1065
+ map = smap;
1066
+ } else {
1067
+ khash = key.$hash();
1068
+ map = _map;
1069
+ }
720
1070
 
721
- for (var key in map) {
722
- result.push(map[key]);
1071
+ result.push(map[khash]);
723
1072
  }
724
1073
 
725
1074
  return result;