opal 0.3.27 → 0.3.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/.gitignore +2 -1
  2. data/CONTRIBUTING.md +24 -0
  3. data/README.md +6 -5
  4. data/Rakefile +12 -2
  5. data/core/array.rb +3 -31
  6. data/core/enumerable.rb +32 -4
  7. data/core/hash.rb +218 -186
  8. data/core/json.rb +3 -2
  9. data/core/kernel.rb +28 -28
  10. data/core/numeric.rb +2 -2
  11. data/core/runtime.js +0 -1
  12. data/lib/opal.rb +4 -2
  13. data/lib/opal/grammar.rb +6 -2
  14. data/lib/opal/grammar.y +3 -0
  15. data/lib/opal/lexer.rb +25 -10
  16. data/lib/opal/parser.rb +75 -34
  17. data/lib/opal/scope.rb +7 -7
  18. data/lib/opal/version.rb +1 -1
  19. data/opal.gemspec +1 -1
  20. data/spec/core/array/reduce_spec.rb +31 -0
  21. data/spec/{opal → core}/array/to_json_spec.rb +0 -0
  22. data/spec/core/boolean/and_spec.rb +17 -0
  23. data/spec/core/boolean/inspect_spec.rb +9 -0
  24. data/spec/core/boolean/or_spec.rb +17 -0
  25. data/spec/{opal → core}/boolean/singleton_class_spec.rb +0 -0
  26. data/spec/{opal → core}/boolean/to_json_spec.rb +1 -1
  27. data/spec/core/boolean/to_s_spec.rb +9 -0
  28. data/spec/core/boolean/xor_spec.rb +17 -0
  29. data/spec/{opal → core}/class/bridge_class_spec.rb +0 -0
  30. data/spec/{opal → core}/class/instance_methods_spec.rb +0 -0
  31. data/spec/core/class/last_value_spec.rb +68 -0
  32. data/spec/core/enumerable/detect_spec.rb +1 -1
  33. data/spec/core/enumerable/find_spec.rb +1 -1
  34. data/spec/{opal → core}/hash/to_json_spec.rb +0 -0
  35. data/spec/{opal → core}/hash/to_native_spec.rb +0 -0
  36. data/spec/{opal → core}/json/parse_spec.rb +0 -0
  37. data/spec/core/kernel/block_given.rb +30 -0
  38. data/spec/core/kernel/methods_spec.rb +11 -0
  39. data/spec/core/kernel/p_spec.rb +13 -0
  40. data/spec/{opal → core}/kernel/to_json_spec.rb +0 -0
  41. data/spec/{opal → core}/nil/to_json_spec.rb +0 -0
  42. data/spec/core/numeric/abs_spec.rb +12 -0
  43. data/spec/core/numeric/bit_and_spec.rb +7 -0
  44. data/spec/core/numeric/bit_or_spec.rb +8 -0
  45. data/spec/core/numeric/bit_xor_spec.rb +6 -0
  46. data/spec/core/numeric/ceil_spec.rb +8 -0
  47. data/spec/core/numeric/chr_spec.rb +8 -0
  48. data/spec/core/numeric/comparison_spec.rb +24 -0
  49. data/spec/core/numeric/complement_spec.rb +8 -0
  50. data/spec/core/numeric/divide_spec.rb +10 -0
  51. data/spec/core/numeric/downto_spec.rb +19 -0
  52. data/spec/core/numeric/eql_spec.rb +9 -0
  53. data/spec/core/numeric/even_spec.rb +21 -0
  54. data/spec/core/numeric/exponent_spec.rb +33 -0
  55. data/spec/core/numeric/floor_spec.rb +8 -0
  56. data/spec/core/numeric/gt_spec.rb +11 -0
  57. data/spec/core/numeric/gte_spec.rb +12 -0
  58. data/spec/core/numeric/integer_spec.rb +9 -0
  59. data/spec/core/numeric/left_shift_spec.rb +21 -0
  60. data/spec/core/numeric/lt_spec.rb +11 -0
  61. data/spec/core/numeric/lte_spec.rb +12 -0
  62. data/spec/core/numeric/magnitude_spec.rb +12 -0
  63. data/spec/core/numeric/minus_spec.rb +8 -0
  64. data/spec/core/numeric/modulo_spec.rb +19 -0
  65. data/spec/core/numeric/multiply_spec.rb +9 -0
  66. data/spec/core/numeric/next_spec.rb +9 -0
  67. data/spec/core/numeric/odd_spec.rb +21 -0
  68. data/spec/core/numeric/ord_spec.rb +9 -0
  69. data/spec/core/numeric/plus_spec.rb +8 -0
  70. data/spec/core/numeric/pred_spec.rb +7 -0
  71. data/spec/core/numeric/right_shift_spec.rb +25 -0
  72. data/spec/core/numeric/succ_spec.rb +9 -0
  73. data/spec/core/numeric/times_spec.rb +36 -0
  74. data/spec/core/numeric/to_f_spec.rb +7 -0
  75. data/spec/core/numeric/to_i_spec.rb +7 -0
  76. data/spec/{opal → core}/numeric/to_json_spec.rb +0 -0
  77. data/spec/core/numeric/to_s_spec.rb +8 -0
  78. data/spec/core/numeric/uminus_spec.rb +9 -0
  79. data/spec/core/numeric/upto_spec.rb +19 -0
  80. data/spec/core/numeric/zero_spec.rb +7 -0
  81. data/spec/{opal → core}/runtime/call_spec.rb +0 -0
  82. data/spec/{opal → core}/runtime/class_hierarchy_spec.rb +0 -0
  83. data/spec/{opal → core}/runtime/def_spec.rb +0 -0
  84. data/spec/{opal → core}/runtime/defined_spec.rb +0 -0
  85. data/spec/{opal → core}/runtime/super_spec.rb +0 -0
  86. data/spec/{opal → core}/string/demodulize_spec.rb +0 -0
  87. data/spec/{opal → core}/string/to_json_spec.rb +0 -0
  88. data/spec/{opal → core}/string/underscore_spec.rb +0 -0
  89. data/spec/{opal → core}/strscan/check_spec.rb +0 -0
  90. data/spec/{opal → core}/strscan/scan_spec.rb +0 -0
  91. data/spec/{lib/grammar → grammar}/alias_spec.rb +0 -0
  92. data/spec/{lib/grammar → grammar}/and_spec.rb +0 -0
  93. data/spec/{lib/grammar → grammar}/array_spec.rb +0 -0
  94. data/spec/{lib/grammar → grammar}/attrasgn_spec.rb +0 -0
  95. data/spec/{lib/grammar → grammar}/begin_spec.rb +0 -0
  96. data/spec/{lib/grammar → grammar}/block_spec.rb +0 -0
  97. data/spec/{lib/grammar → grammar}/break_spec.rb +0 -0
  98. data/spec/{lib/grammar → grammar}/call_spec.rb +23 -1
  99. data/spec/{lib/grammar → grammar}/class_spec.rb +0 -0
  100. data/spec/{lib/grammar → grammar}/const_spec.rb +0 -0
  101. data/spec/{lib/grammar → grammar}/cvar_spec.rb +0 -0
  102. data/spec/{lib/grammar → grammar}/def_spec.rb +0 -0
  103. data/spec/{lib/grammar → grammar}/false_spec.rb +0 -0
  104. data/spec/{lib/grammar → grammar}/file_spec.rb +0 -0
  105. data/spec/{lib/grammar → grammar}/gvar_spec.rb +0 -0
  106. data/spec/{lib/grammar → grammar}/hash_spec.rb +0 -0
  107. data/spec/{lib/grammar → grammar}/iasgn_spec.rb +0 -0
  108. data/spec/{lib/grammar → grammar}/if_spec.rb +0 -0
  109. data/spec/{lib/grammar → grammar}/iter_spec.rb +0 -0
  110. data/spec/{lib/grammar → grammar}/ivar_spec.rb +0 -0
  111. data/spec/{lib/grammar → grammar}/lambda_spec.rb +0 -0
  112. data/spec/{lib/grammar → grammar}/lasgn_spec.rb +0 -0
  113. data/spec/{lib/grammar → grammar}/line_spec.rb +0 -0
  114. data/spec/{lib/grammar → grammar}/lvar_spec.rb +0 -0
  115. data/spec/{lib/grammar → grammar}/masgn_spec.rb +0 -0
  116. data/spec/{lib/grammar → grammar}/module_spec.rb +0 -0
  117. data/spec/{lib/grammar → grammar}/nil_spec.rb +0 -0
  118. data/spec/{lib/grammar → grammar}/not_spec.rb +0 -0
  119. data/spec/{lib/grammar → grammar}/op_asgn1_spec.rb +0 -0
  120. data/spec/{lib/grammar → grammar}/op_asgn2_spec.rb +0 -0
  121. data/spec/{lib/grammar → grammar}/or_spec.rb +0 -0
  122. data/spec/{lib/grammar → grammar}/return_spec.rb +0 -0
  123. data/spec/{lib/grammar → grammar}/sclass_spec.rb +0 -0
  124. data/spec/{lib/grammar → grammar}/self_spec.rb +0 -0
  125. data/spec/{lib/grammar → grammar}/str_spec.rb +7 -0
  126. data/spec/{lib/grammar → grammar}/super_spec.rb +0 -0
  127. data/spec/{lib/grammar → grammar}/true_spec.rb +0 -0
  128. data/spec/{lib/grammar → grammar}/undef_spec.rb +0 -0
  129. data/spec/{lib/grammar → grammar}/unless_spec.rb +0 -0
  130. data/spec/{lib/grammar → grammar}/while_spec.rb +0 -0
  131. data/spec/{lib/grammar → grammar}/xstr_spec.rb +0 -0
  132. data/spec/{lib/grammar → grammar}/yield_spec.rb +0 -0
  133. data/spec/language/string_spec.rb +5 -0
  134. data/spec/{lib/parser → parser}/simple_spec.rb +0 -0
  135. metadata +231 -159
  136. data/spec/core/false/and_spec.rb +0 -9
  137. data/spec/core/false/inspect_spec.rb +0 -5
  138. data/spec/core/false/or_spec.rb +0 -9
  139. data/spec/core/false/to_s_spec.rb +0 -5
  140. data/spec/core/false/xor_spec.rb +0 -9
  141. data/spec/core/true/and_spec.rb +0 -9
  142. data/spec/core/true/inspect_spec.rb +0 -5
  143. data/spec/core/true/or_spec.rb +0 -9
  144. data/spec/core/true/to_s_spec.rb +0 -5
  145. data/spec/core/true/xor_spec.rb +0 -9
  146. data/spec/lib/erb_parser/simple.erb +0 -1
  147. data/spec/opal/kernel/attribute_spec.rb +0 -57
  148. data/spec/opal/runtime/method_missing_spec.rb +0 -17
data/.gitignore CHANGED
@@ -3,4 +3,5 @@
3
3
  .yardoc
4
4
  .bundle
5
5
  Gemfile.lock
6
- build
6
+ build
7
+ gh-pages
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,24 @@
1
+ # Contributing
2
+
3
+ ## Quick Start
4
+
5
+ Clone repo:
6
+
7
+ ```
8
+ $ git clone git://github.com/opal/opal.git
9
+ ```
10
+
11
+ Get dependencies:
12
+
13
+ ```
14
+ $ bundle
15
+ ```
16
+
17
+ ## Tests
18
+
19
+ You need phantomjs installed to run tests. To build opal, its dependencies
20
+ and all specs, run:
21
+
22
+ ```
23
+ $ rake
24
+ ```
data/README.md CHANGED
@@ -6,21 +6,22 @@ Opal is a ruby to javascript source-to-source compiler. It also has an
6
6
  implementation of the ruby corelib.
7
7
 
8
8
  Opal is [hosted on github](http://github.com/opal/opal), and there
9
- is a Freenode IRC channel at `#opal`. There is also a [google group for opal](http://groups.google.com/forum/#!forum/opalrb).
9
+ is a Freenode IRC channel at [#opal](http://webchat.freenode.net/?channels=opal). There is also a [google group for opal](http://groups.google.com/forum/#!forum/opalrb).
10
10
 
11
11
  ## Usage
12
12
 
13
- See the website, [http://opal.github.com](http://opal.github.com).
13
+ See the website, [http://opalrb.org](http://opalrb.org).
14
14
 
15
15
  ## Running tests
16
16
 
17
- Build the runtime, tests and dependencies, and then run the tests all in one
18
- go:
17
+ Build the runtime, tests and dependencies, and run the tests with:
19
18
 
20
19
  ```
21
- $ rake
20
+ rake
22
21
  ```
23
22
 
23
+ You can just build opal using `rake opal`.
24
+
24
25
  Alternatively, after building, you can open `spec/index.html` in any
25
26
  web browser.
26
27
 
data/Rakefile CHANGED
@@ -10,6 +10,16 @@ end
10
10
  # build runtime, dependencies and specs, then run the tests
11
11
  task :default => %w[opal opal:test]
12
12
 
13
+ desc "opal.min.js and opal-parser.min.js"
14
+ task :min do
15
+ %w[opal opal-parser].each do |file|
16
+ puts " * #{file}.min.js"
17
+ File.open("build/#{file}.min.js", "w+") do |o|
18
+ o.puts uglify(File.read "build/#{file}.js")
19
+ end
20
+ end
21
+ end
22
+
13
23
  desc "Check file sizes for opal.js runtime"
14
24
  task :sizes do
15
25
  o = File.read 'build/opal.js'
@@ -44,11 +54,11 @@ def gzip(str)
44
54
  end
45
55
 
46
56
  # For testing just specific sections of opal
47
- desc "Build each test case"
57
+ desc "Build each test case into build/"
48
58
  task :test_cases do
49
59
  FileUtils.mkdir_p 'build/test_cases'
50
60
 
51
- sources = Dir['spec/core/*', 'spec/language', 'spec/lib', 'spec/opal']
61
+ sources = Dir['spec/core/*', 'spec/language', 'spec/parser', 'spec/grammar']
52
62
 
53
63
  sources.each do |c|
54
64
  dest = "build/test_cases/#{File.basename c}"
data/core/array.rb CHANGED
@@ -666,21 +666,8 @@ class Array < `Array`
666
666
  def reject!(&block)
667
667
  %x{
668
668
  var original = #{self}.length;
669
-
670
- for (var i = 0, length = #{self}.length, value; i < length; i++) {
671
- if ((value = block.call(__context, #{self}[i])) === __breaker) {
672
- return __breaker.$v;
673
- }
674
-
675
- if (value !== false && value !== nil) {
676
- #{self}.splice(i, 1);
677
-
678
- length--;
679
- i--;
680
- }
681
- }
682
-
683
- return original === #{self}.length ? nil : #{self};
669
+ #{ delete_if &block };
670
+ return #{self}.length === original ? nil : #{self};
684
671
  }
685
672
  end
686
673
 
@@ -756,22 +743,7 @@ class Array < `Array`
756
743
  def select!(&block)
757
744
  %x{
758
745
  var original = #{self}.length;
759
-
760
- for (var i = 0, length = original, item, value; i < length; i++) {
761
- item = #{self}[i];
762
-
763
- if ((value = block(__context, item)) === __breaker) {
764
- return __breaker.$v;
765
- }
766
-
767
- if (value === false || value === nil) {
768
- #{self}.splice(i, 1);
769
-
770
- length--;
771
- i--;
772
- }
773
- }
774
-
746
+ #{ keep_if &block };
775
747
  return #{self}.length === original ? nil : #{self};
776
748
  }
777
749
  end
data/core/enumerable.rb CHANGED
@@ -96,6 +96,30 @@ module Enumerable
96
96
  }
97
97
  end
98
98
 
99
+ def reduce(object, &block)
100
+ %x{
101
+ var result = #{object} == undefined ? 0 : #{object};
102
+
103
+ var proc = function() {
104
+ var obj = __slice.call(arguments), value;
105
+
106
+ if ((value = block.apply(__context, [result].concat(obj))) === __breaker) {
107
+ result = __breaker.$v;
108
+ __breaker.$v = nil;
109
+
110
+ return __breaker;
111
+ }
112
+
113
+ result = value;
114
+ };
115
+
116
+ #{self}.$each._p = proc;
117
+ #{self}.$each();
118
+
119
+ return result;
120
+ }
121
+ end
122
+
99
123
  def count(object, &block)
100
124
  %x{
101
125
  var result = 0;
@@ -193,8 +217,8 @@ module Enumerable
193
217
  result.push(obj);
194
218
  return value;
195
219
  }
196
-
197
-
220
+
221
+
198
222
  return __breaker;
199
223
  };
200
224
 
@@ -283,7 +307,7 @@ module Enumerable
283
307
  var proc, result = nil, index = 0;
284
308
 
285
309
  if (object != null) {
286
- proc = function (obj) {
310
+ proc = function (obj) {
287
311
  if (#{ `obj` == `object` }) {
288
312
  result = index;
289
313
  return __breaker;
@@ -376,9 +400,13 @@ module Enumerable
376
400
  }
377
401
  end
378
402
 
403
+ alias map collect
404
+
379
405
  alias select find_all
380
406
 
381
407
  alias take first
382
408
 
383
409
  alias to_a entries
384
- end
410
+
411
+ alias inject reduce
412
+ end
data/core/hash.rb CHANGED
@@ -5,17 +5,35 @@ class Hash
5
5
  __hash = Opal.hash = function() {
6
6
  var hash = new Hash,
7
7
  args = __slice.call(arguments),
8
+ keys = [],
8
9
  assocs = {};
9
10
 
10
11
  hash.map = assocs;
12
+ hash.keys = keys;
11
13
 
12
14
  for (var i = 0, length = args.length, key; i < length; i++) {
13
- key = args[i];
14
- assocs[key] = [key, args[++i]];
15
+ var key = args[i], obj = args[++i];
16
+
17
+ if (assocs[key] == null) {
18
+ keys.push(key);
19
+ }
20
+
21
+ assocs[key] = obj;
15
22
  }
16
23
 
17
24
  return hash;
18
25
  };
26
+
27
+ // hash2 is a faster creator for hashes that just use symbols and
28
+ // strings as keys. The map and keys array can be constructed at
29
+ // compile time, so they are just added here by the constructor
30
+ // function
31
+ __hash2 = Opal.hash2 = function(keys, map) {
32
+ var hash = new Hash;
33
+ hash.keys = keys;
34
+ hash.map = map;
35
+ return hash;
36
+ }
19
37
  }
20
38
 
21
39
  def self.[](*objs)
@@ -28,10 +46,11 @@ class Hash
28
46
 
29
47
  def self.from_native(obj)
30
48
  %x{
31
- var hash = __hash(), map = hash.map;
49
+ var hash = __hash(), map = hash.map, keys = hash.keys;
32
50
 
33
51
  for (var key in obj) {
34
- map[key] = [key, obj[key]]
52
+ keys.push(key);
53
+ map[key] = obj[key];
35
54
  }
36
55
 
37
56
  return hash;
@@ -59,20 +78,19 @@ class Hash
59
78
  return true;
60
79
  }
61
80
 
62
- if (!other.map) {
81
+ if (!other.map || !other.keys) {
82
+ return false;
83
+ }
84
+
85
+ if (#{self}.keys.length !== other.keys.length) {
63
86
  return false;
64
87
  }
65
88
 
66
89
  var map = #{self}.map,
67
90
  map2 = other.map;
68
91
 
69
- for (var assoc in map) {
70
- if (!map2[assoc]) {
71
- return false;
72
- }
73
-
74
- var obj = map[assoc][1],
75
- obj2 = map2[assoc][1];
92
+ for (var i = 0, length = #{self}.keys.length; i < length; i++) {
93
+ var key = #{self}.keys[i], obj = map[key], obj2 = map2[key];
76
94
 
77
95
  if (#{`obj` != `obj2`}) {
78
96
  return false;
@@ -85,10 +103,10 @@ class Hash
85
103
 
86
104
  def [](key)
87
105
  %x{
88
- var bucket;
106
+ var bucket = #{self}.map[key];
89
107
 
90
- if (bucket = #{self}.map[key]) {
91
- return bucket[1];
108
+ if (bucket != null) {
109
+ return bucket;
92
110
  }
93
111
 
94
112
  var proc = #{@proc};
@@ -103,7 +121,13 @@ class Hash
103
121
 
104
122
  def []=(key, value)
105
123
  %x{
106
- #{self}.map[key] = [key, value];
124
+ var map = #{self}.map;
125
+
126
+ if (!__hasOwn.call(map, key)) {
127
+ #{self}.keys.push(key);
128
+ }
129
+
130
+ map[key] = value;
107
131
 
108
132
  return value;
109
133
  }
@@ -111,11 +135,13 @@ class Hash
111
135
 
112
136
  def assoc(object)
113
137
  %x{
114
- for (var assoc in #{self}.map) {
115
- var bucket = #{self}.map[assoc];
138
+ var keys = #{self}.keys, key;
139
+
140
+ for (var i = 0, length = keys.length; i < length; i++) {
141
+ key = keys[i];
116
142
 
117
- if (#{`bucket[0]` == `object`}) {
118
- return [bucket[0], bucket[1]];
143
+ if (#{`key` == object}) {
144
+ return [key, #{self}.map[key]];
119
145
  }
120
146
  }
121
147
 
@@ -126,7 +152,7 @@ class Hash
126
152
  def clear
127
153
  %x{
128
154
  #{self}.map = {};
129
-
155
+ #{self}.keys = [];
130
156
  return #{self};
131
157
  }
132
158
  end
@@ -135,10 +161,12 @@ class Hash
135
161
  %x{
136
162
  var result = __hash(),
137
163
  map = #{self}.map,
138
- map2 = result.map;
164
+ map2 = result.map,
165
+ keys2 = result.keys;
139
166
 
140
- for (var assoc in map) {
141
- map2[assoc] = [map[assoc][0], map[assoc][1]];
167
+ for (var i = 0, length = #{self}.keys.length; i < length; i++) {
168
+ keys2.push(#{self}.keys[i]);
169
+ map2[#{self}.keys[i]] = map[#{self}.keys[i]];
142
170
  }
143
171
 
144
172
  return result;
@@ -163,12 +191,12 @@ class Hash
163
191
 
164
192
  def delete(key)
165
193
  %x{
166
- var map = #{self}.map, result;
167
-
168
- if (result = map[key]) {
169
- result = result[1];
194
+ var map = #{self}.map, result = map[key];
170
195
 
196
+ if (result != null) {
171
197
  delete map[key];
198
+ #{self}.keys.$delete(key);
199
+
172
200
  return result;
173
201
  }
174
202
 
@@ -178,18 +206,21 @@ class Hash
178
206
 
179
207
  def delete_if(&block)
180
208
  %x{
181
- var map = #{self}.map;
209
+ var map = #{self}.map, keys = #{self}.keys, value;
182
210
 
183
- for (var assoc in map) {
184
- var bucket = map[assoc],
185
- value;
211
+ for (var i = 0, length = keys.length; i < length; i++) {
212
+ var key = keys[i], obj = map[key];
186
213
 
187
- if ((value = block.call(__context, bucket[0], bucket[1])) === __breaker) {
214
+ if ((value = block.call(__context, key, obj)) === __breaker) {
188
215
  return __breaker.$v;
189
216
  }
190
217
 
191
218
  if (value !== false && value !== nil) {
192
- delete map[assoc];
219
+ keys.splice(i, 1);
220
+ delete map[key];
221
+
222
+ length--;
223
+ i--;
193
224
  }
194
225
  }
195
226
 
@@ -201,12 +232,12 @@ class Hash
201
232
 
202
233
  def each(&block)
203
234
  %x{
204
- var map = #{self}.map;
235
+ var map = #{self}.map, keys = #{self}.keys;
205
236
 
206
- for (var assoc in map) {
207
- var bucket = map[assoc];
237
+ for (var i = 0, length = keys.length; i < length; i++) {
238
+ var key = keys[i];
208
239
 
209
- if (block.call(__context, bucket[0], bucket[1]) === __breaker) {
240
+ if (block.call(__context, key, map[key]) === __breaker) {
210
241
  return __breaker.$v;
211
242
  }
212
243
  }
@@ -217,12 +248,12 @@ class Hash
217
248
 
218
249
  def each_key(&block)
219
250
  %x{
220
- var map = #{self}.map;
251
+ var keys = #{self}.keys;
221
252
 
222
- for (var assoc in map) {
223
- var bucket = map[assoc];
253
+ for (var i = 0, length = keys.length; i < length; i++) {
254
+ var key = keys[i];
224
255
 
225
- if (block.call(__context, bucket[0]) === __breaker) {
256
+ if (block.call(__context, key) === __breaker) {
226
257
  return __breaker.$v;
227
258
  }
228
259
  }
@@ -235,12 +266,10 @@ class Hash
235
266
 
236
267
  def each_value(&block)
237
268
  %x{
238
- var map = #{self}.map;
239
-
240
- for (var assoc in map) {
241
- var bucket = map[assoc];
269
+ var map = #{self}.map, keys = #{self}.keys;
242
270
 
243
- if (block.call(__context, bucket[1]) === __breaker) {
271
+ for (var i = 0, length = keys.length; i < length; i++) {
272
+ if (block.call(__context, map[keys[i]]) === __breaker) {
244
273
  return __breaker.$v;
245
274
  }
246
275
  }
@@ -251,11 +280,7 @@ class Hash
251
280
 
252
281
  def empty?
253
282
  %x{
254
- for (var assoc in #{self}.map) {
255
- return false;
256
- }
257
-
258
- return true;
283
+ return #{self}.keys.length === 0;
259
284
  }
260
285
  end
261
286
 
@@ -263,10 +288,10 @@ class Hash
263
288
 
264
289
  def fetch(key, defaults, &block)
265
290
  %x{
266
- var bucket = #{self}.map[key];
291
+ var value = #{self}.map[key];
267
292
 
268
- if (bucket) {
269
- return bucket[1];
293
+ if (value != null) {
294
+ return value;
270
295
  }
271
296
 
272
297
  if (block !== nil) {
@@ -287,15 +312,12 @@ class Hash
287
312
  }
288
313
  end
289
314
 
290
- def flatten(level)
315
+ def flatten(level=undefined)
291
316
  %x{
292
- var map = #{self}.map,
293
- result = [];
317
+ var map = #{self}.map, keys = #{self}.keys, result = [];
294
318
 
295
- for (var assoc in map) {
296
- var bucket = map[assoc],
297
- key = bucket[0],
298
- value = bucket[1];
319
+ for (var i = 0, length = keys.length; i < length; i++) {
320
+ var key = keys[i], value = map[key];
299
321
 
300
322
  result.push(key);
301
323
 
@@ -304,7 +326,7 @@ class Hash
304
326
  result.push(value);
305
327
  }
306
328
  else {
307
- result = result.concat(#{`value`.flatten(level - 1)});
329
+ result = result.concat(#{`value`.flatten(`level - 1`)});
308
330
  }
309
331
  }
310
332
  else {
@@ -317,13 +339,13 @@ class Hash
317
339
  end
318
340
 
319
341
  def has_key?(key)
320
- `!!#{self}.map[key]`
342
+ `#{self}.map[key] != null`
321
343
  end
322
344
 
323
345
  def has_value?(value)
324
346
  %x{
325
347
  for (var assoc in #{self}.map) {
326
- if (#{`#{self}.map[assoc][1]` == value}) {
348
+ if (#{`#{self}.map[assoc]` == value}) {
327
349
  return true;
328
350
  }
329
351
  }
@@ -340,11 +362,13 @@ class Hash
340
362
 
341
363
  def index(object)
342
364
  %x{
343
- for (var assoc in #{self}.map) {
344
- var bucket = #{self}.map[assoc];
365
+ var map = #{self}.map, keys = #{self}.keys;
366
+
367
+ for (var i = 0, length = keys.length; i < length; i++) {
368
+ var key = keys[i];
345
369
 
346
- if (#{object == `bucket[1]`}) {
347
- return bucket[0];
370
+ if (#{object == `map[key]`}) {
371
+ return key;
348
372
  }
349
373
  }
350
374
 
@@ -354,13 +378,13 @@ class Hash
354
378
 
355
379
  def indexes(*keys)
356
380
  %x{
357
- var result = [], map = #{self}.map, bucket;
381
+ var result = [], map = #{self}.map, val;
358
382
 
359
383
  for (var i = 0, length = keys.length; i < length; i++) {
360
- var key = keys[i];
384
+ var key = keys[i], val = map[key];
361
385
 
362
- if (bucket = map[key]) {
363
- result.push(bucket[1]);
386
+ if (val != null) {
387
+ result.push(val);
364
388
  }
365
389
  else {
366
390
  result.push(#{self}.none);
@@ -375,28 +399,27 @@ class Hash
375
399
 
376
400
  def inspect
377
401
  %x{
378
- var inspect = [],
379
- map = #{self}.map;
380
-
381
- for (var assoc in map) {
382
- var bucket = map[assoc];
402
+ var inspect = [], keys = #{self}.keys, map = #{self}.map;
383
403
 
384
- inspect.push(#{`bucket[0]`.inspect} + '=>' + #{`bucket[1]`.inspect});
404
+ for (var i = 0, length = keys.length; i < length; i++) {
405
+ var key = keys[i];
406
+ inspect.push(#{`key`.inspect} + '=>' + #{`map[key]`.inspect});
385
407
  }
408
+
386
409
  return '{' + inspect.join(', ') + '}';
387
410
  }
388
411
  end
389
412
 
390
413
  def invert
391
414
  %x{
392
- var result = __hash(),
393
- map = #{self}.map,
394
- map2 = result.map;
415
+ var result = __hash(), keys = #{self}.keys, map = #{self}.map,
416
+ keys2 = result.keys, map2 = result.map;
395
417
 
396
- for (var assoc in map) {
397
- var bucket = map[assoc];
418
+ for (var i = 0, length = keys.length; i < length; i++) {
419
+ var key = keys[i], obj = map[key];
398
420
 
399
- map2[bucket[1]] = [bucket[1], bucket[0]];
421
+ keys2.push(obj);
422
+ map2[obj] = key;
400
423
  }
401
424
 
402
425
  return result;
@@ -405,17 +428,21 @@ class Hash
405
428
 
406
429
  def keep_if(&block)
407
430
  %x{
408
- var map = #{self}.map, value;
431
+ var map = #{self}.map, keys = #{self}.keys, value;
409
432
 
410
- for (var assoc in map) {
411
- var bucket = map[assoc];
433
+ for (var i = 0, length = keys.length; i < length; i++) {
434
+ var key = keys[i], obj = map[key];
412
435
 
413
- if ((value = block.call(__context, bucket[0], bucket[1])) === __breaker) {
436
+ if ((value = block.call(__context, key, obj)) === __breaker) {
414
437
  return __breaker.$v;
415
438
  }
416
439
 
417
440
  if (value === false || value === nil) {
418
- delete map[assoc];
441
+ keys.splice(i, 1);
442
+ delete map[key];
443
+
444
+ length--;
445
+ i--;
419
446
  }
420
447
  }
421
448
 
@@ -429,25 +456,13 @@ class Hash
429
456
 
430
457
  def keys
431
458
  %x{
432
- var result = [];
433
-
434
- for (var assoc in #{self}.map) {
435
- result.push(#{self}.map[assoc][0]);
436
- }
437
-
438
- return result;
459
+ return #{self}.keys.slice(0);
439
460
  }
440
461
  end
441
462
 
442
463
  def length
443
464
  %x{
444
- var result = 0;
445
-
446
- for (var assoc in #{self}.map) {
447
- result++;
448
- }
449
-
450
- return result;
465
+ return #{self}.keys.length;
451
466
  }
452
467
  end
453
468
 
@@ -455,34 +470,40 @@ class Hash
455
470
 
456
471
  def merge(other, &block)
457
472
  %x{
458
- var result = __hash(),
459
- map = #{self}.map,
460
- map2 = result.map;
473
+ var keys = #{self}.keys, map = #{self}.map,
474
+ result = __hash(), keys2 = result.keys, map2 = result.map;
461
475
 
462
- for (var assoc in map) {
463
- var bucket = map[assoc];
476
+ for (var i = 0, length = keys.length; i < length; i++) {
477
+ var key = keys[i];
464
478
 
465
- map2[assoc] = [bucket[0], bucket[1]];
479
+ keys2.push(key);
480
+ map2[key] = map[key];
466
481
  }
467
482
 
468
- map = other.map;
483
+ var keys = other.keys, map = other.map;
469
484
 
470
485
  if (block === nil) {
471
- for (var assoc in map) {
472
- var bucket = map[assoc];
486
+ for (var i = 0, length = keys.length; i < length; i++) {
487
+ var key = keys[i];
488
+
489
+ if (map2[key] == null) {
490
+ keys2.push(key);
491
+ }
473
492
 
474
- map2[assoc] = [bucket[0], bucket[1]];
493
+ map2[key] = map[key];
475
494
  }
476
495
  }
477
496
  else {
478
- for (var assoc in map) {
479
- var bucket = map[assoc], key = bucket[0], val = bucket[1];
497
+ for (var i = 0, length = keys.length; i < length; i++) {
498
+ var key = keys[i];
480
499
 
481
- if (__hasOwn.call(map2, assoc)) {
482
- val = block.call(__context, key, map2[assoc][1], val);
500
+ if (map2[key] == null) {
501
+ keys2.push(key);
502
+ map2[key] = map[key];
503
+ }
504
+ else {
505
+ map2[key] = block.call(__context, key, map2[key], map[key]);
483
506
  }
484
-
485
- map2[assoc] = [key, val];
486
507
  }
487
508
  }
488
509
 
@@ -492,25 +513,31 @@ class Hash
492
513
 
493
514
  def merge!(other, &block)
494
515
  %x{
495
- var map = #{self}.map,
496
- map2 = other.map;
516
+ var keys = #{self}.keys, map = #{self}.map,
517
+ keys2 = other.keys, map2 = other.map;
497
518
 
498
519
  if (block === nil) {
499
- for (var assoc in map2) {
500
- var bucket = map2[assoc];
520
+ for (var i = 0, length = keys2.length; i < length; i++) {
521
+ var key = keys2[i];
501
522
 
502
- map[assoc] = [bucket[0], bucket[1]];
523
+ if (map[key] == null) {
524
+ keys.push(key);
525
+ }
526
+
527
+ map[key] = map2[key];
503
528
  }
504
529
  }
505
530
  else {
506
- for (var assoc in map2) {
507
- var bucket = map2[assoc], key = bucket[0], val = bucket[1];
531
+ for (var i = 0, length = keys2.length; i < length; i++) {
532
+ var key = keys2[i];
508
533
 
509
- if (__hasOwn.call(map, assoc)) {
510
- val = block.call(__context, key, map[assoc][1], val);
534
+ if (map[key] == null) {
535
+ keys.push(key);
536
+ map[key] = map2[key];
537
+ }
538
+ else {
539
+ map[key] = block.call(__context, key, map[key], map2[key]);
511
540
  }
512
-
513
- map[assoc] = [key, val];
514
541
  }
515
542
  }
516
543
 
@@ -520,13 +547,13 @@ class Hash
520
547
 
521
548
  def rassoc(object)
522
549
  %x{
523
- var map = #{self}.map;
550
+ var keys = #{self}.keys, map = #{self}.map;
524
551
 
525
- for (var assoc in map) {
526
- var bucket = map[assoc];
552
+ for (var i = 0, length = keys.length; i < length; i++) {
553
+ var key = keys[i], obj = map[key];
527
554
 
528
- if (#{`bucket[1]` == object}) {
529
- return [bucket[0], bucket[1]];
555
+ if (#{`obj` == object}) {
556
+ return [key, obj];
530
557
  }
531
558
  }
532
559
 
@@ -536,18 +563,19 @@ class Hash
536
563
 
537
564
  def reject(&block)
538
565
  %x{
539
- var map = #{self}.map, result = __hash(), map2 = result.map;
566
+ var keys = #{self}.keys, map = #{self}.map,
567
+ result = __hash(), map2 = result.map, keys2 = result.keys;
540
568
 
541
- for (var assoc in map) {
542
- var bucket = map[assoc],
543
- value;
569
+ for (var i = 0, length = keys.length; i < length; i++) {
570
+ var key = keys[i], obj = map[key], value;
544
571
 
545
- if ((value = block.call(__context, bucket[0], bucket[1])) === __breaker) {
572
+ if ((value = block.call(__context, key, obj)) === __breaker) {
546
573
  return __breaker.$v;
547
574
  }
548
575
 
549
576
  if (value === false || value === nil) {
550
- map2[bucket[0]] = [bucket[0], bucket[1]];
577
+ keys2.push(key);
578
+ map2[key] = obj;
551
579
  }
552
580
  }
553
581
 
@@ -557,12 +585,12 @@ class Hash
557
585
 
558
586
  def replace(other)
559
587
  %x{
560
- var map = #{self}.map = {};
561
-
562
- for (var assoc in other.map) {
563
- var bucket = other.map[assoc];
588
+ var map = #{self}.map = {}, keys = #{self}.keys = [];
564
589
 
565
- map[bucket[0]] = [bucket[0], bucket[1]];
590
+ for (var i = 0, length = other.keys.length; i < length; i++) {
591
+ var key = other.keys[i];
592
+ keys.push(key);
593
+ map[key] = other.map[key];
566
594
  }
567
595
 
568
596
  return #{self};
@@ -571,18 +599,19 @@ class Hash
571
599
 
572
600
  def select(&block)
573
601
  %x{
574
- var map = #{self}.map, result = __hash(), map2 = result.map;
602
+ var keys = #{self}.keys, map = #{self}.map,
603
+ result = __hash(), map2 = result.map, keys2 = result.keys;
575
604
 
576
- for (var assoc in map) {
577
- var bucket = map[assoc],
578
- value;
605
+ for (var i = 0, length = keys.length; i < length; i++) {
606
+ var key = keys[i], obj = map[key], value;
579
607
 
580
- if ((value = block.call(__context, bucket[0], bucket[1])) === __breaker) {
608
+ if ((value = block.call(__context, key, obj)) === __breaker) {
581
609
  return __breaker.$v;
582
610
  }
583
611
 
584
612
  if (value !== false && value !== nil) {
585
- map2[bucket[0]] = [bucket[0], bucket[1]];
613
+ keys2.push(key);
614
+ map2[key] = obj;
586
615
  }
587
616
  }
588
617
 
@@ -592,19 +621,22 @@ class Hash
592
621
 
593
622
  def select!(&block)
594
623
  %x{
595
- var map = #{self}.map, result = nil;
624
+ var map = #{self}.map, keys = #{self}.keys, value, result = nil;
596
625
 
597
- for (var assoc in map) {
598
- var bucket = map[assoc],
599
- value;
626
+ for (var i = 0, length = keys.length; i < length; i++) {
627
+ var key = keys[i], obj = map[key];
600
628
 
601
- if ((value = block.call(__context, bucket[0], bucket[1])) === __breaker) {
629
+ if ((value = block.call(__context, key, obj)) === __breaker) {
602
630
  return __breaker.$v;
603
631
  }
604
632
 
605
633
  if (value === false || value === nil) {
606
- delete map[assoc];
607
- result = #{self};
634
+ keys.splice(i, 1);
635
+ delete map[key];
636
+
637
+ length--;
638
+ i--;
639
+ result = #{self}
608
640
  }
609
641
  }
610
642
 
@@ -614,12 +646,15 @@ class Hash
614
646
 
615
647
  def shift
616
648
  %x{
617
- var map = #{self}.map;
649
+ var keys = #{self}.keys, map = #{self}.map;
618
650
 
619
- for (var assoc in map) {
620
- var bucket = map[assoc];
621
- delete map[assoc];
622
- return [bucket[0], bucket[1]];
651
+ if (keys.length) {
652
+ var key = keys[0], obj = map[key];
653
+
654
+ delete map[key];
655
+ keys.splice(0, 1);
656
+
657
+ return [key, obj];
623
658
  }
624
659
 
625
660
  return nil;
@@ -630,13 +665,11 @@ class Hash
630
665
 
631
666
  def to_a
632
667
  %x{
633
- var map = #{self}.map,
634
- result = [];
668
+ var keys = #{self}.keys, map = #{self}.map, result = [];
635
669
 
636
- for (var assoc in map) {
637
- var bucket = map[assoc];
638
-
639
- result.push([bucket[0], bucket[1]]);
670
+ for (var i = 0, length = keys.length; i < length; i++) {
671
+ var key = keys[i];
672
+ result.push([key, map[key]]);
640
673
  }
641
674
 
642
675
  return result;
@@ -649,30 +682,29 @@ class Hash
649
682
 
650
683
  def to_json
651
684
  %x{
652
- var parts = [], map = #{self}.map, bucket;
685
+ var inspect = [], keys = #{self}.keys, map = #{self}.map;
653
686
 
654
- for (var assoc in map) {
655
- bucket = map[assoc];
656
- parts.push(#{ `bucket[0]`.to_json } + ': ' + #{ `bucket[1]`.to_json });
687
+ for (var i = 0, length = keys.length; i < length; i++) {
688
+ var key = keys[i];
689
+ inspect.push(#{`key`.to_json} + ': ' + #{`map[key]`.to_json});
657
690
  }
658
691
 
659
- return '{' + parts.join(', ') + '}';
692
+ return '{' + inspect.join(', ') + '}';
660
693
  }
661
694
  end
662
695
 
663
696
  def to_native
664
697
  %x{
665
- var result = {}, map = #{self}.map, bucket, value;
698
+ var result = {}, keys = #{self}.keys, map = #{self}.map, bucket, value;
666
699
 
667
- for (var assoc in map) {
668
- bucket = map[assoc];
669
- value = bucket[1];
700
+ for (var i = 0, length = keys.length; i < length; i++) {
701
+ var key = keys[i], obj = map[key];
670
702
 
671
- if (value.$to_native) {
672
- result[assoc] = #{ `value`.to_native };
703
+ if (obj.$to_native) {
704
+ result[key] = #{`obj`.to_native};
673
705
  }
674
706
  else {
675
- result[assoc] = value;
707
+ result[key] = obj;
676
708
  }
677
709
  }
678
710
 
@@ -689,7 +721,7 @@ class Hash
689
721
  var map = #{self}.map;
690
722
 
691
723
  for (var assoc in map) {
692
- var v = map[assoc][1];
724
+ var v = map[assoc];
693
725
  if (#{`v` == value}) {
694
726
  return true;
695
727
  }
@@ -706,8 +738,8 @@ class Hash
706
738
  var map = #{self}.map,
707
739
  result = [];
708
740
 
709
- for (var assoc in map) {
710
- result.push(map[assoc][1]);
741
+ for (var key in map) {
742
+ result.push(map[key]);
711
743
  }
712
744
 
713
745
  return result;