Skip to content
This repository

Array specs #52

Merged
merged 22 commits into from about 2 years ago

2 participants

Gallagher Group R&D Department Tomas Matousek
Gallagher Group R&D Department

Update IronRuby to pass more of rubyspec core/array specs

and others added some commits January 04, 2012
Gallagher Group R&D Department Update implementation of Enumerable.zip to call .each on args if .to_…
…ary fails (as per rubyspec)
a3d5012
Update implementation of Array.uniq and uniq! to use blocks correctly…
… (as per rubyspec)

Bugfix uniq! when dealing with recursive arrays (as per rubyspec)
5a52d46
Update implementation of Array[]= to check frozen before coercing arg…
…s, and change the error message to match MRI 1.9.2 (as per rubyspec)
510023a
Update implementation of Array#fill to check frozen on empty array, a…
…nd do proper boundary checking (as per rubyspec)
ff5f4bf
Update implementation of Array.shuffle! to check frozen correctly (as…
… per rubyspec)
3ce9b1f
Implement Array#select! (as per rubyspec) 8208196
Update Array#shift to check for frozen correctly (as per rubyspec)
Implement Array#shift(n) (as per rubyspec)
7ded4c3
Implement Array#sample and Arran#sample(n) as per rubyspec f041d20
Implement Array#rotate and Array#rotate! as per rubyspec b687d8b
Implement Array#rindex when called with no args and no block (reverse…
… index-finding enumerator) as per rubyspec
62f936c
Array#pop should check frozen even when empty (as per rubyspec). Also…
… update other fixes to use existing implementation of RequireNotFrozen(IList) instead of manually casting
a1ec97c
#to_ary is allowed to return nil. Fixes Array#flatten as per rubyspec 411a3e5
Add range checking to Array#product so the tests no longer run out of…
… memory and hang (also part of rubyspec error checking)
3f5b7a6
Minor fixes:
- Some methods were declared as taking RubyArray parameters instead of IList
- One more instance of RequireNotFrozen
b3efe76
Minor fixes:
- Some methods were declared as taking RubyArray parameters instead of IList
- One more instance of RequireNotFrozen
b017689
Resolve merge conflict caused by accidental checkin of wrong initiali…
…zers.generated file
e83501a
Merge branch 'master' into array_specs adfd117
I was using ArrayList (which is not available in Silverlight) interna…
…lly Array#sample. Update to use List<object>
7975d9e
Update Array#slice! to deal with out-of-range values as per rubyspec ae966af
Update Array#inspect to taint result strings correctly as per rubyspec c89e236
Implement Array#keep_if as per rubyspec e92404b
Update Array#product to handle block parameters as per rubyspec ede005c
Tomas Matousek tmat merged commit ede005c into from March 03, 2012
Tomas Matousek tmat closed this March 03, 2012
Tomas Matousek
Owner
tmat commented March 03, 2012

Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 22 unique commits by 2 authors.

Jan 04, 2012
Gallagher Group R&D Department Update implementation of Enumerable.zip to call .each on args if .to_…
…ary fails (as per rubyspec)
a3d5012
Update implementation of Array.uniq and uniq! to use blocks correctly…
… (as per rubyspec)

Bugfix uniq! when dealing with recursive arrays (as per rubyspec)
5a52d46
Jan 05, 2012
Update implementation of Array[]= to check frozen before coercing arg…
…s, and change the error message to match MRI 1.9.2 (as per rubyspec)
510023a
Update implementation of Array#fill to check frozen on empty array, a…
…nd do proper boundary checking (as per rubyspec)
ff5f4bf
Update implementation of Array.shuffle! to check frozen correctly (as…
… per rubyspec)
3ce9b1f
Implement Array#select! (as per rubyspec) 8208196
Update Array#shift to check for frozen correctly (as per rubyspec)
Implement Array#shift(n) (as per rubyspec)
7ded4c3
Implement Array#sample and Arran#sample(n) as per rubyspec f041d20
Jan 06, 2012
Implement Array#rotate and Array#rotate! as per rubyspec b687d8b
Implement Array#rindex when called with no args and no block (reverse…
… index-finding enumerator) as per rubyspec
62f936c
Array#pop should check frozen even when empty (as per rubyspec). Also…
… update other fixes to use existing implementation of RequireNotFrozen(IList) instead of manually casting
a1ec97c
#to_ary is allowed to return nil. Fixes Array#flatten as per rubyspec 411a3e5
Add range checking to Array#product so the tests no longer run out of…
… memory and hang (also part of rubyspec error checking)
3f5b7a6
Minor fixes:
- Some methods were declared as taking RubyArray parameters instead of IList
- One more instance of RequireNotFrozen
b3efe76
Minor fixes:
- Some methods were declared as taking RubyArray parameters instead of IList
- One more instance of RequireNotFrozen
b017689
Resolve merge conflict caused by accidental checkin of wrong initiali…
…zers.generated file
e83501a
Feb 01, 2012
Merge branch 'master' into array_specs adfd117
I was using ArrayList (which is not available in Silverlight) interna…
…lly Array#sample. Update to use List<object>
7975d9e
Update Array#slice! to deal with out-of-range values as per rubyspec ae966af
Update Array#inspect to taint result strings correctly as per rubyspec c89e236
Implement Array#keep_if as per rubyspec e92404b
Update Array#product to handle block parameters as per rubyspec ede005c
This page is out of date. Refresh to see the latest.
21  Languages/Ruby/Libraries/Builtins/Enumerable.cs
@@ -681,16 +681,33 @@ public static class Enumerable {
681 681
         #region zip
682 682
 
683 683
         [RubyMethod("zip")]
684  
-        public static object Zip(CallSiteStorage<EachSite>/*!*/ each, BlockParam block, object self, [DefaultProtocol, NotNullItems]params IList/*!*/[]/*!*/ args) {
  684
+        public static object Zip(CallSiteStorage<EachSite>/*!*/ each, ConversionStorage<IList>/*!*/ tryToAry, CallSiteStorage<EachSite>/*!*/ otherEach, BlockParam block, object self, [DefaultProtocol, NotNullItems] params object/*!*/[]/*!*/ args) {
685 685
             RubyArray results = (block == null) ? new RubyArray() : null;
686 686
             object result = results;
687 687
 
  688
+            // coerce the args into arrays
  689
+            var coercedArgs = new List<IList>(args.Length);
  690
+            foreach (var otherArrayObject in args) {
  691
+                IList otherArray = Protocols.TryCastToArray(tryToAry, otherArrayObject);
  692
+                if (otherArray != null) {
  693
+                    coercedArgs.Add(otherArray);
  694
+                } else { // added in MRI 1.9.2 - if to_ary fails, try call .each to extract values
  695
+                    otherArray = new List<object>();
  696
+                    Each(otherEach, otherArrayObject, Proc.Create(otherEach.Context, delegate(BlockParam/*!*/ selfBlock, object _, object item) {
  697
+                        otherArray.Add(item);
  698
+                        return null;
  699
+                    }));
  700
+                    coercedArgs.Add(otherArray);
  701
+                }
  702
+            }
  703
+
  704
+
688 705
             int index = 0;
689 706
             Each(each, self, Proc.Create(each.Context, delegate(BlockParam/*!*/ selfBlock, object _, object item) {
690 707
                 // Collect items
691 708
                 RubyArray array = new RubyArray(args.Length + 1);
692 709
                 array.Add(item);
693  
-                foreach (IList otherArray in args) {
  710
+                foreach (var otherArray in coercedArgs) {
694 711
                     if (index < otherArray.Count) {
695 712
                         array.Add(otherArray[index]);
696 713
                     } else {
341  Languages/Ruby/Libraries/Extensions/IListOps.cs
@@ -41,7 +41,7 @@ public static class IListOps {
41 41
         private static void RequireNotFrozen(IList/*!*/ self) {
42 42
             RubyArray array = self as RubyArray;
43 43
             if (array != null && array.IsFrozen) {
44  
-                throw RubyExceptions.CreateObjectFrozenError();
  44
+                throw RubyExceptions.CreateArrayFrozenError();
45 45
             }
46 46
         }
47 47
 
@@ -312,24 +312,43 @@ public static class IListOps {
312 312
         }
313 313
 
314 314
         [RubyMethod("product")]
315  
-        public static RubyArray/*!*/ Product(IList/*!*/ self, [DefaultProtocol, NotNullItems]params IList/*!*/[]/*!*/ arrays) {
  315
+        public static IList/*!*/ Product(BlockParam block, IList/*!*/ self, [DefaultProtocol, NotNullItems]params IList/*!*/[]/*!*/ arrays) {
316 316
             var result = new RubyArray();
  317
+            object blockResult = null;
317 318
             
318 319
             if (self.Count == 0) {
319  
-                return result;
  320
+                return self;
320 321
             }
  322
+            
  323
+            int requiredCapacity = 1;
321 324
             for (int i = 0; i < arrays.Length; i++) {
322 325
                 if (arrays[i].Count == 0) {
  326
+                    if (block != null) { // [1,2].product([]) should produce [], but [1,2].product([]){ } should produce [1,2] due to empty block
  327
+                        return self;
  328
+                    }
323 329
                     return result;
324 330
                 }
  331
+                try {
  332
+                    requiredCapacity = checked(requiredCapacity * arrays[i].Count);
  333
+                } catch (OverflowException) {
  334
+                    throw RubyExceptions.CreateRangeError("too big to product");
  335
+                }
325 336
             }
326  
-            
  337
+                        
327 338
             int[] indices = new int[1 + arrays.Length];
328 339
             while (true) {
329 340
                 var current = new RubyArray(indices.Length);
330 341
                 for (int i = 0; i < indices.Length; i++) {
331 342
                     current[i] = GetNth(i, self, arrays)[indices[i]];
332 343
                 }
  344
+
  345
+                if (block != null) {
  346
+                    block.Yield(current, out blockResult);
  347
+                    if (blockResult == null) {
  348
+                        return self;
  349
+                    }
  350
+                }
  351
+
333 352
                 result.Add(current);
334 353
 
335 354
                 // increment indices:
@@ -519,7 +538,7 @@ public static class IListOps {
519 538
 
520 539
             return self[index] = value;
521 540
         }
522  
-
  541
+        
523 542
         [RubyMethod("[]=")]
524 543
         public static object SetElement(IList/*!*/ self, [DefaultProtocol]int index, object value) {
525 544
             index = NormalizeIndexThrowIfNegative(self, index);
@@ -534,11 +553,20 @@ public static class IListOps {
534 553
         }
535 554
 
536 555
         [RubyMethod("[]=")]
  556
+        public static object SetElement(ConversionStorage<IList>/*!*/ arrayTryCast, ConversionStorage<int> fixnumCast,
  557
+            IList/*!*/ self, object index, object length, object value) {
  558
+
  559
+            RequireNotFrozen(self); // rubyspec says we must check for frozen before trying to coerce the index
  560
+            return SetElement(arrayTryCast, self as IList, Protocols.CastToFixnum(fixnumCast, index), Protocols.CastToFixnum(fixnumCast, length), value);
  561
+        }
  562
+
  563
+        [RubyMethod("[]=")]
537 564
         public static object SetElement(ConversionStorage<IList>/*!*/ arrayTryCast, IList/*!*/ self, 
538 565
             [DefaultProtocol]int index, [DefaultProtocol]int length, object value) {
539 566
             if (length < 0) {
540 567
                 throw RubyExceptions.CreateIndexError("negative length ({0})", length);
541 568
             }
  569
+            RequireNotFrozen(self);
542 570
 
543 571
             index = NormalizeIndexThrowIfNegative(self, index);
544 572
 
@@ -584,24 +612,36 @@ public static class IListOps {
584 612
 
585 613
         [RubyMethod("[]=")]
586 614
         public static object SetElement(ConversionStorage<IList>/*!*/ arrayTryCast, ConversionStorage<int>/*!*/ fixnumCast, 
587  
-            IList/*!*/ self, [NotNull]Range/*!*/ range, object value) {
  615
+            IList/*!*/ self, object rangeOrIndex, object value) {
  616
+            
  617
+            RequireNotFrozen(self);
588 618
 
589  
-            int start, count;
590  
-            RangeToStartAndCount(fixnumCast, range, self.Count, out start, out count);
591  
-            return SetElement(arrayTryCast, self, start, count, value);
  619
+            var range = rangeOrIndex as Range;
  620
+            if (range == null) {
  621
+                return SetElement(self, Protocols.CastToFixnum(fixnumCast, rangeOrIndex), value);
  622
+            } else {
  623
+                int start, count;
  624
+                if (TryRangeToStartAndCount(fixnumCast, range, self.Count, out start, out count)) {
  625
+                    return SetElement(arrayTryCast, self, start, count, value);
  626
+                } else {
  627
+                    throw RubyExceptions.CreateRangeError("{0} out of range", range);
  628
+                }
  629
+            }
592 630
         }
593 631
 
594  
-        private static void RangeToStartAndCount(ConversionStorage<int>/*!*/ fixnumCast, Range/*!*/ range, int length, out int start, out int count) {
  632
+        private static bool TryRangeToStartAndCount(ConversionStorage<int>/*!*/ fixnumCast, Range/*!*/ range, int length, out int start, out int count) {
595 633
             start = Protocols.CastToFixnum(fixnumCast, range.Begin);
596 634
             int end = Protocols.CastToFixnum(fixnumCast, range.End);
597 635
 
598 636
             start = start < 0 ? start + length : start;
599 637
             if (start < 0) {
600  
-                throw RubyExceptions.CreateRangeError("{0}..{1} out of range", start, end);
  638
+                count = -1;
  639
+                return false;
601 640
             }
602 641
 
603 642
             end = end < 0 ? end + length : end;
604 643
             count = Math.Max(range.ExcludeEnd ? end - start : end - start + 1, 0);
  644
+            return true;
605 645
         }
606 646
 
607 647
         #endregion
@@ -633,18 +673,23 @@ public static class IListOps {
633 673
             return result;
634 674
         }
635 675
 
636  
-        private static void AddUniqueItems(IList/*!*/ list, IList/*!*/ result, Dictionary<object, bool> seen, ref bool nilSeen) {
  676
+        private static void AddUniqueItems(BlockParam block, IList/*!*/ list, IList/*!*/ result, Dictionary<object, bool> seen, ref bool nilSeen) {
637 677
             foreach (object item in list) {
638  
-                if (item == null) {
  678
+                object key;
  679
+                if (block == null || block.Yield(item, out key)) {
  680
+                    key = item;
  681
+                }
  682
+
  683
+                if (key == null) {
639 684
                     if (!nilSeen) {
640 685
                         nilSeen = true;
641  
-                        result.Add(null);
  686
+                        result.Add(item);
642 687
                     }
643 688
                     continue;
644 689
                 }
645 690
 
646  
-                if (!seen.ContainsKey(item)) {
647  
-                    seen.Add(item, true);
  691
+                if (!seen.ContainsKey(key)) {
  692
+                    seen.Add(key, true);
648 693
                     result.Add(item);
649 694
                 }
650 695
             }
@@ -658,9 +703,9 @@ public static class IListOps {
658 703
             var result = new RubyArray();
659 704
 
660 705
             // Union merges the two arrays, removing duplicates
661  
-            AddUniqueItems(self, result, seen, ref nilSeen);
  706
+            AddUniqueItems(null, self, result, seen, ref nilSeen);
662 707
 
663  
-            AddUniqueItems(other, result, seen, ref nilSeen);
  708
+            AddUniqueItems(null, other, result, seen, ref nilSeen);
664 709
 
665 710
             return result;
666 711
         }
@@ -749,7 +794,7 @@ public static class IListOps {
749 794
 
750 795
         #endregion
751 796
 
752  
-        #region delete, delete_at, reject, reject!
  797
+        #region delete, delete_at, reject, reject!, select!, keep_if
753 798
 
754 799
         public static bool Remove(BinaryOpStorage/*!*/ equals, IList/*!*/ self, object item) {
755 800
             int i = 0;
@@ -801,7 +846,7 @@ public static class IListOps {
801 846
 
802 847
         private static object DeleteIfImpl(BlockParam/*!*/ block, IList/*!*/ self) {
803 848
             bool changed, jumped;
804  
-            DeleteIf(block, self, out changed, out jumped);
  849
+            DeleteIf(block, self, RubyOps.IsTrue, out changed, out jumped);
805 850
             return self;
806 851
         }
807 852
 
@@ -812,7 +857,7 @@ public static class IListOps {
812 857
 
813 858
         private static object RejectInPlaceImpl(BlockParam/*!*/ block, IList/*!*/ self) {
814 859
             bool changed, jumped;
815  
-            object result = DeleteIf(block, self, out changed, out jumped);
  860
+            object result = DeleteIf(block, self, RubyOps.IsTrue, out changed, out jumped);
816 861
             return jumped ? result : changed ? self : null;
817 862
         }
818 863
 
@@ -842,7 +887,30 @@ public static class IListOps {
842 887
             return result;
843 888
         }
844 889
 
845  
-        private static object DeleteIf(BlockParam/*!*/ block, IList/*!*/ self, out bool changed, out bool jumped) {
  890
+        [RubyMethod("select!")]
  891
+        public static object SelectInPlace(BlockParam block, IList/*!*/ self) {
  892
+            return (block != null) ? SelectInPlaceImpl(block, self) : new Enumerator((_, innerBlock) => SelectInPlaceImpl(innerBlock, self));
  893
+        }
  894
+
  895
+        private static object SelectInPlaceImpl(BlockParam/*!*/ block, IList/*!*/ self) {
  896
+            bool changed, jumped;
  897
+            object result = DeleteIf(block, self, RubyOps.IsFalse, out changed, out jumped);
  898
+            return jumped ? result : changed ? self : null;
  899
+        }
  900
+
  901
+        [RubyMethod("keep_if")]
  902
+        public static object KeepIf(BlockParam block, IList/*!*/ self) {
  903
+            // as far as I can tell the only difference between select! and keep_if, is that keep_if returns self if it doesn't modify the array whereas select! returns nil
  904
+            return (block != null) ? KeepIfImpl(block, self) : new Enumerator((_, innerBlock) => KeepIfImpl(innerBlock, self));
  905
+        }
  906
+
  907
+        private static object KeepIfImpl(BlockParam/*!*/ block, IList/*!*/ self) {
  908
+            bool changed, jumped;
  909
+            object result = DeleteIf(block, self, RubyOps.IsFalse, out changed, out jumped);
  910
+            return jumped ? result : self;
  911
+        }
  912
+                
  913
+        private static object DeleteIf(BlockParam/*!*/ block, IList/*!*/ self, Func<object, bool> predicate, out bool changed, out bool jumped) {
846 914
             Assert.NotNull(block, self);
847 915
 
848 916
             changed = false;
@@ -859,7 +927,7 @@ public static class IListOps {
859 927
                     return result;
860 928
                 }
861 929
 
862  
-                if (RubyOps.IsTrue(result)) {
  930
+                if (predicate(result)) {
863 931
                     changed = true;
864 932
                     self.RemoveAt(i);
865 933
                 } else {
@@ -964,6 +1032,8 @@ public static class IListOps {
964 1032
 
965 1033
         [RubyMethod("fill")]
966 1034
         public static IList/*!*/ Fill(IList/*!*/ self, object obj, [DefaultParameterValue(0)]int start) {
  1035
+            RequireNotFrozen(self);
  1036
+            
967 1037
             // Note: Array#fill(obj, start) is not equivalent to Array#fill(obj, start, 0)
968 1038
             // (as per MRI behavior, the latter can expand the array if start > length, but the former doesn't)
969 1039
             start = Math.Max(0, NormalizeIndex(self, start));
@@ -976,6 +1046,10 @@ public static class IListOps {
976 1046
 
977 1047
         [RubyMethod("fill")]
978 1048
         public static IList/*!*/ Fill(IList/*!*/ self, object obj, int start, int length) {
  1049
+            if (length > (int.MaxValue / 20)) { // This is roughly what MRI array max size is
  1050
+                throw RubyExceptions.CreateArgumentError("argument too big");
  1051
+            }
  1052
+
979 1053
             // Note: Array#fill(obj, start) is not equivalent to Array#fill(obj, start, 0)
980 1054
             // (as per MRI behavior, the latter can expand the array if start > length, but the former doesn't)
981 1055
             start = Math.Max(0, NormalizeIndex(self, start));
@@ -990,7 +1064,11 @@ public static class IListOps {
990 1064
         }
991 1065
 
992 1066
         [RubyMethod("fill")]
993  
-        public static IList/*!*/ Fill(ConversionStorage<int>/*!*/ fixnumCast, IList/*!*/ self, object obj, object start, [DefaultParameterValue(null)]object length) {
  1067
+        public static IList/*!*/ Fill(ConversionStorage<int>/*!*/ fixnumCast, BlockParam block, IList/*!*/ self, object obj, object start, [DefaultParameterValue(null)]object length) {
  1068
+            if (block != null) { // 3 arguments requires no block be passed, but because of the way IronRuby selects methods, we must explicitly check for the block
  1069
+                throw RubyExceptions.CreateArgumentError("wrong number of arguments (3 for 0..2)");
  1070
+            }
  1071
+
994 1072
             int startFixnum = (start == null) ? 0 : Protocols.CastToFixnum(fixnumCast, start);
995 1073
             if (length == null) {
996 1074
                 return Fill(self, obj, startFixnum);
@@ -1003,6 +1081,9 @@ public static class IListOps {
1003 1081
         public static IList/*!*/ Fill(ConversionStorage<int>/*!*/ fixnumCast, IList/*!*/ self, object obj, [NotNull]Range/*!*/ range) {
1004 1082
             int begin = NormalizeIndex(self, Protocols.CastToFixnum(fixnumCast, range.Begin));
1005 1083
             int end = NormalizeIndex(self, Protocols.CastToFixnum(fixnumCast, range.End));
  1084
+            if (begin < 0 || end < 0) {
  1085
+                throw RubyExceptions.CreateRangeError("{0} out of range", range);
  1086
+            }
1006 1087
             int length = Math.Max(0, end - begin + (range.ExcludeEnd ? 0 : 1));
1007 1088
 
1008 1089
             return Fill(self, obj, begin, length);
@@ -1053,6 +1134,9 @@ public static class IListOps {
1053 1134
         public static object Fill(ConversionStorage<int>/*!*/ fixnumCast, [NotNull]BlockParam/*!*/ block, IList/*!*/ self, [NotNull]Range/*!*/ range) {
1054 1135
             int begin = NormalizeIndex(self, Protocols.CastToFixnum(fixnumCast, range.Begin));
1055 1136
             int end = NormalizeIndex(self, Protocols.CastToFixnum(fixnumCast, range.End));
  1137
+            if (begin < 0 || end < 0) {
  1138
+                throw RubyExceptions.CreateRangeError("{0} out of range", range);
  1139
+            }
1056 1140
             int length = Math.Max(0, end - begin + (range.ExcludeEnd ? 0 : 1));
1057 1141
 
1058 1142
             return Fill(block, self, begin, length);
@@ -1322,6 +1406,23 @@ public static class IListOps {
1322 1406
         }
1323 1407
 
1324 1408
         [RubyMethod("rindex")]
  1409
+        public static Enumerator/*!*/ GetReverseIndexEnumerator(IList/*!*/ self) { // when rindex is called with no args and no block, we produce a reverse value enumerator. When the enumerator is each'ed over, if the block returns true, we return the index at which that happened
  1410
+            return new Enumerator((_, innerBlock) => {
  1411
+                object result;
  1412
+                for(int i=self.Count - 1; i >= 0; i--) {
  1413
+                    if(innerBlock.Yield(self[i], out result)) {
  1414
+                        return null; // block exited with break or similar
  1415
+                    }
  1416
+                    if(RubyOps.IsTrue(result)) {
  1417
+                        return i;
  1418
+                    }
  1419
+                }
  1420
+
  1421
+                return null;
  1422
+            });
  1423
+        }
  1424
+
  1425
+        [RubyMethod("rindex")]
1325 1426
         public static object ReverseIndex([NotNull]BlockParam/*!*/ predicate, IList/*!*/ self) {
1326 1427
             foreach (int i in IListOps.ReverseEnumerateIndexes(self)) {
1327 1428
                 object blockResult;
@@ -1529,6 +1630,10 @@ public static class IListOps {
1529 1630
                     return MutableString.CreateAscii("[...]");
1530 1631
                 }
1531 1632
                 MutableString str = MutableString.CreateMutable(RubyEncoding.Binary);
  1633
+                if (self.Count > 0) { // tainted empty arrays don't taint the inspect string if the array is empty
  1634
+                    str.TaintBy(self, context);
  1635
+                }
  1636
+
1532 1637
                 str.Append('[');
1533 1638
                 bool first = true;
1534 1639
                 foreach (object obj in self) {
@@ -1537,7 +1642,10 @@ public static class IListOps {
1537 1642
                     } else {
1538 1643
                         str.Append(", ");
1539 1644
                     }
1540  
-                    str.Append(context.Inspect(obj));
  1645
+
  1646
+                    var objInspected = context.Inspect(obj);
  1647
+                    str.Append(objInspected);
  1648
+                    str.TaintBy(objInspected);
1541 1649
                 }
1542 1650
                 str.Append(']');
1543 1651
                 return str;
@@ -1645,6 +1753,7 @@ public static class IListOps {
1645 1753
 
1646 1754
         [RubyMethod("pop")]
1647 1755
         public static object Pop(IList/*!*/ self) {
  1756
+            RequireNotFrozen(self);
1648 1757
             if (self.Count == 0) {
1649 1758
                 return null;
1650 1759
             }
@@ -1676,6 +1785,7 @@ public static class IListOps {
1676 1785
 
1677 1786
         [RubyMethod("shift")]
1678 1787
         public static object Shift(IList/*!*/ self) {
  1788
+            RequireNotFrozen(self);
1679 1789
             if (self.Count == 0) {
1680 1790
                 return null;
1681 1791
             }
@@ -1685,6 +1795,32 @@ public static class IListOps {
1685 1795
             return result;
1686 1796
         }
1687 1797
 
  1798
+        [RubyMethod("shift")]
  1799
+        public static object Shift(UnaryOpStorage/*!*/ allocateStorage, IList/*!*/ self, [DefaultProtocol]int elementCount) {
  1800
+            if (elementCount < 0) {
  1801
+                throw RubyExceptions.CreateArgumentError("negative array size");
  1802
+            }
  1803
+
  1804
+            RequireNotFrozen(self);
  1805
+
  1806
+            IList resultList = CreateResultArray(allocateStorage, self);
  1807
+
  1808
+            if (self.Count == 0) {
  1809
+                return resultList;
  1810
+            }
  1811
+
  1812
+            while (elementCount-- > 0) {
  1813
+                if (self.Count == 0) {
  1814
+                    break;
  1815
+                }
  1816
+
  1817
+                object result = self[0];
  1818
+                self.RemoveAt(0);
  1819
+                resultList.Add(result);
  1820
+            }
  1821
+            return resultList;
  1822
+        }
  1823
+
1688 1824
         [RubyMethod("unshift")]
1689 1825
         public static IList/*!*/ Unshift(IList/*!*/ self, object/*!*/ arg) {
1690 1826
             self.Insert(0, arg);
@@ -1725,15 +1861,25 @@ public static class IListOps {
1725 1861
 
1726 1862
             IList result = GetElements(fixnumCast, allocateStorage, self, range);
1727 1863
             int start, count;
1728  
-            RangeToStartAndCount(fixnumCast, range, self.Count, out start, out count);
1729  
-            DeleteElements(self, start, count);
1730  
-            return result;
  1864
+            if (TryRangeToStartAndCount(fixnumCast, range, self.Count, out start, out count)) {
  1865
+                return SliceInPlace(allocateStorage, self, start, count);
  1866
+            } else { // out of range
  1867
+                return null;
  1868
+            }
1731 1869
         }
1732 1870
 
1733 1871
         [RubyMethod("slice!")]
1734 1872
         public static IList SliceInPlace(UnaryOpStorage/*!*/ allocateStorage, 
1735 1873
             IList/*!*/ self, [DefaultProtocol]int start, [DefaultProtocol]int length) {
1736 1874
 
  1875
+            start = NormalizeIndex(self, start);
  1876
+
  1877
+            if (start > self.Count || start < 0) {
  1878
+                return null;
  1879
+            } else if (start == self.Count) {
  1880
+                return CreateResultArray(allocateStorage, self);
  1881
+            }
  1882
+
1737 1883
             IList result = GetElements(allocateStorage, self, start, length);
1738 1884
             DeleteElements(self, start, length);
1739 1885
             return result;
@@ -1785,7 +1931,7 @@ public static class IListOps {
1785 1931
 
1786 1932
         #endregion
1787 1933
 
1788  
-        #region shuffle, shuffle!
  1934
+        #region shuffle, shuffle!, sample
1789 1935
 
1790 1936
         [RubyMethod("shuffle")]
1791 1937
         public static IList/*!*/ Shuffle(UnaryOpStorage/*!*/ allocateStorage, RubyArray/*!*/ self) {
@@ -1813,6 +1959,7 @@ public static class IListOps {
1813 1959
 
1814 1960
         [RubyMethod("shuffle!")]
1815 1961
         public static RubyArray/*!*/ ShuffleInPlace(RubyContext/*!*/ context, RubyArray/*!*/ self) {
  1962
+            self.RequireNotFrozen();
1816 1963
             var generator = context.RandomNumberGenerator;
1817 1964
             for (int i = self.Count - 1; i >= 0; i--) {
1818 1965
                 int j = generator.Next(i + 1);
@@ -1823,6 +1970,113 @@ public static class IListOps {
1823 1970
             return self;
1824 1971
         }
1825 1972
 
  1973
+        [RubyMethod("sample")]
  1974
+        public static object Sample(RubyContext/*!*/ context, IList/*!*/ self) {
  1975
+            var generator = context.RandomNumberGenerator;
  1976
+            if (self.Count == 0) {
  1977
+                return null;
  1978
+            }
  1979
+            return self[generator.Next(self.Count)];
  1980
+        }
  1981
+
  1982
+        [RubyMethod("sample")]
  1983
+        public static IList/*!*/ Sample(UnaryOpStorage/*!*/ allocateStorage, ConversionStorage<int>/*!*/ fixnumCast, IList/*!*/ self, object elementCount) {
  1984
+            return Sample(allocateStorage, self, Protocols.CastToFixnum(fixnumCast, elementCount));
  1985
+        }
  1986
+
  1987
+        [RubyMethod("sample")]
  1988
+        public static IList/*!*/ Sample(UnaryOpStorage/*!*/ allocateStorage, IList/*!*/ self, [DefaultProtocol]int elementCount) {
  1989
+            if (elementCount < 0) {
  1990
+                throw RubyExceptions.CreateArgumentError("negative sample number");
  1991
+            }
  1992
+
  1993
+            IList result = CreateResultArray(allocateStorage, self);
  1994
+            if (self.Count == 0) {
  1995
+                return result;
  1996
+            }
  1997
+
  1998
+            var generator = allocateStorage.Context.RandomNumberGenerator;
  1999
+
  2000
+            // we can't pick the same element twice, so remove items from a copy of the list as we pick them
  2001
+            var remaining = new List<object>(self.Count); // can't use ArrayList here as silverlight doesn't have it
  2002
+            foreach (var x in self)
  2003
+                remaining.Add(x);
  2004
+
  2005
+            while (remaining.Count > 0 && elementCount-- > 0) {
  2006
+                var idx = generator.Next(remaining.Count);
  2007
+                result.Add(remaining[idx]);
  2008
+                remaining.RemoveAt(idx);
  2009
+            }
  2010
+
  2011
+            return result;
  2012
+        }
  2013
+
  2014
+        #endregion
  2015
+
  2016
+        #region rotate, rotate!
  2017
+
  2018
+        [RubyMethod("rotate")]
  2019
+        public static IList/*!*/ Rotate(UnaryOpStorage/*!*/ allocateStorage, IList/*!*/ self) {
  2020
+            return Rotate(allocateStorage, self, 1);
  2021
+        }
  2022
+
  2023
+        [RubyMethod("rotate")]
  2024
+        public static IList/*!*/ Rotate(UnaryOpStorage/*!*/ allocateStorage, IList/*!*/ self, [DefaultProtocol]int n) {
  2025
+            IList result = CreateResultArray(allocateStorage, self);
  2026
+            if (result is RubyArray) {
  2027
+                (result as RubyArray).AddCapacity(self.Count);
  2028
+            }
  2029
+            for (int i = 0; i< self.Count; i++ ) {
  2030
+                var idx = NormalizeIndex(self, (i + n) % self.Count ); // we can have negative n which rotates backwards
  2031
+                result.Add(self[idx]);
  2032
+            }
  2033
+            return result;
  2034
+        }
  2035
+
  2036
+        [RubyMethod("rotate!")]
  2037
+        public static IList/*!*/ InPlaceRotate(IList/*!*/ self) {
  2038
+            return InPlaceRotate(self, 1);
  2039
+        }
  2040
+
  2041
+        [RubyMethod("rotate!")]
  2042
+        public static IList/*!*/ InPlaceRotate(IList/*!*/ self, [DefaultProtocol]int n) {
  2043
+            RequireNotFrozen(self);
  2044
+
  2045
+            var count = self.Count;
  2046
+            if (count == 0 || count == 1)
  2047
+                return self;
  2048
+
  2049
+            n = n % count;
  2050
+            if (n == 0)
  2051
+                return self;
  2052
+
  2053
+            var tmp = new object[Math.Abs(n)];
  2054
+            if (n > 0) {
  2055
+                for (int i = 0; i < n; i++) { // copy parts that will get overwritten
  2056
+                    tmp[i] = self[i];
  2057
+                }
  2058
+                for (int i = n; i < count; i++) { // shift down
  2059
+                    self[i - n] = self[i];
  2060
+                }
  2061
+                for (int i = 0; i < n; i++) { // restore overwritten
  2062
+                    self[count - n + i] = tmp[i];
  2063
+                }
  2064
+            } else { // negative n
  2065
+                n = -n;
  2066
+                for (int i = n; i > 0; i--) { // copy parts that will get overwritten
  2067
+                    tmp[n - i] = self[count - i];
  2068
+                }
  2069
+                for (int i = count - n - 1; i >= 0; i--) { // shift up
  2070
+                    self[i + n] = self[i];
  2071
+                }
  2072
+                for (int i = 0; i < n; i++) { // restore overwritten
  2073
+                    self[i] = tmp[i];
  2074
+                }
  2075
+            }
  2076
+
  2077
+            return self;
  2078
+        }
  2079
+
1826 2080
         #endregion
1827 2081
 
1828 2082
         #region reverse, reverse!, transpose, uniq, uniq!
@@ -1881,30 +2135,36 @@ public static class IListOps {
1881 2135
         }
1882 2136
 
1883 2137
         [RubyMethod("uniq")]
1884  
-        public static IList/*!*/ Unique(UnaryOpStorage/*!*/ allocateStorage, IList/*!*/ self) {
  2138
+        public static IList/*!*/ Unique(UnaryOpStorage/*!*/ allocateStorage, BlockParam block, IList/*!*/ self) {
1885 2139
             IList result = CreateResultArray(allocateStorage, self);
1886 2140
 
1887 2141
             var seen = new Dictionary<object, bool>(allocateStorage.Context.EqualityComparer);
1888 2142
             bool nilSeen = false;
1889 2143
             
1890  
-            AddUniqueItems(self, result, seen, ref nilSeen);
  2144
+            AddUniqueItems(block, self, result, seen, ref nilSeen);
1891 2145
             return result;
1892 2146
         }
1893 2147
 
1894 2148
         [RubyMethod("uniq!")]
1895  
-        public static IList UniqueSelf(UnaryOpStorage/*!*/ hashStorage, BinaryOpStorage/*!*/ eqlStorage, RubyArray/*!*/ self) {
  2149
+        public static IList UniqueSelf(UnaryOpStorage/*!*/ hashStorage, BinaryOpStorage/*!*/ eqlStorage, BlockParam block, RubyArray/*!*/ self) {
1896 2150
             self.RequireNotFrozen();
1897  
-            return UniqueSelf(hashStorage, eqlStorage, (IList)self);
  2151
+            return UniqueSelf(hashStorage, eqlStorage, block, (IList)self);
1898 2152
         }
1899 2153
 
1900 2154
         [RubyMethod("uniq!")]
1901  
-        public static IList UniqueSelf(UnaryOpStorage/*!*/ hashStorage, BinaryOpStorage/*!*/ eqlStorage, IList/*!*/ self) {
1902  
-            var seen = new Dictionary<object, bool>(new EqualityComparer(hashStorage, eqlStorage));
  2155
+        public static IList UniqueSelf(UnaryOpStorage/*!*/ hashStorage, BinaryOpStorage/*!*/ eqlStorage, BlockParam block, IList/*!*/ self) {
  2156
+            IEqualityComparer<object> comparer = new EqualityComparer(hashStorage, eqlStorage);
  2157
+            var seen = new Dictionary<object, bool>(comparer);
1903 2158
             bool nilSeen = false;
1904 2159
             bool modified = false;
1905 2160
             int i = 0;
1906 2161
             while (i < self.Count) {
1907  
-                object key = self[i];
  2162
+                object item = self[i];
  2163
+                object key;
  2164
+                if (block == null || block.Yield(item, out key)) {
  2165
+                    key = item;
  2166
+                }
  2167
+
1908 2168
                 if (key != null && !seen.ContainsKey(key)) {
1909 2169
                     seen.Add(key, true);
1910 2170
                     i++;
@@ -1912,8 +2172,15 @@ public static class IListOps {
1912 2172
                     nilSeen = true;
1913 2173
                     i++;
1914 2174
                 } else {
1915  
-                    self.RemoveAt(i);
  2175
+                    // removing objects modifies the array... which breaks the dictionary if "seen" is a self-referential array
  2176
+                    bool isRecursiveArray = seen.Remove(self);
  2177
+
  2178
+                    self.RemoveAt(i); 
1916 2179
                     modified = true;
  2180
+
  2181
+                    if (isRecursiveArray) {
  2182
+                        seen.Add(self, true); // self.hash will change
  2183
+                    }
1917 2184
                 }
1918 2185
             }
1919 2186
 
94  Languages/Ruby/Libraries/Initializers.Generated.cs
@@ -1347,8 +1347,8 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
1347 1347
             );
1348 1348
             
1349 1349
             DefineLibraryMethod(module, "zip", 0x51, 
1350  
-                0x80040008U, 
1351  
-                new Func<IronRuby.Runtime.CallSiteStorage<Func<System.Runtime.CompilerServices.CallSite, System.Object, IronRuby.Builtins.Proc, System.Object>>, IronRuby.Runtime.BlockParam, System.Object, System.Collections.IList[], System.Object>(IronRuby.Builtins.Enumerable.Zip)
  1350
+                0x80100020U, 
  1351
+                new Func<IronRuby.Runtime.CallSiteStorage<Func<System.Runtime.CompilerServices.CallSite, System.Object, IronRuby.Builtins.Proc, System.Object>>, IronRuby.Runtime.ConversionStorage<System.Collections.IList>, IronRuby.Runtime.CallSiteStorage<Func<System.Runtime.CompilerServices.CallSite, System.Object, IronRuby.Builtins.Proc, System.Object>>, IronRuby.Runtime.BlockParam, System.Object, System.Object[], System.Object>(IronRuby.Builtins.Enumerable.Zip)
1352 1352
             );
1353 1353
             
1354 1354
         }
@@ -3024,11 +3024,11 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
3024 3024
             );
3025 3025
             
3026 3026
             DefineLibraryMethod(module, "readlines", 0x51, 
3027  
-                0x00000000U, 0x00020004U, 0x00060000U, 0x00000000U, 
  3027
+                0x00000000U, 0x00000000U, 0x00020004U, 0x00060000U, 
  3028
+                new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.RubyIO, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.RubyIOOps.ReadLines), 
3028 3029
                 new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.RubyIO, Microsoft.Scripting.Runtime.DynamicNull, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.RubyIOOps.ReadLines), 
3029 3030
                 new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.RubyIO, IronRuby.Runtime.Union<IronRuby.Builtins.MutableString, System.Int32>, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.RubyIOOps.ReadLines), 
3030  
-                new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.RubyIO, IronRuby.Builtins.MutableString, System.Int32, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.RubyIOOps.ReadLines), 
3031  
-                new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.RubyIO, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.RubyIOOps.ReadLines)
  3031
+                new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.RubyIO, IronRuby.Builtins.MutableString, System.Int32, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.RubyIOOps.ReadLines)
3032 3032
             );
3033 3033
             
3034 3034
             DefineLibraryMethod(module, "readpartial", 0x51, 
@@ -4250,15 +4250,15 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
4250 4250
             );
4251 4251
             
4252 4252
             DefineLibraryMethod(module, "define_singleton_method", 0x51, 
4253  
-                new[] { 0x0000000cU, 0x0002000cU, 0x0000000cU, 0x0002000cU, 0x0000000cU, 0x0004000aU, 0x0000000aU, 0x0002000cU}, 
4254  
-                new Func<IronRuby.Runtime.RubyScope, System.Object, IronRuby.Runtime.ClrName, IronRuby.Builtins.Proc, IronRuby.Builtins.Proc>(IronRuby.Builtins.KernelOps.DefineSingletonMethod), 
  4253
+                new[] { 0x0002000cU, 0x0000000cU, 0x0002000cU, 0x0000000cU, 0x0004000aU, 0x0000000aU, 0x0002000cU, 0x0000000cU}, 
4255 4254
                 new Func<IronRuby.Runtime.RubyScope, System.Object, System.String, IronRuby.Builtins.RubyMethod, IronRuby.Builtins.RubyMethod>(IronRuby.Builtins.KernelOps.DefineSingletonMethod), 
4256 4255
                 new Func<IronRuby.Runtime.RubyScope, System.Object, IronRuby.Runtime.ClrName, IronRuby.Builtins.RubyMethod, IronRuby.Builtins.RubyMethod>(IronRuby.Builtins.KernelOps.DefineSingletonMethod), 
4257 4256
                 new Func<IronRuby.Runtime.RubyScope, System.Object, System.String, IronRuby.Builtins.UnboundMethod, IronRuby.Builtins.UnboundMethod>(IronRuby.Builtins.KernelOps.DefineSingletonMethod), 
4258 4257
                 new Func<IronRuby.Runtime.RubyScope, System.Object, IronRuby.Runtime.ClrName, IronRuby.Builtins.UnboundMethod, IronRuby.Builtins.UnboundMethod>(IronRuby.Builtins.KernelOps.DefineSingletonMethod), 
4259 4258
                 new Func<IronRuby.Runtime.RubyScope, IronRuby.Runtime.BlockParam, System.Object, System.String, IronRuby.Builtins.Proc>(IronRuby.Builtins.KernelOps.DefineSingletonMethod), 
4260 4259
                 new Func<IronRuby.Runtime.RubyScope, IronRuby.Runtime.BlockParam, System.Object, IronRuby.Runtime.ClrName, IronRuby.Builtins.Proc>(IronRuby.Builtins.KernelOps.DefineSingletonMethod), 
4261  
-                new Func<IronRuby.Runtime.RubyScope, System.Object, System.String, IronRuby.Builtins.Proc, IronRuby.Builtins.Proc>(IronRuby.Builtins.KernelOps.DefineSingletonMethod)
  4260
+                new Func<IronRuby.Runtime.RubyScope, System.Object, System.String, IronRuby.Builtins.Proc, IronRuby.Builtins.Proc>(IronRuby.Builtins.KernelOps.DefineSingletonMethod), 
  4261
+                new Func<IronRuby.Runtime.RubyScope, System.Object, IronRuby.Runtime.ClrName, IronRuby.Builtins.Proc, IronRuby.Builtins.Proc>(IronRuby.Builtins.KernelOps.DefineSingletonMethod)
4262 4262
             );
4263 4263
             
4264 4264
             DefineLibraryMethod(module, "display", 0x51, 
@@ -6850,11 +6850,11 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
6850 6850
             );
6851 6851
             
6852 6852
             DefineLibraryMethod(module, "each_line", 0x51, 
6853  
-                0x00000002U, 0x00010000U, 0x00020001U, 0x00000000U, 
  6853
+                0x00000000U, 0x00000002U, 0x00010000U, 0x00020001U, 
  6854
+                new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.MutableString, IronRuby.Builtins.Enumerator>(IronRuby.Builtins.MutableStringOps.EachLine), 
6854 6855
                 new Func<IronRuby.Runtime.RubyContext, IronRuby.Runtime.BlockParam, IronRuby.Builtins.MutableString, System.Object>(IronRuby.Builtins.MutableStringOps.EachLine), 
6855 6856
                 new Func<IronRuby.Builtins.MutableString, IronRuby.Builtins.MutableString, IronRuby.Builtins.Enumerator>(IronRuby.Builtins.MutableStringOps.EachLine), 
6856  
-                new Func<IronRuby.Runtime.BlockParam, IronRuby.Builtins.MutableString, IronRuby.Builtins.MutableString, System.Object>(IronRuby.Builtins.MutableStringOps.EachLine), 
6857  
-                new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.MutableString, IronRuby.Builtins.Enumerator>(IronRuby.Builtins.MutableStringOps.EachLine)
  6857
+                new Func<IronRuby.Runtime.BlockParam, IronRuby.Builtins.MutableString, IronRuby.Builtins.MutableString, System.Object>(IronRuby.Builtins.MutableStringOps.EachLine)
6858 6858
             );
6859 6859
             
6860 6860
             DefineLibraryMethod(module, "empty?", 0x51, 
@@ -6965,11 +6965,11 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
6965 6965
             );
6966 6966
             
6967 6967
             DefineLibraryMethod(module, "lines", 0x51, 
6968  
-                0x00000002U, 0x00010000U, 0x00020001U, 0x00000000U, 
  6968
+                0x00000000U, 0x00000002U, 0x00010000U, 0x00020001U, 
  6969
+                new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.MutableString, IronRuby.Builtins.Enumerator>(IronRuby.Builtins.MutableStringOps.EachLine), 
6969 6970
                 new Func<IronRuby.Runtime.RubyContext, IronRuby.Runtime.BlockParam, IronRuby.Builtins.MutableString, System.Object>(IronRuby.Builtins.MutableStringOps.EachLine), 
6970 6971
                 new Func<IronRuby.Builtins.MutableString, IronRuby.Builtins.MutableString, IronRuby.Builtins.Enumerator>(IronRuby.Builtins.MutableStringOps.EachLine), 
6971  
-                new Func<IronRuby.Runtime.BlockParam, IronRuby.Builtins.MutableString, IronRuby.Builtins.MutableString, System.Object>(IronRuby.Builtins.MutableStringOps.EachLine), 
6972  
-                new Func<IronRuby.Runtime.RubyContext, IronRuby.Builtins.MutableString, IronRuby.Builtins.Enumerator>(IronRuby.Builtins.MutableStringOps.EachLine)
  6972
+                new Func<IronRuby.Runtime.BlockParam, IronRuby.Builtins.MutableString, IronRuby.Builtins.MutableString, System.Object>(IronRuby.Builtins.MutableStringOps.EachLine)
6973 6973
             );
6974 6974
             
6975 6975
             DefineLibraryMethod(module, "ljust", 0x51, 
@@ -7030,10 +7030,10 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
7030 7030
             );
7031 7031
             
7032 7032
             DefineLibraryMethod(module, "rindex", 0x51, 
7033  
-                0x00010002U, 0x00030002U, 0x00040004U, 
  7033
+                0x00040004U, 0x00010002U, 0x00030002U, 
  7034
+                new Func<IronRuby.Runtime.RubyScope, IronRuby.Builtins.MutableString, IronRuby.Builtins.RubyRegex, System.Int32, System.Object>(IronRuby.Builtins.MutableStringOps.LastIndexOf), 
7034 7035
                 new Func<IronRuby.Builtins.MutableString, IronRuby.Builtins.MutableString, System.Object>(IronRuby.Builtins.MutableStringOps.LastIndexOf), 
7035  
-                new Func<IronRuby.Builtins.MutableString, IronRuby.Builtins.MutableString, System.Int32, System.Object>(IronRuby.Builtins.MutableStringOps.LastIndexOf), 
7036  
-                new Func<IronRuby.Runtime.RubyScope, IronRuby.Builtins.MutableString, IronRuby.Builtins.RubyRegex, System.Int32, System.Object>(IronRuby.Builtins.MutableStringOps.LastIndexOf)
  7036
+                new Func<IronRuby.Builtins.MutableString, IronRuby.Builtins.MutableString, System.Int32, System.Object>(IronRuby.Builtins.MutableStringOps.LastIndexOf)
7037 7037
             );
7038 7038
             
7039 7039
             DefineLibraryMethod(module, "rjust", 0x51, 
@@ -7840,11 +7840,12 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
7840 7840
             );
7841 7841
             
7842 7842
             DefineLibraryMethod(module, "[]=", 0x51, 
7843  
-                0x00010000U, 0x00010000U, 0x00060000U, 0x00000008U, 
  7843
+                new[] { 0x00010000U, 0x00010000U, 0x00000000U, 0x00060000U, 0x00000000U}, 
7844 7844
                 new Func<IronRuby.Builtins.RubyArray, System.Int32, System.Object, System.Object>(IronRuby.Builtins.IListOps.SetElement), 
7845 7845
                 new Func<System.Collections.IList, System.Int32, System.Object, System.Object>(IronRuby.Builtins.IListOps.SetElement), 
  7846
+                new Func<IronRuby.Runtime.ConversionStorage<System.Collections.IList>, IronRuby.Runtime.ConversionStorage<System.Int32>, System.Collections.IList, System.Object, System.Object, System.Object, System.Object>(IronRuby.Builtins.IListOps.SetElement), 
7846 7847
                 new Func<IronRuby.Runtime.ConversionStorage<System.Collections.IList>, System.Collections.IList, System.Int32, System.Int32, System.Object, System.Object>(IronRuby.Builtins.IListOps.SetElement), 
7847  
-                new Func<IronRuby.Runtime.ConversionStorage<System.Collections.IList>, IronRuby.Runtime.ConversionStorage<System.Int32>, System.Collections.IList, IronRuby.Builtins.Range, System.Object, System.Object>(IronRuby.Builtins.IListOps.SetElement)
  7848
+                new Func<IronRuby.Runtime.ConversionStorage<System.Collections.IList>, IronRuby.Runtime.ConversionStorage<System.Int32>, System.Collections.IList, System.Object, System.Object, System.Object>(IronRuby.Builtins.IListOps.SetElement)
7848 7849
             );
7849 7850
             
7850 7851
             DefineLibraryMethod(module, "|", 0x51, 
@@ -7968,7 +7969,7 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
7968 7969
                 new[] { 0x00000000U, 0x00000000U, 0x00000000U, 0x00000008U, 0x00000001U, 0x00000001U, 0x00000002U, 0x0000000aU}, 
7969 7970
                 new Func<System.Collections.IList, System.Object, System.Int32, System.Collections.IList>(IronRuby.Builtins.IListOps.Fill), 
7970 7971
                 new Func<System.Collections.IList, System.Object, System.Int32, System.Int32, System.Collections.IList>(IronRuby.Builtins.IListOps.Fill), 
7971  
-                new Func<IronRuby.Runtime.ConversionStorage<System.Int32>, System.Collections.IList, System.Object, System.Object, System.Object, System.Collections.IList>(IronRuby.Builtins.IListOps.Fill), 
  7972
+                new Func<IronRuby.Runtime.ConversionStorage<System.Int32>, IronRuby.Runtime.BlockParam, System.Collections.IList, System.Object, System.Object, System.Object, System.Collections.IList>(IronRuby.Builtins.IListOps.Fill), 
7972 7973
                 new Func<IronRuby.Runtime.ConversionStorage<System.Int32>, System.Collections.IList, System.Object, IronRuby.Builtins.Range, System.Collections.IList>(IronRuby.Builtins.IListOps.Fill), 
7973 7974
                 new Func<IronRuby.Runtime.BlockParam, System.Collections.IList, System.Int32, System.Object>(IronRuby.Builtins.IListOps.Fill), 
7974 7975
                 new Func<IronRuby.Runtime.BlockParam, System.Collections.IList, System.Int32, System.Int32, System.Object>(IronRuby.Builtins.IListOps.Fill), 
@@ -8048,6 +8049,11 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
8048 8049
                 new Func<IronRuby.Runtime.JoinConversionStorage, IronRuby.Runtime.ConversionStorage<IronRuby.Builtins.MutableString>, System.Collections.IList, System.Object, IronRuby.Builtins.MutableString>(IronRuby.Builtins.IListOps.JoinWithLazySeparatorConversion)
8049 8050
             );
8050 8051
             
  8052
+            DefineLibraryMethod(module, "keep_if", 0x51, 
  8053
+                0x00000000U, 
  8054
+                new Func<IronRuby.Runtime.BlockParam, System.Collections.IList, System.Object>(IronRuby.Builtins.IListOps.KeepIf)
  8055
+            );
  8056
+            
8051 8057
             DefineLibraryMethod(module, "last", 0x51, 
8052 8058
                 0x00000000U, 0x00010000U, 
8053 8059
                 new Func<System.Collections.IList, System.Object>(IronRuby.Builtins.IListOps.Last), 
@@ -8086,8 +8092,8 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
8086 8092
             );
8087 8093
             
8088 8094
             DefineLibraryMethod(module, "product", 0x51, 
8089  
-                0x80010002U, 
8090  
-                new Func<System.Collections.IList, System.Collections.IList[], IronRuby.Builtins.RubyArray>(IronRuby.Builtins.IListOps.Product)
  8095
+                0x80020004U, 
  8096
+                new Func<IronRuby.Runtime.BlockParam, System.Collections.IList, System.Collections.IList[], System.Collections.IList>(IronRuby.Builtins.IListOps.Product)
8091 8097
             );
8092 8098
             
8093 8099
             DefineLibraryMethod(module, "push", 0x51, 
@@ -8132,14 +8138,40 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
8132 8138
             );
8133 8139
             
8134 8140
             DefineLibraryMethod(module, "rindex", 0x51, 
8135  
-                0x00000001U, 0x00000000U, 
  8141
+                0x00000000U, 0x00000001U, 0x00000000U, 
  8142
+                new Func<System.Collections.IList, IronRuby.Builtins.Enumerator>(IronRuby.Builtins.IListOps.GetReverseIndexEnumerator), 
8136 8143
                 new Func<IronRuby.Runtime.BlockParam, System.Collections.IList, System.Object>(IronRuby.Builtins.IListOps.ReverseIndex), 
8137 8144
                 new Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BlockParam, System.Collections.IList, System.Object, System.Object>(IronRuby.Builtins.IListOps.ReverseIndex)
8138 8145
             );
8139 8146
             
8140  
-            DefineLibraryMethod(module, "shift", 0x51, 
  8147
+            DefineLibraryMethod(module, "rotate", 0x51, 
  8148
+                0x00000000U, 0x00020000U, 
  8149
+                new Func<IronRuby.Runtime.UnaryOpStorage, System.Collections.IList, System.Collections.IList>(IronRuby.Builtins.IListOps.Rotate), 
  8150
+                new Func<IronRuby.Runtime.UnaryOpStorage, System.Collections.IList, System.Int32, System.Collections.IList>(IronRuby.Builtins.IListOps.Rotate)
  8151
+            );
  8152
+            
  8153
+            DefineLibraryMethod(module, "rotate!", 0x51, 
  8154
+                0x00000000U, 0x00010000U, 
  8155
+                new Func<System.Collections.IList, System.Collections.IList>(IronRuby.Builtins.IListOps.InPlaceRotate), 
  8156
+                new Func<System.Collections.IList, System.Int32, System.Collections.IList>(IronRuby.Builtins.IListOps.InPlaceRotate)
  8157
+            );
  8158
+            
  8159
+            DefineLibraryMethod(module, "sample", 0x51, 
  8160
+                0x00000000U, 0x00000000U, 0x00020000U, 
  8161
+                new Func<IronRuby.Runtime.RubyContext, System.Collections.IList, System.Object>(IronRuby.Builtins.IListOps.Sample), 
  8162
+                new Func<IronRuby.Runtime.UnaryOpStorage, IronRuby.Runtime.ConversionStorage<System.Int32>, System.Collections.IList, System.Object, System.Collections.IList>(IronRuby.Builtins.IListOps.Sample), 
  8163
+                new Func<IronRuby.Runtime.UnaryOpStorage, System.Collections.IList, System.Int32, System.Collections.IList>(IronRuby.Builtins.IListOps.Sample)
  8164
+            );
  8165
+            
  8166
+            DefineLibraryMethod(module, "select!", 0x51, 
8141 8167
                 0x00000000U, 
8142  
-                new Func<System.Collections.IList, System.Object>(IronRuby.Builtins.IListOps.Shift)
  8168
+                new Func<IronRuby.Runtime.BlockParam, System.Collections.IList, System.Object>(IronRuby.Builtins.IListOps.SelectInPlace)
  8169
+            );
  8170
+            
  8171
+            DefineLibraryMethod(module, "shift", 0x51, 
  8172
+                0x00000000U, 0x00020000U, 
  8173
+                new Func<System.Collections.IList, System.Object>(IronRuby.Builtins.IListOps.Shift), 
  8174
+                new Func<IronRuby.Runtime.UnaryOpStorage, System.Collections.IList, System.Int32, System.Object>(IronRuby.Builtins.IListOps.Shift)
8143 8175
             );
8144 8176
             
8145 8177
             DefineLibraryMethod(module, "shuffle", 0x51, 
@@ -8203,13 +8235,13 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
8203 8235
             
8204 8236
             DefineLibraryMethod(module, "uniq", 0x51, 
8205 8237
                 0x00000000U, 
8206  
-                new Func<IronRuby.Runtime.UnaryOpStorage, System.Collections.IList, System.Collections.IList>(IronRuby.Builtins.IListOps.Unique)
  8238
+                new Func<IronRuby.Runtime.UnaryOpStorage, IronRuby.Runtime.BlockParam, System.Collections.IList, System.Collections.IList>(IronRuby.Builtins.IListOps.Unique)
8207 8239
             );
8208 8240
             
8209 8241
             DefineLibraryMethod(module, "uniq!", 0x51, 
8210 8242
                 0x00000000U, 0x00000000U, 
8211  
-                new Func<IronRuby.Runtime.UnaryOpStorage, IronRuby.Runtime.BinaryOpStorage, IronRuby.Builtins.RubyArray, System.Collections.IList>(IronRuby.Builtins.IListOps.UniqueSelf), 
8212  
-                new Func<IronRuby.Runtime.UnaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Collections.IList, System.Collections.IList>(IronRuby.Builtins.IListOps.UniqueSelf)
  8243
+                new Func<IronRuby.Runtime.UnaryOpStorage, IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BlockParam, IronRuby.Builtins.RubyArray, System.Collections.IList>(IronRuby.Builtins.IListOps.UniqueSelf), 
  8244
+                new Func<IronRuby.Runtime.UnaryOpStorage, IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BlockParam, System.Collections.IList, System.Collections.IList>(IronRuby.Builtins.IListOps.UniqueSelf)
8213 8245
             );
8214 8246
             
8215 8247
             DefineLibraryMethod(module, "unshift", 0x51, 
@@ -11520,12 +11552,12 @@ public sealed class BigDecimalLibraryInitializer : IronRuby.Builtins.LibraryInit
11520 11552
             );
11521 11553
             
11522 11554
             DefineLibraryMethod(module, "<=>", 0x11, 
11523  
-                new[] { 0x00000000U, 0x00000002U, 0x00000004U, 0x00000000U, 0x00000000U}, 
11524  
-                new Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, IronRuby.StandardLibrary.BigDecimal.BigDecimal, System.Object, System.Object>(IronRuby.StandardLibrary.BigDecimal.BigDecimalOps.Compare), 
  11555
+                new[] { 0x00000002U, 0x00000004U, 0x00000000U, 0x00000000U, 0x00000000U}, 
11525 11556
                 new Func<IronRuby.StandardLibrary.BigDecimal.BigDecimal, IronRuby.StandardLibrary.BigDecimal.BigDecimal, System.Object>(IronRuby.StandardLibrary.BigDecimal.BigDecimalOps.Compare), 
11526 11557
                 new Func<IronRuby.Runtime.RubyContext, IronRuby.StandardLibrary.BigDecimal.BigDecimal, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.StandardLibrary.BigDecimal.BigDecimalOps.Compare), 
11527 11558
                 new Func<IronRuby.Runtime.RubyContext, IronRuby.StandardLibrary.BigDecimal.BigDecimal, System.Int32, System.Object>(IronRuby.StandardLibrary.BigDecimal.BigDecimalOps.Compare), 
11528  
-                new Func<IronRuby.Runtime.RubyContext, IronRuby.StandardLibrary.BigDecimal.BigDecimal, System.Double, System.Object>(IronRuby.StandardLibrary.BigDecimal.BigDecimalOps.Compare)
  11559
+                new Func<IronRuby.Runtime.RubyContext, IronRuby.StandardLibrary.BigDecimal.BigDecimal, System.Double, System.Object>(IronRuby.StandardLibrary.BigDecimal.BigDecimalOps.Compare), 
  11560
+                new Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, IronRuby.StandardLibrary.BigDecimal.BigDecimal, System.Object, System.Object>(IronRuby.StandardLibrary.BigDecimal.BigDecimalOps.Compare)
11529 11561
             );
11530 11562
             
11531 11563
             DefineLibraryMethod(module, "==", 0x11, 
6  Languages/Ruby/Ruby/Builtins/RubyArray.cs
@@ -142,12 +142,12 @@ public RubyArray(IEnumerable/*!*/ items)
142 142
         public void RequireNotFrozen() {
143 143
             if ((_flags & IsFrozenFlag) != 0) {
144 144
                 // throw in a separate method to allow inlining of the current one
145  
-                ThrowObjectFrozenException();
  145
+                ThrowArrayFrozenException();
146 146
             }
147 147
         }
148 148
 
149  
-        private static void ThrowObjectFrozenException() {
150  
-            throw RubyExceptions.CreateObjectFrozenError();
  149
+        private static void ThrowArrayFrozenException() {
  150
+            throw RubyExceptions.CreateArrayFrozenError();
151 151
         }
152 152
 
153 153
         private void Mutate() {
4  Languages/Ruby/Ruby/Runtime/RubyExceptions.cs
@@ -48,6 +48,10 @@ public static class RubyExceptions {
48 48
             return CreateRuntimeError("can't modify frozen object");
49 49
         }
50 50
 
  51
+        public static Exception/*!*/ CreateArrayFrozenError() {
  52
+            return CreateRuntimeError("can't modify frozen array");
  53
+        }
  54
+
51 55
         public static Exception/*!*/ CreateTypeConversionError(string/*!*/ fromType, string/*!*/ toType) {
52 56
             Assert.NotNull(fromType, toType);
53 57
             return CreateTypeError("can't convert {0} into {1}", fromType, toType);
5  Languages/Ruby/Ruby/Runtime/RubyOps.cs
@@ -2139,8 +2139,11 @@ private sealed class _NeedsUpdate {
2139 2139
 
2140 2140
         [Emitted] // ProtocolConversionAction
2141 2141
         public static IList/*!*/ ToArrayValidator(string/*!*/ className, object obj) {
  2142
+            if (obj == null) // to_ary is allowed to return nil
  2143
+                return null;
  2144
+
2142 2145
             var result = obj as IList;
2143  
-            if (result == null) {
  2146
+            if (result == null) { // but it's not allowed to return other types
2144 2147
                 throw RubyExceptions.CreateReturnTypeError(className, "to_ary", "Array");
2145 2148
             }
2146 2149
             return result;
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.