opal 0.3.43 → 0.3.44

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/CHANGELOG.md +19 -0
  2. data/README.md +1 -0
  3. data/Rakefile +29 -19
  4. data/examples/native/Gemfile +3 -0
  5. data/examples/native/README.md +17 -0
  6. data/examples/native/app/app.rb +38 -0
  7. data/examples/native/config.ru +8 -0
  8. data/examples/native/index.html.erb +12 -0
  9. data/lib/opal/lexer.rb +5 -1
  10. data/lib/opal/parser.rb +36 -10
  11. data/lib/opal/processor.rb +10 -9
  12. data/lib/opal/server.rb +17 -7
  13. data/lib/opal/target_scope.rb +2 -2
  14. data/lib/opal/version.rb +1 -1
  15. data/opal/opal-browser/script_loader.rb +8 -13
  16. data/opal/opal.rb +23 -5
  17. data/opal/opal/array.rb +128 -14
  18. data/opal/opal/boolean.rb +1 -1
  19. data/opal/opal/class.rb +92 -18
  20. data/opal/opal/enumerable.rb +90 -0
  21. data/opal/opal/error.rb +1 -1
  22. data/opal/opal/hash.rb +2 -2
  23. data/opal/opal/kernel.rb +3 -3
  24. data/opal/opal/numeric.rb +1 -1
  25. data/opal/opal/proc.rb +1 -1
  26. data/opal/opal/regexp.rb +31 -31
  27. data/opal/opal/runtime.js +181 -69
  28. data/opal/opal/string.rb +561 -40
  29. data/opal/opal/time.rb +1 -1
  30. data/opal/rbconfig.rb +17 -3
  31. data/opal/strscan.rb +41 -5
  32. data/spec/opal/class/new_spec.rb +27 -0
  33. data/spec/opal/native_spec.rb +127 -0
  34. data/spec/ospec/runner.rb +0 -2
  35. data/spec/parser/strscan/get_byte_spec.rb +29 -0
  36. data/spec/parser/strscan/skip_spec.rb +40 -0
  37. data/spec/rubyspec/core/array/each_spec.rb +1 -1
  38. data/spec/rubyspec/core/array/intersection_spec.rb +5 -0
  39. data/spec/rubyspec/core/array/max_spec.rb +32 -0
  40. data/spec/rubyspec/core/array/min_spec.rb +32 -0
  41. data/spec/rubyspec/core/array/minus_spec.rb +7 -5
  42. data/spec/rubyspec/core/array/multiply_spec.rb +1 -1
  43. data/spec/rubyspec/core/array/plus_spec.rb +1 -1
  44. data/spec/rubyspec/core/array/pop_spec.rb +1 -1
  45. data/spec/rubyspec/core/array/push_spec.rb +1 -1
  46. data/spec/rubyspec/core/array/rassoc_spec.rb +1 -1
  47. data/spec/rubyspec/core/array/reject_spec.rb +2 -2
  48. data/spec/rubyspec/core/array/reverse_each_spec.rb +2 -2
  49. data/spec/rubyspec/core/array/rindex_spec.rb +2 -2
  50. data/spec/rubyspec/core/array/select_spec.rb +1 -1
  51. data/spec/rubyspec/core/array/shift_spec.rb +1 -1
  52. data/spec/rubyspec/core/array/slice_spec.rb +1 -1
  53. data/spec/rubyspec/core/array/sort_spec.rb +15 -15
  54. data/spec/rubyspec/core/array/to_a_spec.rb +1 -1
  55. data/spec/rubyspec/core/array/to_ary_spec.rb +1 -1
  56. data/spec/rubyspec/core/array/uniq_spec.rb +1 -1
  57. data/spec/rubyspec/core/array/unshift_spec.rb +1 -1
  58. data/spec/rubyspec/core/array/zip_spec.rb +1 -1
  59. data/spec/rubyspec/core/enumerable/select_spec.rb +4 -1
  60. data/spec/rubyspec/core/module/const_defined_spec.rb +86 -0
  61. data/spec/rubyspec/core/module/const_get_spec.rb +55 -3
  62. data/spec/rubyspec/core/module/const_set_spec.rb +2 -2
  63. data/spec/rubyspec/core/module/constants_spec.rb +49 -0
  64. data/spec/rubyspec/core/regexp/match_spec.rb +66 -1
  65. data/spec/rubyspec/core/string/center_spec.rb +71 -0
  66. data/spec/rubyspec/core/string/chomp_spec.rb +6 -1
  67. data/spec/rubyspec/core/string/clone_spec.rb +8 -0
  68. data/spec/rubyspec/core/string/dup_spec.rb +8 -0
  69. data/spec/rubyspec/core/string/end_with_spec.rb +5 -1
  70. data/spec/rubyspec/core/string/gsub_spec.rb +15 -1
  71. data/spec/rubyspec/core/string/lines_spec.rb +9 -0
  72. data/spec/rubyspec/core/string/ljust_spec.rb +17 -0
  73. data/spec/rubyspec/core/string/match_spec.rb +25 -3
  74. data/spec/rubyspec/core/string/rindex_spec.rb +50 -0
  75. data/spec/rubyspec/core/string/rjust_spec.rb +17 -0
  76. data/spec/rubyspec/core/string/scan_spec.rb +66 -0
  77. data/spec/rubyspec/core/string/sub_spec.rb +17 -1
  78. data/spec/rubyspec/core/string/tr_s_spec.rb +31 -0
  79. data/spec/rubyspec/core/string/tr_spec.rb +31 -0
  80. data/spec/rubyspec/fixtures/constants.rb +6 -0
  81. data/spec/rubyspec/language/class_spec.rb +4 -8
  82. data/spec/rubyspec/language/numbers_spec.rb +10 -4
  83. data/spec/rubyspec/language/predefined_spec.rb +69 -2
  84. data/spec/rubyspec/library/rbconfig/config_spec.rb +47 -0
  85. data/spec/rubyspec/spec_helper.rb +6 -0
  86. metadata +46 -25
  87. data/opal/opal-eventable.rb +0 -26
  88. data/opal/opal/native.rb +0 -115
  89. data/spec/opal/eventable_spec.rb +0 -75
  90. data/spec/opal/native/element_reference_spec.rb +0 -40
  91. data/spec/opal/native/equal_spec.rb +0 -17
  92. data/spec/opal/native/fixtures/classes.rb +0 -27
  93. data/spec/opal/native/global_spec.rb +0 -12
  94. data/spec/opal/native/initialize_spec.rb +0 -8
  95. data/spec/opal/native/method_missing_spec.rb +0 -53
  96. data/spec/opal/native/to_native_spec.rb +0 -8
  97. data/spec/rubyspec/core/string/demodulize_spec.rb +0 -10
  98. data/spec/rubyspec/core/string/underscore_spec.rb +0 -17
data/opal/opal/string.rb CHANGED
@@ -1,4 +1,4 @@
1
- class String < `String`
1
+ class String
2
2
  include Comparable
3
3
 
4
4
  `def._isString = true`
@@ -165,6 +165,19 @@ class String < `String`
165
165
  }
166
166
  end
167
167
 
168
+ def center(width, padstr = ' ')
169
+ %x{
170
+ if (width <= #{self}.length) {
171
+ return #{self};
172
+ }
173
+ else {
174
+ var ljustified = #{self.ljust( ((width + self.size)/2).floor, padstr)};
175
+ var rjustified = #{self.rjust( ((width + self.size)/2).ceil, padstr)};
176
+ return ljustified + rjustified.slice(#{self}.length);
177
+ }
178
+ }
179
+ end
180
+
168
181
  def chars
169
182
  %x{
170
183
  for (var i = 0, length = #{self}.length; i < length; i++) {
@@ -175,13 +188,30 @@ class String < `String`
175
188
 
176
189
  def chomp(separator = $/)
177
190
  %x{
178
- if (separator === "\\n") {
179
- return #{self}.replace(/(\\n|\\r|\\r\\n)$/, '');
180
- }
181
- else if (separator === "") {
182
- return #{self}.replace(/(\\n|\\r\\n)+$/, '');
191
+ var strlen = #{self}.length;
192
+ var seplen = separator.length;
193
+ if (strlen > 0) {
194
+ if (separator === "\\n") {
195
+ var last = #{self}.charAt(strlen - 1);
196
+ if (last === "\\n" || last == "\\r") {
197
+ var result = #{self}.substr(0, strlen - 1);
198
+ if (strlen > 1 && #{self}.charAt(strlen - 2) === "\\r") {
199
+ result = #{self}.substr(0, strlen - 2);
200
+ }
201
+ return result;
202
+ }
203
+ }
204
+ else if (separator === "") {
205
+ return #{self}.replace(/(?:\\n|\\r\\n)+$/, '');
206
+ }
207
+ else if (strlen >= seplen) {
208
+ var tail = #{self}.substr(-1 * seplen);
209
+ if (tail === separator) {
210
+ return #{self}.substr(0, strlen - seplen);
211
+ }
212
+ }
183
213
  }
184
- return #{self}.replace(new RegExp(separator + '$'), '');
214
+ return #{self}
185
215
  }
186
216
  end
187
217
 
@@ -193,39 +223,49 @@ class String < `String`
193
223
  `#{self}.charAt(0)`
194
224
  end
195
225
 
196
- def count(str)
197
- `(#{self}.length - #{self}.replace(new RegExp(str,"g"), '').length) / str.length`
226
+ def clone
227
+ `#{self}.slice()`
198
228
  end
199
229
 
200
- def dasherize
201
- `#{self}.replace(/[-\\s]+/g, '-')
202
- .replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1-$2')
203
- .replace(/([a-z\\d])([A-Z])/g, '$1-$2')
204
- .toLowerCase()`
230
+ def count(str)
231
+ `(#{self}.length - #{self}.replace(new RegExp(str,"g"), '').length) / str.length`
205
232
  end
206
233
 
207
- def demodulize
208
- %x{
209
- var idx = #{self}.lastIndexOf('::');
210
-
211
- if (idx > -1) {
212
- return #{self}.substr(idx + 2);
213
- }
214
-
215
- return #{self};
216
- }
217
- end
234
+ alias dup clone
218
235
 
219
236
  alias_native :downcase, :toLowerCase
220
237
 
221
238
  alias each_char chars
222
239
 
223
240
  def each_line (separator = $/)
241
+ return self.split(separator).each unless block_given?
242
+
224
243
  %x{
225
- var splitted = #{self}.split(separator);
244
+ var chomped = #{self.chomp};
245
+ var trailing_separator = #{self}.length != chomped.length
246
+ var splitted = chomped.split(separator);
247
+
248
+ if (!#{block_given?}) {
249
+ result = []
250
+ for (var i = 0, length = splitted.length; i < length; i++) {
251
+ if (i < length - 1 || trailing_separator) {
252
+ result.push(splitted[i] + separator);
253
+ }
254
+ else {
255
+ result.push(splitted[i]);
256
+ }
257
+ }
258
+
259
+ return #{`result`.each};
260
+ }
226
261
 
227
262
  for (var i = 0, length = splitted.length; i < length; i++) {
228
- #{yield `splitted[i] + separator`}
263
+ if (i < length - 1 || trailing_separator) {
264
+ #{yield `splitted[i] + separator`}
265
+ }
266
+ else {
267
+ #{yield `splitted[i]`}
268
+ }
229
269
  }
230
270
  }
231
271
  end
@@ -239,7 +279,7 @@ class String < `String`
239
279
  for (var i = 0, length = suffixes.length; i < length; i++) {
240
280
  var suffix = suffixes[i];
241
281
 
242
- if (#{self}.lastIndexOf(suffix) === #{self}.length - suffix.length) {
282
+ if (#{self}.length >= suffix.length && #{self}.substr(0 - suffix.length) === suffix) {
243
283
  return true;
244
284
  }
245
285
  }
@@ -352,8 +392,19 @@ class String < `String`
352
392
  `#{self}.length`
353
393
  end
354
394
 
355
- def ljust(integer, padstr = ' ')
356
- raise NotImplementedError
395
+ def ljust(width, padstr = ' ')
396
+ %x{
397
+ if (width <= #{self}.length) {
398
+ return #{self};
399
+ }
400
+ else {
401
+ var n_chars = Math.floor(width - #{self}.length)
402
+ var n_patterns = Math.floor(n_chars/padstr.length);
403
+ var result = Array(n_patterns + 1).join(padstr);
404
+ var remaining = n_chars - result.length;
405
+ return result + padstr.slice(0, remaining) + #{self};
406
+ }
407
+ }
357
408
  end
358
409
 
359
410
  def lstrip
@@ -394,10 +445,95 @@ class String < `String`
394
445
  `#{self}.split('').reverse().join('')`
395
446
  end
396
447
 
448
+ # TODO handle case where search is regexp
449
+ def rindex(search, offset = undefined)
450
+ %x{
451
+ var search_type = (search == null ? Opal.NilClass : search.$class());
452
+ if (search_type != String && search_type != RegExp) {
453
+ var msg = "type mismatch: " + search_type + " given";
454
+ #{raise TypeError.new(`msg`)};
455
+ }
456
+
457
+ if (#{self}.length == 0) {
458
+ return search.length == 0 ? 0 : nil;
459
+ }
460
+
461
+ var result = -1;
462
+ if (offset != null) {
463
+ if (offset < 0) {
464
+ offset = #{self}.length + offset;
465
+ }
466
+
467
+ if (search_type == String) {
468
+ result = #{self}.lastIndexOf(search, offset);
469
+ }
470
+ else {
471
+ result = #{self}.substr(0, offset + 1).$reverse().search(search);
472
+ if (result !== -1) {
473
+ result = offset - result;
474
+ }
475
+ }
476
+ }
477
+ else {
478
+ if (search_type == String) {
479
+ result = #{self}.lastIndexOf(search);
480
+ }
481
+ else {
482
+ result = #{self}.$reverse().search(search);
483
+ if (result !== -1) {
484
+ result = #{self}.length - 1 - result;
485
+ }
486
+ }
487
+ }
488
+
489
+ return result === -1 ? nil : result;
490
+ }
491
+ end
492
+
493
+ def rjust(width, padstr = ' ')
494
+ %x{
495
+ if (width <= #{self}.length) {
496
+ return #{self};
497
+ }
498
+ else {
499
+ var ljustified = #{ self.ljust(width, padstr) };
500
+ return #{self} + ljustified.slice(0, -#{self}.length);
501
+ }
502
+ }
503
+ end
504
+
397
505
  def rstrip
398
506
  `#{self}.replace(/\\s*$/, '')`
399
507
  end
400
508
 
509
+ def scan(pattern, &block)
510
+ %x{
511
+ if (pattern.global) {
512
+ // should we clear it afterwards too?
513
+ pattern.lastIndex = 0;
514
+ }
515
+ else {
516
+ // rewrite regular expression to add the global flag to capture pre/post match
517
+ pattern = new RegExp(pattern.source, 'g' + (pattern.multiline ? 'm' : '') + (pattern.ignoreCase ? 'i' : ''));
518
+ }
519
+
520
+ var result = [];
521
+ var match;
522
+
523
+ while ((match = pattern.exec(#{self})) != null) {
524
+ var match_data = #{MatchData.new `pattern`, `match`};
525
+ if (block === nil) {
526
+ match.length == 1 ? result.push(match[0]) : result.push(match.slice(1));
527
+ }
528
+ else {
529
+ match.length == 1 ? block(match[0]) : block.apply(#{self}, match.slice(1));
530
+ }
531
+ }
532
+
533
+ return (block !== nil ? #{self} : result);
534
+ }
535
+ end
536
+
401
537
  alias size length
402
538
 
403
539
  alias slice []
@@ -425,12 +561,35 @@ class String < `String`
425
561
  def sub(pattern, replace = undefined, &block)
426
562
  %x{
427
563
  if (typeof(replace) === 'string') {
564
+ // convert Ruby back reference to JavaScript back reference
565
+ replace = replace.replace(/\\\\([1-9])/g, '$$$1')
428
566
  return #{self}.replace(pattern, replace);
429
567
  }
430
568
  if (block !== nil) {
431
- return #{self}.replace(pattern, function(str, a) {
432
- #{ $1 = `a` };
433
- return block(str);
569
+ return #{self}.replace(pattern, function() {
570
+ // FIXME: this should be a formal MatchData object with all the goodies
571
+ var match_data = []
572
+ for (var i = 0, len = arguments.length; i < len; i++) {
573
+ var arg = arguments[i];
574
+ if (arg == undefined) {
575
+ match_data.push(nil);
576
+ }
577
+ else {
578
+ match_data.push(arg);
579
+ }
580
+ }
581
+
582
+ var str = match_data.pop();
583
+ var offset = match_data.pop();
584
+ var match_len = match_data.length;
585
+
586
+ // $1, $2, $3 not being parsed correctly in Ruby code
587
+ //for (var i = 1; i < match_len; i++) {
588
+ // __gvars[String(i)] = match_data[i];
589
+ //}
590
+ #{$& = `match_data[0]`};
591
+ #{$~ = `match_data`};
592
+ return block(match_data[0]);
434
593
  });
435
594
  }
436
595
  else if (replace !== undefined) {
@@ -452,7 +611,9 @@ class String < `String`
452
611
  }
453
612
  }
454
613
  else {
455
- return #{self}.replace(pattern, replace.toString());
614
+ // convert Ruby back reference to JavaScript back reference
615
+ replace = replace.toString().replace(/\\\\([1-9])/g, '$$$1')
616
+ return #{self}.replace(pattern, replace);
456
617
  }
457
618
  }
458
619
  end
@@ -533,15 +694,375 @@ class String < `String`
533
694
  alias to_str to_s
534
695
 
535
696
  alias to_sym intern
536
-
537
- def underscore
538
- `#{self}.replace(/[-\\s]+/g, '_')
539
- .replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1_$2')
540
- .replace(/([a-z\\d])([A-Z])/g, '$1_$2')
541
- .toLowerCase()`
697
+
698
+ def tr(from, to)
699
+ %x{
700
+ if (from.length == 0 || from === to) {
701
+ return #{self};
702
+ }
703
+
704
+ var subs = {};
705
+ var from_chars = from.split('');
706
+ var from_length = from_chars.length;
707
+ var to_chars = to.split('');
708
+ var to_length = to_chars.length;
709
+
710
+ var inverse = false;
711
+ var global_sub = null;
712
+ if (from_chars[0] === '^') {
713
+ inverse = true;
714
+ from_chars.shift();
715
+ global_sub = to_chars[to_length - 1]
716
+ from_length -= 1;
717
+ }
718
+
719
+ var from_chars_expanded = [];
720
+ var last_from = null;
721
+ var in_range = false;
722
+ for (var i = 0; i < from_length; i++) {
723
+ var char = from_chars[i];
724
+ if (last_from == null) {
725
+ last_from = char;
726
+ from_chars_expanded.push(char);
727
+ }
728
+ else if (char === '-') {
729
+ if (last_from === '-') {
730
+ from_chars_expanded.push('-');
731
+ from_chars_expanded.push('-');
732
+ }
733
+ else if (i == from_length - 1) {
734
+ from_chars_expanded.push('-');
735
+ }
736
+ else {
737
+ in_range = true;
738
+ }
739
+ }
740
+ else if (in_range) {
741
+ var start = last_from.charCodeAt(0) + 1;
742
+ var end = char.charCodeAt(0);
743
+ for (var c = start; c < end; c++) {
744
+ from_chars_expanded.push(String.fromCharCode(c));
745
+ }
746
+ from_chars_expanded.push(char);
747
+ in_range = null;
748
+ last_from = null;
749
+ }
750
+ else {
751
+ from_chars_expanded.push(char);
752
+ }
753
+ }
754
+
755
+ from_chars = from_chars_expanded;
756
+ from_length = from_chars.length;
757
+
758
+ if (inverse) {
759
+ for (var i = 0; i < from_length; i++) {
760
+ subs[from_chars[i]] = true;
761
+ }
762
+ }
763
+ else {
764
+ if (to_length > 0) {
765
+ var to_chars_expanded = [];
766
+ var last_to = null;
767
+ var in_range = false;
768
+ for (var i = 0; i < to_length; i++) {
769
+ var char = to_chars[i];
770
+ if (last_from == null) {
771
+ last_from = char;
772
+ to_chars_expanded.push(char);
773
+ }
774
+ else if (char === '-') {
775
+ if (last_to === '-') {
776
+ to_chars_expanded.push('-');
777
+ to_chars_expanded.push('-');
778
+ }
779
+ else if (i == to_length - 1) {
780
+ to_chars_expanded.push('-');
781
+ }
782
+ else {
783
+ in_range = true;
784
+ }
785
+ }
786
+ else if (in_range) {
787
+ var start = last_from.charCodeAt(0) + 1;
788
+ var end = char.charCodeAt(0);
789
+ for (var c = start; c < end; c++) {
790
+ to_chars_expanded.push(String.fromCharCode(c));
791
+ }
792
+ to_chars_expanded.push(char);
793
+ in_range = null;
794
+ last_from = null;
795
+ }
796
+ else {
797
+ to_chars_expanded.push(char);
798
+ }
799
+ }
800
+
801
+ to_chars = to_chars_expanded;
802
+ to_length = to_chars.length;
803
+ }
804
+
805
+ var length_diff = from_length - to_length;
806
+ if (length_diff > 0) {
807
+ var pad_char = (to_length > 0 ? to_chars[to_length - 1] : '');
808
+ for (var i = 0; i < length_diff; i++) {
809
+ to_chars.push(pad_char);
810
+ }
811
+ }
812
+
813
+ for (var i = 0; i < from_length; i++) {
814
+ subs[from_chars[i]] = to_chars[i];
815
+ }
816
+ }
817
+
818
+ var new_str = ''
819
+ for (var i = 0, length = #{self}.length; i < length; i++) {
820
+ var char = #{self}.charAt(i);
821
+ var sub = subs[char];
822
+ if (inverse) {
823
+ new_str += (sub == null ? global_sub : char);
824
+ }
825
+ else {
826
+ new_str += (sub != null ? sub : char);
827
+ }
828
+ }
829
+ return new_str;
830
+ }
831
+ end
832
+
833
+ def tr_s(from, to)
834
+ %x{
835
+ if (from.length == 0) {
836
+ return #{self};
837
+ }
838
+
839
+ var subs = {};
840
+ var from_chars = from.split('');
841
+ var from_length = from_chars.length;
842
+ var to_chars = to.split('');
843
+ var to_length = to_chars.length;
844
+
845
+ var inverse = false;
846
+ var global_sub = null;
847
+ if (from_chars[0] === '^') {
848
+ inverse = true;
849
+ from_chars.shift();
850
+ global_sub = to_chars[to_length - 1]
851
+ from_length -= 1;
852
+ }
853
+
854
+ var from_chars_expanded = [];
855
+ var last_from = null;
856
+ var in_range = false;
857
+ for (var i = 0; i < from_length; i++) {
858
+ var char = from_chars[i];
859
+ if (last_from == null) {
860
+ last_from = char;
861
+ from_chars_expanded.push(char);
862
+ }
863
+ else if (char === '-') {
864
+ if (last_from === '-') {
865
+ from_chars_expanded.push('-');
866
+ from_chars_expanded.push('-');
867
+ }
868
+ else if (i == from_length - 1) {
869
+ from_chars_expanded.push('-');
870
+ }
871
+ else {
872
+ in_range = true;
873
+ }
874
+ }
875
+ else if (in_range) {
876
+ var start = last_from.charCodeAt(0) + 1;
877
+ var end = char.charCodeAt(0);
878
+ for (var c = start; c < end; c++) {
879
+ from_chars_expanded.push(String.fromCharCode(c));
880
+ }
881
+ from_chars_expanded.push(char);
882
+ in_range = null;
883
+ last_from = null;
884
+ }
885
+ else {
886
+ from_chars_expanded.push(char);
887
+ }
888
+ }
889
+
890
+ from_chars = from_chars_expanded;
891
+ from_length = from_chars.length;
892
+
893
+ if (inverse) {
894
+ for (var i = 0; i < from_length; i++) {
895
+ subs[from_chars[i]] = true;
896
+ }
897
+ }
898
+ else {
899
+ if (to_length > 0) {
900
+ var to_chars_expanded = [];
901
+ var last_to = null;
902
+ var in_range = false;
903
+ for (var i = 0; i < to_length; i++) {
904
+ var char = to_chars[i];
905
+ if (last_from == null) {
906
+ last_from = char;
907
+ to_chars_expanded.push(char);
908
+ }
909
+ else if (char === '-') {
910
+ if (last_to === '-') {
911
+ to_chars_expanded.push('-');
912
+ to_chars_expanded.push('-');
913
+ }
914
+ else if (i == to_length - 1) {
915
+ to_chars_expanded.push('-');
916
+ }
917
+ else {
918
+ in_range = true;
919
+ }
920
+ }
921
+ else if (in_range) {
922
+ var start = last_from.charCodeAt(0) + 1;
923
+ var end = char.charCodeAt(0);
924
+ for (var c = start; c < end; c++) {
925
+ to_chars_expanded.push(String.fromCharCode(c));
926
+ }
927
+ to_chars_expanded.push(char);
928
+ in_range = null;
929
+ last_from = null;
930
+ }
931
+ else {
932
+ to_chars_expanded.push(char);
933
+ }
934
+ }
935
+
936
+ to_chars = to_chars_expanded;
937
+ to_length = to_chars.length;
938
+ }
939
+
940
+ var length_diff = from_length - to_length;
941
+ if (length_diff > 0) {
942
+ var pad_char = (to_length > 0 ? to_chars[to_length - 1] : '');
943
+ for (var i = 0; i < length_diff; i++) {
944
+ to_chars.push(pad_char);
945
+ }
946
+ }
947
+
948
+ for (var i = 0; i < from_length; i++) {
949
+ subs[from_chars[i]] = to_chars[i];
950
+ }
951
+ }
952
+ var new_str = ''
953
+ var last_substitute = null
954
+ for (var i = 0, length = #{self}.length; i < length; i++) {
955
+ var char = #{self}.charAt(i);
956
+ var sub = subs[char]
957
+ if (inverse) {
958
+ if (sub == null) {
959
+ if (last_substitute == null) {
960
+ new_str += global_sub;
961
+ last_substitute = true;
962
+ }
963
+ }
964
+ else {
965
+ new_str += char;
966
+ last_substitute = null;
967
+ }
968
+ }
969
+ else {
970
+ if (sub != null) {
971
+ if (last_substitute == null || last_substitute !== sub) {
972
+ new_str += sub;
973
+ last_substitute = sub;
974
+ }
975
+ }
976
+ else {
977
+ new_str += char;
978
+ last_substitute = null;
979
+ }
980
+ }
981
+ }
982
+ return new_str;
983
+ }
542
984
  end
543
985
 
544
986
  alias_native :upcase, :toUpperCase
545
987
  end
546
988
 
547
989
  Symbol = String
990
+
991
+ class MatchData < Array
992
+ attr_reader :post_match, :pre_match, :regexp, :string
993
+
994
+ def self.new(regexp, match_groups)
995
+ %x{
996
+ var instance = new Opal.MatchData;
997
+ for (var i = 0, len = match_groups.length; i < len; i++) {
998
+ var group = match_groups[i];
999
+ if (group == undefined) {
1000
+ instance.push(nil);
1001
+ }
1002
+ else {
1003
+ instance.push(group);
1004
+ }
1005
+ }
1006
+ instance._begin = match_groups.index;
1007
+ instance.regexp = regexp;
1008
+ instance.string = match_groups.input;
1009
+ instance.pre_match = #{$` = `instance.string.substr(0, regexp.lastIndex - instance[0].length)`};
1010
+ instance.post_match = #{$' = `instance.string.substr(regexp.lastIndex)`};
1011
+ return #{$~ = `instance`};
1012
+ }
1013
+ end
1014
+
1015
+ def begin(pos)
1016
+ %x{
1017
+ if (pos == 0 || pos == 1) {
1018
+ return #{self}._begin;
1019
+ }
1020
+ else {
1021
+ #{raise ArgumentError, 'MatchData#begin only supports 0th element'};
1022
+ }
1023
+ }
1024
+ end
1025
+
1026
+ def captures
1027
+ `#{self}.slice(1)`
1028
+ end
1029
+
1030
+ def inspect
1031
+ %x{
1032
+ var str = "<#MatchData " + #{self}[0].$inspect()
1033
+ for (var i = 1, len = #{self}.length; i < len; i++) {
1034
+ str += " " + i + ":" + #{self}[i].$inspect();
1035
+ }
1036
+ str += ">";
1037
+ return str;
1038
+ }
1039
+ end
1040
+
1041
+ def to_s
1042
+ `#{self}[0]`
1043
+ end
1044
+
1045
+ def values_at(*indexes)
1046
+ %x{
1047
+ var vals = [];
1048
+ var match_length = #{self}.length;
1049
+ for (var i = 0, length = indexes.length; i < length; i++) {
1050
+ var pos = indexes[i];
1051
+ if (pos >= 0) {
1052
+ vals.push(#{self}[pos]);
1053
+ }
1054
+ else {
1055
+ pos = match_length + pos;
1056
+ if (pos > 0) {
1057
+ vals.push(#{self}[pos]);
1058
+ }
1059
+ else {
1060
+ vals.push(nil);
1061
+ }
1062
+ }
1063
+ }
1064
+
1065
+ return vals;
1066
+ }
1067
+ end
1068
+ end