opal 1.7.2 → 1.8.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +1 -0
  3. data/.github/workflows/build.yml +9 -9
  4. data/.rubocop/todo.yml +2 -2
  5. data/.rubocop.yml +17 -10
  6. data/.rubocop_todo.yml +311 -0
  7. data/CHANGELOG.md +16 -2
  8. data/UNRELEASED.md +78 -1
  9. data/benchmark-ips/bm_block_vs_yield.rb +3 -0
  10. data/benchmark-ips/bm_slice_or_not.rb +53 -0
  11. data/docs/bridging.md +112 -0
  12. data/docs/compiled_ruby.md +10 -10
  13. data/docs/getting_started.md +18 -22
  14. data/docs/index.md +1 -1
  15. data/lib/opal/builder_scheduler/prefork.rb +2 -2
  16. data/lib/opal/cache/file_cache.rb +7 -10
  17. data/lib/opal/cli_runners/chrome_cdp_interface.rb +5 -2
  18. data/lib/opal/cli_runners/firefox_cdp_interface.rb +5 -2
  19. data/lib/opal/compiler.rb +33 -1
  20. data/lib/opal/nodes/args/extract_kwoptarg.rb +2 -1
  21. data/lib/opal/nodes/call.rb +1 -1
  22. data/lib/opal/nodes/call_special.rb +71 -47
  23. data/lib/opal/nodes/hash.rb +14 -30
  24. data/lib/opal/nodes/if.rb +38 -30
  25. data/lib/opal/nodes/literal.rb +5 -1
  26. data/lib/opal/nodes/x_string.rb +13 -0
  27. data/lib/opal/parser/patch.rb +7 -0
  28. data/lib/opal/rewriters/for_rewriter.rb +36 -24
  29. data/lib/opal/source_map/file.rb +1 -1
  30. data/lib/opal/version.rb +1 -1
  31. data/opal/corelib/array/pack.rb +1 -0
  32. data/opal/corelib/array.rb +75 -47
  33. data/opal/corelib/basic_object.rb +1 -0
  34. data/opal/corelib/binding.rb +2 -0
  35. data/opal/corelib/boolean.rb +1 -0
  36. data/opal/corelib/class.rb +2 -0
  37. data/opal/corelib/comparable.rb +1 -0
  38. data/opal/corelib/complex.rb +2 -0
  39. data/opal/corelib/constants.rb +2 -2
  40. data/opal/corelib/dir.rb +2 -0
  41. data/opal/corelib/enumerable.rb +3 -2
  42. data/opal/corelib/enumerator/arithmetic_sequence.rb +2 -0
  43. data/opal/corelib/enumerator/chain.rb +1 -0
  44. data/opal/corelib/enumerator/generator.rb +1 -0
  45. data/opal/corelib/enumerator/lazy.rb +1 -0
  46. data/opal/corelib/enumerator/yielder.rb +2 -0
  47. data/opal/corelib/enumerator.rb +1 -0
  48. data/opal/corelib/error/errno.rb +2 -0
  49. data/opal/corelib/error.rb +12 -0
  50. data/opal/corelib/file.rb +1 -0
  51. data/opal/corelib/hash.rb +197 -504
  52. data/opal/corelib/helpers.rb +1 -0
  53. data/opal/corelib/io.rb +2 -0
  54. data/opal/corelib/irb.rb +2 -0
  55. data/opal/corelib/kernel/format.rb +1 -0
  56. data/opal/corelib/kernel.rb +70 -14
  57. data/opal/corelib/main.rb +2 -0
  58. data/opal/corelib/marshal/read_buffer.rb +2 -0
  59. data/opal/corelib/marshal/write_buffer.rb +2 -0
  60. data/opal/corelib/math/polyfills.rb +2 -0
  61. data/opal/corelib/math.rb +1 -0
  62. data/opal/corelib/method.rb +2 -0
  63. data/opal/corelib/module.rb +1 -0
  64. data/opal/corelib/nil.rb +3 -1
  65. data/opal/corelib/number.rb +2 -0
  66. data/opal/corelib/numeric.rb +2 -0
  67. data/opal/corelib/object_space.rb +1 -0
  68. data/opal/corelib/pack_unpack/format_string_parser.rb +2 -0
  69. data/opal/corelib/proc.rb +30 -28
  70. data/opal/corelib/process.rb +2 -0
  71. data/opal/corelib/random/formatter.rb +2 -0
  72. data/opal/corelib/random/math_random.js.rb +2 -0
  73. data/opal/corelib/random/mersenne_twister.rb +2 -0
  74. data/opal/corelib/random/seedrandom.js.rb +2 -0
  75. data/opal/corelib/random.rb +1 -0
  76. data/opal/corelib/range.rb +34 -12
  77. data/opal/corelib/rational.rb +2 -0
  78. data/opal/corelib/regexp.rb +5 -1
  79. data/opal/corelib/runtime.js +188 -224
  80. data/opal/corelib/set.rb +2 -0
  81. data/opal/corelib/string/encoding.rb +3 -0
  82. data/opal/corelib/string/unpack.rb +2 -0
  83. data/opal/corelib/string.rb +20 -12
  84. data/opal/corelib/struct.rb +3 -1
  85. data/opal/corelib/time.rb +1 -0
  86. data/opal/corelib/trace_point.rb +2 -0
  87. data/opal/corelib/unsupported.rb +2 -0
  88. data/opal/corelib/variables.rb +2 -0
  89. data/opal.gemspec +2 -2
  90. data/spec/filters/bugs/array.rb +0 -3
  91. data/spec/filters/bugs/enumerable.rb +0 -3
  92. data/spec/filters/bugs/hash.rb +0 -13
  93. data/spec/filters/bugs/integer.rb +0 -1
  94. data/spec/filters/bugs/kernel.rb +0 -39
  95. data/spec/filters/bugs/language.rb +0 -3
  96. data/spec/filters/bugs/range.rb +0 -1
  97. data/spec/filters/bugs/ruby-32.rb +0 -2
  98. data/spec/filters/bugs/string.rb +0 -1
  99. data/spec/filters/bugs/struct.rb +1 -5
  100. data/spec/filters/unsupported/hash.rb +1 -0
  101. data/spec/lib/compiler_spec.rb +24 -17
  102. data/spec/mspec-opal/formatters.rb +2 -0
  103. data/spec/mspec-opal/runner.rb +2 -0
  104. data/spec/opal/core/array/dup_spec.rb +2 -0
  105. data/spec/opal/core/exception_spec.rb +2 -0
  106. data/spec/opal/core/hash/internals_spec.rb +154 -206
  107. data/spec/opal/core/hash_spec.rb +2 -0
  108. data/spec/opal/core/iterable_props_spec.rb +2 -0
  109. data/spec/opal/core/kernel/at_exit_spec.rb +2 -0
  110. data/spec/opal/core/kernel/respond_to_spec.rb +2 -0
  111. data/spec/opal/core/language/arguments/mlhs_arg_spec.rb +2 -0
  112. data/spec/opal/core/language/case_spec.rb +13 -0
  113. data/spec/opal/core/language/safe_navigator_spec.rb +2 -0
  114. data/spec/opal/core/language/xstring_send_spec.rb +15 -0
  115. data/spec/opal/core/language/xstring_spec.rb +2 -0
  116. data/spec/opal/core/language_spec.rb +2 -0
  117. data/spec/opal/core/module_spec.rb +44 -0
  118. data/spec/opal/core/number/to_i_spec.rb +2 -0
  119. data/spec/opal/core/object_id_spec.rb +2 -0
  120. data/spec/opal/core/regexp/match_spec.rb +2 -0
  121. data/spec/opal/core/runtime/bridged_classes_spec.rb +38 -0
  122. data/spec/opal/core/runtime/constants_spec.rb +2 -0
  123. data/spec/opal/core/runtime/eval_spec.rb +2 -0
  124. data/spec/opal/core/runtime/exit_spec.rb +2 -0
  125. data/spec/opal/core/runtime/is_a_spec.rb +2 -0
  126. data/spec/opal/core/runtime/loaded_spec.rb +2 -0
  127. data/spec/opal/core/runtime/method_missing_spec.rb +2 -0
  128. data/spec/opal/core/runtime/rescue_spec.rb +2 -0
  129. data/spec/opal/core/runtime/string_spec.rb +2 -0
  130. data/spec/opal/core/runtime/truthy_spec.rb +2 -0
  131. data/spec/opal/core/runtime_spec.rb +2 -6
  132. data/spec/opal/core/string/to_sym_spec.rb +2 -0
  133. data/spec/opal/stdlib/js_spec.rb +2 -0
  134. data/spec/opal/stdlib/native/alias_native_spec.rb +2 -0
  135. data/spec/opal/stdlib/native/array_spec.rb +2 -0
  136. data/spec/opal/stdlib/native/date_spec.rb +2 -0
  137. data/spec/opal/stdlib/native/each_spec.rb +2 -0
  138. data/spec/opal/stdlib/native/element_reference_spec.rb +2 -0
  139. data/spec/opal/stdlib/native/exposure_spec.rb +2 -0
  140. data/spec/opal/stdlib/native/ext_spec.rb +2 -0
  141. data/spec/opal/stdlib/native/hash_spec.rb +30 -2
  142. data/spec/opal/stdlib/native/initialize_spec.rb +2 -0
  143. data/spec/opal/stdlib/native/method_missing_spec.rb +2 -0
  144. data/spec/opal/stdlib/native/native_alias_spec.rb +2 -0
  145. data/spec/opal/stdlib/native/native_class_spec.rb +2 -0
  146. data/spec/opal/stdlib/native/native_module_spec.rb +2 -0
  147. data/spec/opal/stdlib/native/native_reader_spec.rb +2 -0
  148. data/spec/opal/stdlib/native/native_writer_spec.rb +2 -0
  149. data/spec/opal/stdlib/native/new_spec.rb +2 -0
  150. data/spec/opal/stdlib/native/struct_spec.rb +2 -0
  151. data/spec/spec_helper.rb +2 -0
  152. data/stdlib/await.rb +1 -0
  153. data/stdlib/base64.rb +2 -0
  154. data/stdlib/bigdecimal/bignumber.js.rb +2 -0
  155. data/stdlib/bigdecimal/util.rb +1 -0
  156. data/stdlib/bigdecimal.rb +2 -0
  157. data/stdlib/buffer/array.rb +2 -0
  158. data/stdlib/buffer/view.rb +2 -0
  159. data/stdlib/buffer.rb +2 -0
  160. data/stdlib/cgi.rb +14 -0
  161. data/stdlib/console.rb +2 -0
  162. data/stdlib/date/date_time.rb +2 -0
  163. data/stdlib/date.rb +2 -0
  164. data/stdlib/delegate.rb +2 -0
  165. data/stdlib/deno/base.rb +2 -0
  166. data/stdlib/deno/file.rb +2 -0
  167. data/stdlib/erb.rb +2 -0
  168. data/stdlib/gjs/io.rb +2 -0
  169. data/stdlib/gjs/kernel.rb +2 -0
  170. data/stdlib/headless_browser/base.rb +2 -0
  171. data/stdlib/headless_browser/file.rb +1 -0
  172. data/stdlib/headless_browser.rb +1 -0
  173. data/stdlib/js.rb +2 -0
  174. data/stdlib/json.rb +9 -15
  175. data/stdlib/logger.rb +2 -0
  176. data/stdlib/nashorn/file.rb +2 -0
  177. data/stdlib/nashorn/io.rb +2 -0
  178. data/stdlib/native.rb +48 -48
  179. data/stdlib/nodejs/base.rb +2 -0
  180. data/stdlib/nodejs/dir.rb +2 -0
  181. data/stdlib/nodejs/env.rb +2 -0
  182. data/stdlib/nodejs/file.rb +2 -0
  183. data/stdlib/nodejs/fileutils.rb +2 -0
  184. data/stdlib/nodejs/io.rb +2 -0
  185. data/stdlib/nodejs/js-yaml-3-6-1.js +1 -1
  186. data/stdlib/nodejs/kernel.rb +2 -0
  187. data/stdlib/nodejs/open-uri.rb +2 -0
  188. data/stdlib/nodejs/pathname.rb +2 -0
  189. data/stdlib/nodejs/require.rb +2 -0
  190. data/stdlib/nodejs/yaml.rb +9 -3
  191. data/stdlib/opal/miniracer.rb +2 -0
  192. data/stdlib/opal-parser.rb +8 -1
  193. data/stdlib/opal-platform.rb +2 -0
  194. data/stdlib/opal-replutils.rb +2 -0
  195. data/stdlib/open-uri.rb +4 -1
  196. data/stdlib/ostruct.rb +4 -2
  197. data/stdlib/pathname.rb +2 -0
  198. data/stdlib/pp.rb +1 -0
  199. data/stdlib/promise/v2.rb +2 -0
  200. data/stdlib/quickjs/io.rb +2 -0
  201. data/stdlib/quickjs/kernel.rb +2 -0
  202. data/stdlib/quickjs.rb +2 -0
  203. data/stdlib/securerandom.rb +2 -0
  204. data/stdlib/strscan.rb +2 -0
  205. data/stdlib/time.rb +2 -0
  206. data/stdlib/uri.rb +1 -0
  207. data/tasks/performance/optimization_status.rb +2 -0
  208. data/tasks/testing.rake +1 -0
  209. data/test/nodejs/test_await.rb +1 -0
  210. data/test/nodejs/test_dir.rb +2 -0
  211. data/test/nodejs/test_error.rb +2 -0
  212. data/test/nodejs/test_file.rb +2 -0
  213. data/test/nodejs/test_string.rb +2 -0
  214. data/test/nodejs/test_yaml.rb +20 -0
  215. metadata +24 -14
  216. 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