opal 1.7.4 → 1.8.0.alpha1

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 (211) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +9 -9
  3. data/.rubocop/todo.yml +2 -2
  4. data/.rubocop.yml +17 -10
  5. data/.rubocop_todo.yml +311 -0
  6. data/CHANGELOG.md +1 -15
  7. data/UNRELEASED.md +78 -1
  8. data/benchmark-ips/bm_block_vs_yield.rb +3 -0
  9. data/benchmark-ips/bm_slice_or_not.rb +53 -0
  10. data/docs/bridging.md +112 -0
  11. data/docs/compiled_ruby.md +10 -10
  12. data/docs/getting_started.md +18 -22
  13. data/lib/opal/cli_runners/chrome.rb +1 -5
  14. data/lib/opal/cli_runners/chrome_cdp_interface.rb +1 -0
  15. data/lib/opal/cli_runners/firefox_cdp_interface.rb +1 -0
  16. data/lib/opal/compiler.rb +33 -1
  17. data/lib/opal/nodes/args/extract_kwoptarg.rb +2 -1
  18. data/lib/opal/nodes/call.rb +1 -1
  19. data/lib/opal/nodes/call_special.rb +71 -47
  20. data/lib/opal/nodes/hash.rb +14 -30
  21. data/lib/opal/nodes/if.rb +37 -29
  22. data/lib/opal/nodes/literal.rb +5 -1
  23. data/lib/opal/nodes/x_string.rb +13 -0
  24. data/lib/opal/parser/patch.rb +1 -0
  25. data/lib/opal/rewriters/for_rewriter.rb +36 -24
  26. data/lib/opal/simple_server.rb +2 -2
  27. data/lib/opal/source_map/file.rb +1 -1
  28. data/lib/opal/version.rb +1 -1
  29. data/opal/corelib/array/pack.rb +1 -0
  30. data/opal/corelib/array.rb +71 -43
  31. data/opal/corelib/basic_object.rb +1 -0
  32. data/opal/corelib/binding.rb +2 -0
  33. data/opal/corelib/boolean.rb +1 -0
  34. data/opal/corelib/class.rb +2 -0
  35. data/opal/corelib/comparable.rb +1 -0
  36. data/opal/corelib/complex.rb +2 -0
  37. data/opal/corelib/constants.rb +2 -2
  38. data/opal/corelib/dir.rb +2 -0
  39. data/opal/corelib/enumerable.rb +3 -2
  40. data/opal/corelib/enumerator/arithmetic_sequence.rb +2 -0
  41. data/opal/corelib/enumerator/chain.rb +1 -0
  42. data/opal/corelib/enumerator/generator.rb +1 -0
  43. data/opal/corelib/enumerator/lazy.rb +1 -0
  44. data/opal/corelib/enumerator/yielder.rb +2 -0
  45. data/opal/corelib/enumerator.rb +1 -0
  46. data/opal/corelib/error/errno.rb +2 -0
  47. data/opal/corelib/error.rb +12 -0
  48. data/opal/corelib/file.rb +1 -0
  49. data/opal/corelib/hash.rb +197 -504
  50. data/opal/corelib/helpers.rb +1 -0
  51. data/opal/corelib/io.rb +2 -0
  52. data/opal/corelib/irb.rb +2 -0
  53. data/opal/corelib/kernel/format.rb +1 -0
  54. data/opal/corelib/kernel.rb +70 -14
  55. data/opal/corelib/main.rb +2 -0
  56. data/opal/corelib/marshal/read_buffer.rb +2 -0
  57. data/opal/corelib/marshal/write_buffer.rb +2 -0
  58. data/opal/corelib/math/polyfills.rb +2 -0
  59. data/opal/corelib/math.rb +1 -0
  60. data/opal/corelib/method.rb +2 -0
  61. data/opal/corelib/module.rb +1 -0
  62. data/opal/corelib/nil.rb +3 -1
  63. data/opal/corelib/number.rb +2 -0
  64. data/opal/corelib/numeric.rb +2 -0
  65. data/opal/corelib/object_space.rb +1 -0
  66. data/opal/corelib/pack_unpack/format_string_parser.rb +2 -0
  67. data/opal/corelib/proc.rb +30 -28
  68. data/opal/corelib/process.rb +2 -0
  69. data/opal/corelib/random/formatter.rb +2 -0
  70. data/opal/corelib/random/math_random.js.rb +2 -0
  71. data/opal/corelib/random/mersenne_twister.rb +2 -0
  72. data/opal/corelib/random/seedrandom.js.rb +2 -0
  73. data/opal/corelib/random.rb +1 -0
  74. data/opal/corelib/range.rb +34 -12
  75. data/opal/corelib/rational.rb +2 -0
  76. data/opal/corelib/regexp.rb +1 -0
  77. data/opal/corelib/runtime.js +187 -231
  78. data/opal/corelib/set.rb +2 -0
  79. data/opal/corelib/string/encoding.rb +3 -0
  80. data/opal/corelib/string/unpack.rb +2 -0
  81. data/opal/corelib/string.rb +20 -12
  82. data/opal/corelib/struct.rb +3 -1
  83. data/opal/corelib/time.rb +1 -0
  84. data/opal/corelib/trace_point.rb +2 -0
  85. data/opal/corelib/unsupported.rb +2 -0
  86. data/opal/corelib/variables.rb +2 -0
  87. data/opal.gemspec +2 -2
  88. data/spec/filters/bugs/array.rb +0 -2
  89. data/spec/filters/bugs/enumerable.rb +0 -3
  90. data/spec/filters/bugs/hash.rb +0 -13
  91. data/spec/filters/bugs/kernel.rb +0 -38
  92. data/spec/filters/bugs/range.rb +0 -1
  93. data/spec/filters/bugs/ruby-32.rb +0 -2
  94. data/spec/filters/bugs/string.rb +0 -1
  95. data/spec/filters/bugs/struct.rb +1 -5
  96. data/spec/filters/unsupported/hash.rb +1 -0
  97. data/spec/lib/compiler_spec.rb +24 -17
  98. data/spec/mspec-opal/formatters.rb +2 -0
  99. data/spec/mspec-opal/runner.rb +2 -0
  100. data/spec/opal/core/array/dup_spec.rb +2 -0
  101. data/spec/opal/core/exception_spec.rb +2 -0
  102. data/spec/opal/core/hash/internals_spec.rb +154 -206
  103. data/spec/opal/core/hash_spec.rb +2 -0
  104. data/spec/opal/core/iterable_props_spec.rb +2 -0
  105. data/spec/opal/core/kernel/at_exit_spec.rb +2 -0
  106. data/spec/opal/core/kernel/respond_to_spec.rb +2 -0
  107. data/spec/opal/core/language/arguments/mlhs_arg_spec.rb +2 -0
  108. data/spec/opal/core/language/safe_navigator_spec.rb +2 -0
  109. data/spec/opal/core/language/xstring_send_spec.rb +15 -0
  110. data/spec/opal/core/language/xstring_spec.rb +2 -0
  111. data/spec/opal/core/language_spec.rb +2 -0
  112. data/spec/opal/core/module_spec.rb +44 -0
  113. data/spec/opal/core/number/to_i_spec.rb +2 -0
  114. data/spec/opal/core/object_id_spec.rb +2 -0
  115. data/spec/opal/core/regexp/match_spec.rb +2 -0
  116. data/spec/opal/core/runtime/bridged_classes_spec.rb +38 -0
  117. data/spec/opal/core/runtime/constants_spec.rb +2 -0
  118. data/spec/opal/core/runtime/eval_spec.rb +2 -0
  119. data/spec/opal/core/runtime/exit_spec.rb +2 -0
  120. data/spec/opal/core/runtime/is_a_spec.rb +2 -0
  121. data/spec/opal/core/runtime/loaded_spec.rb +2 -0
  122. data/spec/opal/core/runtime/method_missing_spec.rb +2 -0
  123. data/spec/opal/core/runtime/rescue_spec.rb +2 -0
  124. data/spec/opal/core/runtime/string_spec.rb +2 -0
  125. data/spec/opal/core/runtime/truthy_spec.rb +2 -0
  126. data/spec/opal/core/runtime_spec.rb +2 -6
  127. data/spec/opal/core/string/to_sym_spec.rb +2 -0
  128. data/spec/opal/stdlib/js_spec.rb +2 -0
  129. data/spec/opal/stdlib/native/alias_native_spec.rb +2 -0
  130. data/spec/opal/stdlib/native/array_spec.rb +2 -0
  131. data/spec/opal/stdlib/native/date_spec.rb +2 -0
  132. data/spec/opal/stdlib/native/each_spec.rb +2 -0
  133. data/spec/opal/stdlib/native/element_reference_spec.rb +2 -0
  134. data/spec/opal/stdlib/native/exposure_spec.rb +2 -0
  135. data/spec/opal/stdlib/native/ext_spec.rb +2 -0
  136. data/spec/opal/stdlib/native/hash_spec.rb +30 -2
  137. data/spec/opal/stdlib/native/initialize_spec.rb +2 -0
  138. data/spec/opal/stdlib/native/method_missing_spec.rb +2 -0
  139. data/spec/opal/stdlib/native/native_alias_spec.rb +2 -0
  140. data/spec/opal/stdlib/native/native_class_spec.rb +2 -0
  141. data/spec/opal/stdlib/native/native_module_spec.rb +2 -0
  142. data/spec/opal/stdlib/native/native_reader_spec.rb +2 -0
  143. data/spec/opal/stdlib/native/native_writer_spec.rb +2 -0
  144. data/spec/opal/stdlib/native/new_spec.rb +2 -0
  145. data/spec/opal/stdlib/native/struct_spec.rb +2 -0
  146. data/spec/spec_helper.rb +2 -0
  147. data/stdlib/await.rb +1 -0
  148. data/stdlib/base64.rb +2 -0
  149. data/stdlib/bigdecimal/bignumber.js.rb +2 -0
  150. data/stdlib/bigdecimal/util.rb +1 -0
  151. data/stdlib/bigdecimal.rb +2 -0
  152. data/stdlib/buffer/array.rb +2 -0
  153. data/stdlib/buffer/view.rb +2 -0
  154. data/stdlib/buffer.rb +2 -0
  155. data/stdlib/cgi.rb +14 -0
  156. data/stdlib/console.rb +2 -0
  157. data/stdlib/date/date_time.rb +2 -0
  158. data/stdlib/date.rb +2 -0
  159. data/stdlib/delegate.rb +2 -0
  160. data/stdlib/deno/base.rb +2 -0
  161. data/stdlib/deno/file.rb +2 -0
  162. data/stdlib/erb.rb +2 -0
  163. data/stdlib/gjs/io.rb +2 -0
  164. data/stdlib/gjs/kernel.rb +2 -0
  165. data/stdlib/headless_browser/base.rb +2 -0
  166. data/stdlib/headless_browser/file.rb +1 -0
  167. data/stdlib/headless_browser.rb +1 -0
  168. data/stdlib/js.rb +2 -0
  169. data/stdlib/json.rb +9 -15
  170. data/stdlib/logger.rb +2 -0
  171. data/stdlib/nashorn/file.rb +2 -0
  172. data/stdlib/nashorn/io.rb +2 -0
  173. data/stdlib/native.rb +48 -48
  174. data/stdlib/nodejs/base.rb +2 -0
  175. data/stdlib/nodejs/dir.rb +2 -0
  176. data/stdlib/nodejs/env.rb +2 -0
  177. data/stdlib/nodejs/file.rb +2 -0
  178. data/stdlib/nodejs/fileutils.rb +2 -0
  179. data/stdlib/nodejs/io.rb +2 -0
  180. data/stdlib/nodejs/js-yaml-3-6-1.js +1 -1
  181. data/stdlib/nodejs/kernel.rb +2 -0
  182. data/stdlib/nodejs/open-uri.rb +2 -0
  183. data/stdlib/nodejs/pathname.rb +2 -0
  184. data/stdlib/nodejs/require.rb +2 -0
  185. data/stdlib/nodejs/yaml.rb +9 -3
  186. data/stdlib/opal/miniracer.rb +2 -0
  187. data/stdlib/opal-parser.rb +8 -1
  188. data/stdlib/opal-platform.rb +2 -0
  189. data/stdlib/opal-replutils.rb +2 -0
  190. data/stdlib/open-uri.rb +4 -1
  191. data/stdlib/ostruct.rb +4 -2
  192. data/stdlib/pathname.rb +2 -0
  193. data/stdlib/pp.rb +1 -0
  194. data/stdlib/promise/v2.rb +2 -0
  195. data/stdlib/quickjs/io.rb +2 -0
  196. data/stdlib/quickjs/kernel.rb +2 -0
  197. data/stdlib/quickjs.rb +2 -0
  198. data/stdlib/securerandom.rb +2 -0
  199. data/stdlib/strscan.rb +2 -0
  200. data/stdlib/time.rb +2 -0
  201. data/stdlib/uri.rb +1 -0
  202. data/tasks/performance/optimization_status.rb +2 -0
  203. data/tasks/testing.rake +1 -0
  204. data/test/nodejs/test_await.rb +1 -0
  205. data/test/nodejs/test_dir.rb +2 -0
  206. data/test/nodejs/test_error.rb +2 -0
  207. data/test/nodejs/test_file.rb +2 -0
  208. data/test/nodejs/test_string.rb +2 -0
  209. data/test/nodejs/test_yaml.rb +20 -0
  210. metadata +22 -13
  211. data/spec/filters/bugs/openstruct.rb +0 -8
data/opal/corelib/hash.rb CHANGED
@@ -1,16 +1,15 @@
1
- # helpers: yield1, hash, hash_init, hash_get, hash_put, hash_delete, deny_frozen_access, freeze
1
+ # helpers: yield1, hash_clone, hash_delete, hash_each, hash_get, hash_put, deny_frozen_access, freeze
2
+ # backtick_javascript: true
2
3
 
3
4
  require 'corelib/enumerable'
4
5
 
5
6
  # ---
6
7
  # Internal properties:
7
8
  #
8
- # - $$map [JS::Object<String => hash-bucket>] the hash table for ordinary keys
9
- # - $$smap [JS::Object<String => hash-bucket>] the hash table for string keys
10
- # - $$keys [Array<hash-bucket>] the list of all keys
9
+ # - $$keys [Map<key-array>] optional Map of key arrays, used when objects are used as keys
11
10
  # - $$proc [Proc,null,nil] the default proc used for missing keys
12
- # - hash-bucket [JS::Object] an element of a linked list that holds hash values, keys are `{key:,key_hash:,value:,next:}`
13
- class ::Hash
11
+ # - key-array [JS::Map] an element of a array that holds objects used as keys, `{ key_hash => [objects...] }`
12
+ class ::Hash < `Map`
14
13
  include ::Enumerable
15
14
 
16
15
  # Mark all hash instances as valid hashes (used to check keyword args, etc)
@@ -18,7 +17,7 @@ class ::Hash
18
17
 
19
18
  def self.[](*argv)
20
19
  %x{
21
- var hash, argc = argv.length, i;
20
+ var hash, argc = argv.length, arg, i;
22
21
 
23
22
  if (argc === 1) {
24
23
  hash = #{::Opal.coerce_to?(argv[0], ::Hash, :to_hash)};
@@ -28,23 +27,22 @@ class ::Hash
28
27
 
29
28
  argv = #{::Opal.coerce_to?(argv[0], ::Array, :to_ary)};
30
29
  if (argv === nil) {
31
- #{::Kernel.raise ::ArgumentError, 'odd number of arguments for Hash'}
30
+ #{::Kernel.raise ::ArgumentError, 'odd number of arguments for Hash'};
32
31
  }
33
32
 
34
33
  argc = argv.length;
35
34
  hash = #{allocate};
36
35
 
37
36
  for (i = 0; i < argc; i++) {
38
- if (!argv[i].$$is_array) continue;
39
- switch(argv[i].length) {
40
- case 1:
41
- hash.$store(argv[i][0], nil);
42
- break;
43
- case 2:
44
- hash.$store(argv[i][0], argv[i][1]);
45
- break;
46
- default:
47
- #{::Kernel.raise ::ArgumentError, "invalid number of elements (#{`argv[i].length`} for 1..2)"}
37
+ arg = argv[i];
38
+ if (!arg.$$is_array)
39
+ #{::Kernel.raise ::ArgumentError, "invalid element #{`arg`.inspect} for Hash"};
40
+ if (arg.length === 1) {
41
+ hash.$store(arg[0], nil);
42
+ } else if (arg.length === 2) {
43
+ hash.$store(arg[0], arg[1]);
44
+ } else {
45
+ #{::Kernel.raise ::ArgumentError, "invalid number of elements (#{`arg.length`} for #{`arg`.inspect}), must be 1..2"};
48
46
  }
49
47
  }
50
48
 
@@ -69,8 +67,6 @@ class ::Hash
69
67
  %x{
70
68
  var hash = new self.$$constructor();
71
69
 
72
- $hash_init(hash);
73
-
74
70
  hash.$$none = nil;
75
71
  hash.$$proc = nil;
76
72
 
@@ -106,27 +102,17 @@ class ::Hash
106
102
  return false;
107
103
  }
108
104
 
109
- if (self.$$keys.length !== other.$$keys.length) {
105
+ if (self.size !== other.size) {
110
106
  return false;
111
107
  }
112
108
 
113
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value, other_value; i < length; i++) {
114
- key = keys[i];
115
-
116
- if (key.$$is_string) {
117
- value = self.$$smap[key];
118
- other_value = other.$$smap[key];
119
- } else {
120
- value = key.value;
121
- other_value = $hash_get(other, key.key);
122
- }
123
-
109
+ return $hash_each(self, true, function(key, value) {
110
+ var other_value = $hash_get(other, key);
124
111
  if (other_value === undefined || !value['$eql?'](other_value)) {
125
- return false;
112
+ return [true, false];
126
113
  }
127
- }
128
-
129
- return true;
114
+ return [false, true];
115
+ });
130
116
  }
131
117
  end
132
118
 
@@ -134,8 +120,8 @@ class ::Hash
134
120
  other = ::Opal.coerce_to!(other, ::Hash, :to_hash)
135
121
 
136
122
  %x{
137
- if (self.$$keys.length < other.$$keys.length) {
138
- return false
123
+ if (self.size < other.size) {
124
+ return false;
139
125
  }
140
126
  }
141
127
 
@@ -159,8 +145,8 @@ class ::Hash
159
145
  other = ::Opal.coerce_to!(other, ::Hash, :to_hash)
160
146
 
161
147
  %x{
162
- if (self.$$keys.length <= other.$$keys.length) {
163
- return false
148
+ if (self.size <= other.size) {
149
+ return false;
164
150
  }
165
151
  }
166
152
 
@@ -200,21 +186,12 @@ class ::Hash
200
186
 
201
187
  def assoc(object)
202
188
  %x{
203
- for (var i = 0, keys = self.$$keys, length = keys.length, key; i < length; i++) {
204
- key = keys[i];
205
-
206
- if (key.$$is_string) {
207
- if (#{`key` == object}) {
208
- return [key, self.$$smap[key]];
209
- }
210
- } else {
211
- if (#{`key.key` == object}) {
212
- return [key.key, key.value];
213
- }
189
+ return $hash_each(self, nil, function(key, value) {
190
+ if (#{`key` == object}) {
191
+ return [true, [key, value]];
214
192
  }
215
- }
216
-
217
- return nil;
193
+ return [false, nil];
194
+ });
218
195
  }
219
196
  end
220
197
 
@@ -222,42 +199,31 @@ class ::Hash
222
199
  %x{
223
200
  $deny_frozen_access(self);
224
201
 
225
- $hash_init(self);
202
+ self.clear();
203
+ if (self.$$keys)
204
+ self.$$keys.clear();
205
+
226
206
  return self;
227
207
  }
228
208
  end
229
209
 
230
210
  def clone
231
211
  %x{
232
- var hash = new self.$$class();
233
-
234
- $hash_init(hash);
235
- Opal.hash_clone(self, hash);
236
-
237
- return hash;
212
+ var hash = self.$class().$new();
213
+ return $hash_clone(self, hash);
238
214
  }
239
215
  end
240
216
 
241
217
  def compact
242
218
  %x{
243
- var hash = $hash();
244
-
245
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value, obj; i < length; i++) {
246
- key = keys[i];
247
-
248
- if (key.$$is_string) {
249
- value = self.$$smap[key];
250
- } else {
251
- value = key.value;
252
- key = key.key;
253
- }
219
+ var hash = new Map();
254
220
 
221
+ return $hash_each(self, hash, function(key, value) {
255
222
  if (value !== nil) {
256
223
  $hash_put(hash, key, value);
257
224
  }
258
- }
259
-
260
- return hash;
225
+ return [false, hash];
226
+ });
261
227
  }
262
228
  end
263
229
 
@@ -265,28 +231,15 @@ class ::Hash
265
231
  %x{
266
232
  $deny_frozen_access(self);
267
233
 
268
- var changes_were_made = false;
269
-
270
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value, obj; i < length; i++) {
271
- key = keys[i];
272
-
273
- if (key.$$is_string) {
274
- value = self.$$smap[key];
275
- } else {
276
- value = key.value;
277
- key = key.key;
278
- }
234
+ var result = nil;
279
235
 
236
+ return $hash_each(self, result, function(key, value) {
280
237
  if (value === nil) {
281
- if ($hash_delete(self, key) !== undefined) {
282
- changes_were_made = true;
283
- length--;
284
- i--;
285
- }
238
+ $hash_delete(self, key);
239
+ result = self;
286
240
  }
287
- }
288
-
289
- return changes_were_made ? self : nil;
241
+ return [false, result];
242
+ });
290
243
  }
291
244
  end
292
245
 
@@ -294,24 +247,13 @@ class ::Hash
294
247
  %x{
295
248
  $deny_frozen_access(self);
296
249
 
297
- var i, ii, key, keys = self.$$keys, identity_hash;
298
-
299
- if (self.$$by_identity) return self;
300
- if (self.$$keys.length === 0) {
301
- self.$$by_identity = true
302
- return self;
303
- }
250
+ if (!self.$$by_identity) {
251
+ self.$$by_identity = true;
304
252
 
305
- identity_hash = #{ {}.compare_by_identity };
306
- for(i = 0, ii = keys.length; i < ii; i++) {
307
- key = keys[i];
308
- if (!key.$$is_string) key = key.key;
309
- $hash_put(identity_hash, key, $hash_get(self, key));
253
+ if (self.size !== 0)
254
+ Opal.hash_rehash(self);
310
255
  }
311
256
 
312
- self.$$by_identity = true;
313
- self.$$map = identity_hash.$$map;
314
- self.$$smap = identity_hash.$$smap;
315
257
  return self;
316
258
  }
317
259
  end
@@ -396,27 +338,14 @@ class ::Hash
396
338
  %x{
397
339
  $deny_frozen_access(self);
398
340
 
399
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value, obj; i < length; i++) {
400
- key = keys[i];
401
-
402
- if (key.$$is_string) {
403
- value = self.$$smap[key];
404
- } else {
405
- value = key.value;
406
- key = key.key;
407
- }
408
-
409
- obj = block(key, value);
341
+ return $hash_each(self, self, function(key, value) {
342
+ var obj = block(key, value);
410
343
 
411
344
  if (obj !== false && obj !== nil) {
412
- if ($hash_delete(self, key) !== undefined) {
413
- length--;
414
- i--;
415
- }
345
+ $hash_delete(self, key);
416
346
  }
417
- }
418
-
419
- return self;
347
+ return [false, self];
348
+ });
420
349
  }
421
350
  end
422
351
 
@@ -440,20 +369,10 @@ class ::Hash
440
369
  return enum_for(:each) { size } unless block
441
370
 
442
371
  %x{
443
- for (var i = 0, keys = self.$$keys.slice(), length = keys.length, key, value; i < length; i++) {
444
- key = keys[i];
445
-
446
- if (key.$$is_string) {
447
- value = self.$$smap[key];
448
- } else {
449
- value = key.value;
450
- key = key.key;
451
- }
452
-
372
+ return $hash_each(self, self, function(key, value) {
453
373
  $yield1(block, [key, value]);
454
- }
455
-
456
- return self;
374
+ return [false, self];
375
+ });
457
376
  }
458
377
  end
459
378
 
@@ -461,13 +380,10 @@ class ::Hash
461
380
  return enum_for(:each_key) { size } unless block
462
381
 
463
382
  %x{
464
- for (var i = 0, keys = self.$$keys.slice(), length = keys.length, key; i < length; i++) {
465
- key = keys[i];
466
-
467
- block(key.$$is_string ? key : key.key);
468
- }
469
-
470
- return self;
383
+ return $hash_each(self, self, function(key, value) {
384
+ block(key);
385
+ return [false, self];
386
+ });
471
387
  }
472
388
  end
473
389
 
@@ -475,18 +391,15 @@ class ::Hash
475
391
  return enum_for(:each_value) { size } unless block
476
392
 
477
393
  %x{
478
- for (var i = 0, keys = self.$$keys.slice(), length = keys.length, key; i < length; i++) {
479
- key = keys[i];
480
-
481
- block(key.$$is_string ? self.$$smap[key] : key.value);
482
- }
483
-
484
- return self;
394
+ return $hash_each(self, self, function(key, value) {
395
+ block(value);
396
+ return [false, self];
397
+ });
485
398
  }
486
399
  end
487
400
 
488
401
  def empty?
489
- `self.$$keys.length === 0`
402
+ `self.size === 0`
490
403
  end
491
404
 
492
405
  def except(*keys)
@@ -528,32 +441,22 @@ class ::Hash
528
441
  %x{
529
442
  var result = [];
530
443
 
531
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
532
- key = keys[i];
533
-
534
- if (key.$$is_string) {
535
- value = self.$$smap[key];
536
- } else {
537
- value = key.value;
538
- key = key.key;
539
- }
540
-
444
+ return $hash_each(self, result, function(key, value) {
541
445
  result.push(key);
542
446
 
543
447
  if (value.$$is_array) {
544
448
  if (level === 1) {
545
449
  result.push(value);
546
- continue;
450
+ return [false, result];
547
451
  }
548
452
 
549
453
  result = result.concat(#{`value`.flatten(`level - 2`)});
550
- continue;
454
+ return [false, result];
551
455
  }
552
456
 
553
457
  result.push(value);
554
- }
555
-
556
- return result;
458
+ return [false, result];
459
+ });
557
460
  }
558
461
  end
559
462
 
@@ -569,15 +472,12 @@ class ::Hash
569
472
 
570
473
  def has_value?(value)
571
474
  %x{
572
- for (var i = 0, keys = self.$$keys, length = keys.length, key; i < length; i++) {
573
- key = keys[i];
574
-
575
- if (#{`(key.$$is_string ? self.$$smap[key] : key.value)` == value}) {
576
- return true;
475
+ return $hash_each(self, false, function(key, val) {
476
+ if (#{`val` == value}) {
477
+ return [true, true];
577
478
  }
578
- }
579
-
580
- return false;
479
+ return [false, false];
480
+ });
581
481
  }
582
482
  end
583
483
 
@@ -606,15 +506,10 @@ class ::Hash
606
506
 
607
507
  Opal.hash_ids[hash_id] = self;
608
508
 
609
- for (var i = 0, keys = self.$$keys, length = keys.length; i < length; i++) {
610
- key = keys[i];
611
-
612
- if (key.$$is_string) {
613
- result.push([key, self.$$smap[key].$hash()]);
614
- } else {
615
- result.push([key.key_hash, key.value.$hash()]);
616
- }
617
- }
509
+ $hash_each(self, false, function(key, value) {
510
+ result.push([key, value.$hash()]);
511
+ return [false, false];
512
+ });
618
513
 
619
514
  return result.sort().join();
620
515
 
@@ -628,22 +523,12 @@ class ::Hash
628
523
 
629
524
  def index(object)
630
525
  %x{
631
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
632
- key = keys[i];
633
-
634
- if (key.$$is_string) {
635
- value = self.$$smap[key];
636
- } else {
637
- value = key.value;
638
- key = key.key;
639
- }
640
-
526
+ return $hash_each(self, nil, function(key, value) {
641
527
  if (#{`value` == object}) {
642
- return key;
528
+ return [true, key];
643
529
  }
644
- }
645
-
646
- return nil;
530
+ return [false, nil];
531
+ });
647
532
  }
648
533
  end
649
534
 
@@ -688,21 +573,13 @@ class ::Hash
688
573
 
689
574
  inspect_ids[hash_id] = true;
690
575
 
691
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
692
- key = keys[i];
693
-
694
- if (key.$$is_string) {
695
- value = self.$$smap[key];
696
- } else {
697
- value = key.value;
698
- key = key.key;
699
- }
700
-
701
- key = #{Opal.inspect(`key`)}
576
+ $hash_each(self, false, function(key, value) {
702
577
  value = #{Opal.inspect(`value`)}
578
+ key = #{Opal.inspect(`key`)}
703
579
 
704
580
  result.push(key + '=>' + value);
705
- }
581
+ return [false, false];
582
+ })
706
583
 
707
584
  return '{' + result.join(', ') + '}';
708
585
  }
@@ -714,22 +591,12 @@ class ::Hash
714
591
 
715
592
  def invert
716
593
  %x{
717
- var hash = $hash();
718
-
719
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
720
- key = keys[i];
721
-
722
- if (key.$$is_string) {
723
- value = self.$$smap[key];
724
- } else {
725
- value = key.value;
726
- key = key.key;
727
- }
594
+ var hash = new Map();
728
595
 
596
+ return $hash_each(self, hash, function(key, value) {
729
597
  $hash_put(hash, value, key);
730
- }
731
-
732
- return hash;
598
+ return [false, hash];
599
+ });
733
600
  }
734
601
  end
735
602
 
@@ -739,50 +606,23 @@ class ::Hash
739
606
  %x{
740
607
  $deny_frozen_access(self);
741
608
 
742
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value, obj; i < length; i++) {
743
- key = keys[i];
744
-
745
- if (key.$$is_string) {
746
- value = self.$$smap[key];
747
- } else {
748
- value = key.value;
749
- key = key.key;
750
- }
751
-
752
- obj = block(key, value);
609
+ return $hash_each(self, self, function(key, value) {
610
+ var obj = block(key, value);
753
611
 
754
612
  if (obj === false || obj === nil) {
755
- if ($hash_delete(self, key) !== undefined) {
756
- length--;
757
- i--;
758
- }
613
+ $hash_delete(self, key);
759
614
  }
760
- }
761
-
762
- return self;
615
+ return [false, self];
616
+ });
763
617
  }
764
618
  end
765
619
 
766
620
  def keys
767
- %x{
768
- var result = [];
769
-
770
- for (var i = 0, keys = self.$$keys, length = keys.length, key; i < length; i++) {
771
- key = keys[i];
772
-
773
- if (key.$$is_string) {
774
- result.push(key);
775
- } else {
776
- result.push(key.key);
777
- }
778
- }
779
-
780
- return result;
781
- }
621
+ `Array.from(self.keys())`
782
622
  end
783
623
 
784
624
  def length
785
- `self.$$keys.length`
625
+ `self.size`
786
626
  end
787
627
 
788
628
  def merge(*others, &block)
@@ -792,44 +632,28 @@ class ::Hash
792
632
  def merge!(*others, &block)
793
633
  %x{
794
634
  $deny_frozen_access(self);
795
- var i, j, other, other_keys, length, key, value, other_value;
635
+
636
+ var i, j, other;
796
637
  for (i = 0; i < others.length; ++i) {
797
638
  other = #{::Opal.coerce_to!(`others[i]`, ::Hash, :to_hash)};
798
- other_keys = other.$$keys, length = other_keys.length;
799
639
 
800
640
  if (block === nil) {
801
- for (j = 0; j < length; j++) {
802
- key = other_keys[j];
803
-
804
- if (key.$$is_string) {
805
- other_value = other.$$smap[key];
806
- } else {
807
- other_value = key.value;
808
- key = key.key;
809
- }
810
-
811
- $hash_put(self, key, other_value);
812
- }
641
+ $hash_each(other, false, function(key, value) {
642
+ $hash_put(self, key, value);
643
+ return [false, false];
644
+ });
813
645
  } else {
814
- for (j = 0; j < length; j++) {
815
- key = other_keys[j];
816
-
817
- if (key.$$is_string) {
818
- other_value = other.$$smap[key];
819
- } else {
820
- other_value = key.value;
821
- key = key.key;
822
- }
646
+ $hash_each(other, false, function(key, value) {
647
+ var val = $hash_get(self, key);
823
648
 
824
- value = $hash_get(self, key);
825
-
826
- if (value === undefined) {
827
- $hash_put(self, key, other_value);
828
- continue;
649
+ if (val === undefined) {
650
+ $hash_put(self, key, value);
651
+ return [false, false];
829
652
  }
830
653
 
831
- $hash_put(self, key, block(key, value, other_value));
832
- }
654
+ $hash_put(self, key, block(key, val, value));
655
+ return [false, false];
656
+ });
833
657
  }
834
658
  }
835
659
 
@@ -839,30 +663,19 @@ class ::Hash
839
663
 
840
664
  def rassoc(object)
841
665
  %x{
842
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
843
- key = keys[i];
844
-
845
- if (key.$$is_string) {
846
- value = self.$$smap[key];
847
- } else {
848
- value = key.value;
849
- key = key.key;
850
- }
851
-
666
+ return $hash_each(self, nil, function(key, value) {
852
667
  if (#{`value` == object}) {
853
- return [key, value];
668
+ return [true, [key, value]];
854
669
  }
855
- }
856
-
857
- return nil;
670
+ return [false, nil];
671
+ });
858
672
  }
859
673
  end
860
674
 
861
675
  def rehash
862
676
  %x{
863
677
  $deny_frozen_access(self);
864
- Opal.hash_rehash(self);
865
- return self;
678
+ return Opal.hash_rehash(self);
866
679
  }
867
680
  end
868
681
 
@@ -870,26 +683,16 @@ class ::Hash
870
683
  return enum_for(:reject) { size } unless block
871
684
 
872
685
  %x{
873
- var hash = $hash();
874
-
875
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value, obj; i < length; i++) {
876
- key = keys[i];
877
-
878
- if (key.$$is_string) {
879
- value = self.$$smap[key];
880
- } else {
881
- value = key.value;
882
- key = key.key;
883
- }
686
+ var hash = new Map();
884
687
 
885
- obj = block(key, value);
688
+ return $hash_each(self, hash, function(key, value) {
689
+ var obj = block(key, value);
886
690
 
887
691
  if (obj === false || obj === nil) {
888
692
  $hash_put(hash, key, value);
889
693
  }
890
- }
891
-
892
- return hash;
694
+ return [false, hash]
695
+ });
893
696
  }
894
697
  end
895
698
 
@@ -899,30 +702,17 @@ class ::Hash
899
702
  %x{
900
703
  $deny_frozen_access(self);
901
704
 
902
- var changes_were_made = false;
903
-
904
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value, obj; i < length; i++) {
905
- key = keys[i];
906
-
907
- if (key.$$is_string) {
908
- value = self.$$smap[key];
909
- } else {
910
- value = key.value;
911
- key = key.key;
912
- }
705
+ var result = nil;
913
706
 
914
- obj = block(key, value);
707
+ return $hash_each(self, result, function(key, value) {
708
+ var obj = block(key, value);
915
709
 
916
710
  if (obj !== false && obj !== nil) {
917
- if ($hash_delete(self, key) !== undefined) {
918
- changes_were_made = true;
919
- length--;
920
- i--;
921
- }
711
+ $hash_delete(self, key);
712
+ result = self;
922
713
  }
923
- }
924
-
925
- return changes_were_made ? self : nil;
714
+ return [false, result];
715
+ });
926
716
  }
927
717
  end
928
718
 
@@ -932,20 +722,12 @@ class ::Hash
932
722
  other = ::Opal.coerce_to!(other, ::Hash, :to_hash)
933
723
 
934
724
  %x{
935
- $hash_init(self);
725
+ self.$clear();
936
726
 
937
- for (var i = 0, other_keys = other.$$keys, length = other_keys.length, key, value, other_value; i < length; i++) {
938
- key = other_keys[i];
939
-
940
- if (key.$$is_string) {
941
- other_value = other.$$smap[key];
942
- } else {
943
- other_value = key.value;
944
- key = key.key;
945
- }
946
-
947
- $hash_put(self, key, other_value);
948
- }
727
+ $hash_each(other, false, function(key, value) {
728
+ $hash_put(self, key, value);
729
+ return [false, false];
730
+ });
949
731
  }
950
732
 
951
733
  if other.default_proc
@@ -961,26 +743,16 @@ class ::Hash
961
743
  return enum_for(:select) { size } unless block
962
744
 
963
745
  %x{
964
- var hash = $hash();
965
-
966
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value, obj; i < length; i++) {
967
- key = keys[i];
746
+ var hash = new Map();
968
747
 
969
- if (key.$$is_string) {
970
- value = self.$$smap[key];
971
- } else {
972
- value = key.value;
973
- key = key.key;
974
- }
975
-
976
- obj = block(key, value);
748
+ return $hash_each(self, hash, function(key, value) {
749
+ var obj = block(key, value);
977
750
 
978
751
  if (obj !== false && obj !== nil) {
979
752
  $hash_put(hash, key, value);
980
753
  }
981
- }
982
-
983
- return hash;
754
+ return [false, hash];
755
+ });
984
756
  }
985
757
  end
986
758
 
@@ -992,52 +764,31 @@ class ::Hash
992
764
 
993
765
  var result = nil;
994
766
 
995
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value, obj; i < length; i++) {
996
- key = keys[i];
997
-
998
- if (key.$$is_string) {
999
- value = self.$$smap[key];
1000
- } else {
1001
- value = key.value;
1002
- key = key.key;
1003
- }
1004
-
1005
- obj = block(key, value);
767
+ return $hash_each(self, result, function(key, value) {
768
+ var obj = block(key, value);
1006
769
 
1007
770
  if (obj === false || obj === nil) {
1008
- if ($hash_delete(self, key) !== undefined) {
1009
- length--;
1010
- i--;
1011
- }
771
+ $hash_delete(self, key);
1012
772
  result = self;
1013
773
  }
1014
- }
1015
-
1016
- return result;
774
+ return [false, result];
775
+ });
1017
776
  }
1018
777
  end
1019
778
 
1020
779
  def shift
1021
780
  %x{
1022
781
  $deny_frozen_access(self);
1023
- var keys = self.$$keys,
1024
- key;
1025
782
 
1026
- if (keys.length > 0) {
1027
- key = keys[0];
1028
-
1029
- key = key.$$is_string ? key : key.key;
1030
-
1031
- return [key, $hash_delete(self, key)];
1032
- }
1033
-
1034
- return nil;
783
+ return $hash_each(self, nil, function(key, value) {
784
+ return [true, [key, $hash_delete(self, key)]];
785
+ });
1035
786
  }
1036
787
  end
1037
788
 
1038
789
  def slice(*keys)
1039
790
  %x{
1040
- var result = $hash();
791
+ var result = new Map();
1041
792
 
1042
793
  for (var i = 0, length = keys.length; i < length; i++) {
1043
794
  var key = keys[i], value = $hash_get(self, key);
@@ -1055,20 +806,10 @@ class ::Hash
1055
806
  %x{
1056
807
  var result = [];
1057
808
 
1058
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
1059
- key = keys[i];
1060
-
1061
- if (key.$$is_string) {
1062
- value = self.$$smap[key];
1063
- } else {
1064
- value = key.value;
1065
- key = key.key;
1066
- }
1067
-
809
+ return $hash_each(self, result, function(key, value) {
1068
810
  result.push([key, value]);
1069
- }
1070
-
1071
- return result;
811
+ return [false, result];
812
+ });
1072
813
  }
1073
814
  end
1074
815
 
@@ -1080,10 +821,9 @@ class ::Hash
1080
821
  return self;
1081
822
  }
1082
823
 
1083
- var hash = new Opal.Hash();
824
+ var hash = new Map();
1084
825
 
1085
- $hash_init(hash);
1086
- Opal.hash_clone(self, hash);
826
+ $hash_clone(self, hash);
1087
827
 
1088
828
  return hash;
1089
829
  }
@@ -1105,57 +845,48 @@ class ::Hash
1105
845
  end
1106
846
  end
1107
847
 
1108
- def transform_keys(&block)
1109
- return enum_for(:transform_keys) { size } unless block
848
+ def transform_keys(keys_hash = nil, &block)
849
+ return enum_for(:transform_keys) { size } if !block && !keys_hash
1110
850
 
1111
851
  %x{
1112
- var result = $hash();
1113
-
1114
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
1115
- key = keys[i];
1116
-
1117
- if (key.$$is_string) {
1118
- value = self.$$smap[key];
1119
- } else {
1120
- value = key.value;
1121
- key = key.key;
1122
- }
852
+ var result = new Map();
1123
853
 
1124
- key = $yield1(block, key);
1125
-
1126
- $hash_put(result, key, value);
1127
- }
1128
-
1129
- return result;
854
+ return $hash_each(self, result, function(key, value) {
855
+ var new_key;
856
+ if (keys_hash !== nil)
857
+ new_key = $hash_get(keys_hash, key);
858
+ if (new_key === undefined && block && block !== nil)
859
+ new_key = block(key);
860
+ if (new_key === undefined)
861
+ new_key = key // key not modified
862
+ $hash_put(result, new_key, value);
863
+ return [false, result];
864
+ });
1130
865
  }
1131
866
  end
1132
867
 
1133
- def transform_keys!(&block)
1134
- return enum_for(:transform_keys!) { size } unless block
868
+ def transform_keys!(keys_hash = nil, &block)
869
+ return enum_for(:transform_keys!) { size } if !block && !keys_hash
1135
870
 
1136
871
  %x{
1137
872
  $deny_frozen_access(self);
1138
873
 
1139
- var keys = Opal.slice(self.$$keys),
1140
- i, length = keys.length, key, value, new_key;
1141
-
1142
- for (i = 0; i < length; i++) {
1143
- key = keys[i];
1144
-
1145
- if (key.$$is_string) {
1146
- value = self.$$smap[key];
1147
- } else {
1148
- value = key.value;
1149
- key = key.key;
1150
- }
1151
-
1152
- new_key = $yield1(block, key);
1153
-
1154
- $hash_delete(self, key);
874
+ var modified_keys = new Map();
875
+
876
+ return $hash_each(self, self, function(key, value) {
877
+ var new_key;
878
+ if (keys_hash !== nil)
879
+ new_key = $hash_get(keys_hash, key);
880
+ if (new_key === undefined && block && block !== nil)
881
+ new_key = block(key);
882
+ if (new_key === undefined)
883
+ return [false, self]; // key not modified
884
+ if (!$hash_get(modified_keys, key))
885
+ $hash_delete(self, key);
1155
886
  $hash_put(self, new_key, value);
1156
- }
1157
-
1158
- return self;
887
+ $hash_put(modified_keys, new_key, true)
888
+ return [false, self];
889
+ });
1159
890
  }
1160
891
  end
1161
892
 
@@ -1163,24 +894,12 @@ class ::Hash
1163
894
  return enum_for(:transform_values) { size } unless block
1164
895
 
1165
896
  %x{
1166
- var result = $hash();
1167
-
1168
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
1169
- key = keys[i];
1170
-
1171
- if (key.$$is_string) {
1172
- value = self.$$smap[key];
1173
- } else {
1174
- value = key.value;
1175
- key = key.key;
1176
- }
1177
-
1178
- value = $yield1(block, value);
1179
-
1180
- $hash_put(result, key, value);
1181
- }
897
+ var result = new Map();
1182
898
 
1183
- return result;
899
+ return $hash_each(self, result, function(key, value) {
900
+ $hash_put(result, key, block(value));
901
+ return [false, result];
902
+ });
1184
903
  }
1185
904
  end
1186
905
 
@@ -1190,41 +909,15 @@ class ::Hash
1190
909
  %x{
1191
910
  $deny_frozen_access(self);
1192
911
 
1193
- for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
1194
- key = keys[i];
1195
-
1196
- if (key.$$is_string) {
1197
- value = self.$$smap[key];
1198
- } else {
1199
- value = key.value;
1200
- key = key.key;
1201
- }
1202
-
1203
- value = $yield1(block, value);
1204
-
1205
- $hash_put(self, key, value);
1206
- }
1207
-
1208
- return self;
912
+ return $hash_each(self, self, function(key, value) {
913
+ $hash_put(self, key, block(value));
914
+ return [false, self];
915
+ });
1209
916
  }
1210
917
  end
1211
918
 
1212
919
  def values
1213
- %x{
1214
- var result = [];
1215
-
1216
- for (var i = 0, keys = self.$$keys, length = keys.length, key; i < length; i++) {
1217
- key = keys[i];
1218
-
1219
- if (key.$$is_string) {
1220
- result.push(self.$$smap[key]);
1221
- } else {
1222
- result.push(key.value);
1223
- }
1224
- }
1225
-
1226
- return result;
1227
- }
920
+ `Array.from(self.values())`
1228
921
  end
1229
922
 
1230
923
  alias dup clone