[Ironruby-core] Code review: String#unpack, Bignum and Array related stuff

Daniele Alessandri suppakilla at gmail.com
Sun Jul 19 05:29:06 EDT 2009


Hi
first of all I am trying a different approach to submitting my
patches: I created a code_review branch on my repository in which I am
going to push all my fixes for review. Fixes that will pass review
will be rebased (not merged) in my main branch (ready to get pulled
into the ironruby repository), the others will remain staged in my
code_review branch for further works until they are "approved". I am
just experimenting a different git workflow :-)

Anyway, let's move on to the new commits:


* http://github.com/nrk/ironruby/commit/48a4a02b5b47d61f2f7a3f3887ea4bf02d63edb4

- More fixes for String#unpack:
   o Fixed errors when unpacking data with 'Z' and '@' directives
   o Implemented 'Q' and 'q' directives


* http://github.com/nrk/ironruby/commit/17b5edab64967b0200370edf6657321a0f79953d

- Array related fixes:
   o Array#== does not call #to_ary on its argument but it calls #to_a (it
   basically performs a conversion of the argument rather than casting it to a
   ruby array)
   o Array#zip calls #to_ary to cast the argument to an Array, therefore it
   overrides Enumerable#zip in which the argument is converted by calling
   #to_a.


* http://github.com/nrk/ironruby/commit/547d810c78b38afc34e728855ab7d0c20f499719

- Bignum related fixes:
   o Changed the signature for ClrBigInteger.ToString(self,radix), now
   Bignum#to_s works as expected raising an ArgumentException if base is less
   than 2 or higher than 36.
   o Fixed Bignum#divmod, Bignum#remainder, Bignum#% and Bignum#modulo to work
   with Float values as argument.
   o Fixed Bignum#/ and Bignum#div as they behave differently with each other
   when Float values are passed as argument.

Note: Now bignum does not fail any of the expectations in core/bignum.

See also the attached diff.

Thanks,
Daniele

-- 
Daniele Alessandri
http://www.clorophilla.net/blog/
http://twitter.com/JoL1hAHN
-------------- next part --------------
diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/array/equal_value_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/array/equal_value_tags.txt
index bf03ad0..17d97a5 100644
--- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/array/equal_value_tags.txt
+++ b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/array/equal_value_tags.txt
@@ -1,2 +1 @@
 fails:Array#== returns true if corresponding elements are #==
-fails:Array#== does not call #to_ary on its argument
diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/array/zip_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/array/zip_tags.txt
deleted file mode 100644
index f863d32..0000000
--- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/array/zip_tags.txt
+++ /dev/null
@@ -1 +0,0 @@
-fails:Array#zip calls #to_ary to convert the argument to an Array
diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/div_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/div_tags.txt
deleted file mode 100644
index a4b2900..0000000
--- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/div_tags.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-fails:Bignum#div returns a result of integer division of self by a float argument
-fails:Bignum#div raises FloatDomainError if the argument is a float zero
diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/divmod_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/divmod_tags.txt
deleted file mode 100644
index f8a72c1..0000000
--- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/divmod_tags.txt
+++ /dev/null
@@ -1 +0,0 @@
-fails:Bignum#divmod returns an Array containing quotient and modulus obtained from dividing self by the given argument
diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/modulo_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/modulo_tags.txt
deleted file mode 100644
index d64c330..0000000
--- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/modulo_tags.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-fails:Bignum#% returns the modulus obtained from dividing self by the given argument
-fails:Bignum#modulo returns the modulus obtained from dividing self by the given argument
diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/remainder_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/remainder_tags.txt
deleted file mode 100644
index 0867179..0000000
--- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/remainder_tags.txt
+++ /dev/null
@@ -1 +0,0 @@
-fails:Bignum#remainder returns the remainder of dividing self by other
diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/to_s_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/to_s_tags.txt
deleted file mode 100644
index d14bd59..0000000
--- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/bignum/to_s_tags.txt
+++ /dev/null
@@ -1 +0,0 @@
-fails:Bignum#to_s when given a base raises an ArgumentError if the base is less than 2 or higher than 36
diff --git a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/string/unpack_tags.txt b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/string/unpack_tags.txt
index d0ab5e9..0e5968d 100644
--- a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/string/unpack_tags.txt
+++ b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/core/string/unpack_tags.txt
@@ -1,14 +1,9 @@
 fails:String#unpack returns an array by decoding self according to the format string
-fails:String#unpack with 'Z' directive returns an array by decoding self according to the format string
 fails:String#unpack with 'N' and 'n' directives returns an array by decoding self according to the format string
-fails:String#unpack with 'Q' and 'q' directives returns an array in little-endian (native format) order by decoding self according to the format string
-fails:String#unpack with 'Q' and 'q' directives returns Bignums for big numeric values on little-endian platforms
-fails:String#unpack with 'Q' and 'q' directives returns Fixnums for small numeric values
 fails:String#unpack with 'a', 'X' and 'x' directives returns an array by decoding self according to the format string
 fails:String#unpack with 'DdEeFfGg' directives returns an array by decoding self according to the format string
 fails:String#unpack with 'DdEeFfGg' directives returns an array by decoding self in little-endian order according to the format string
 fails:String#unpack with 'U' directive returns an array by decoding self according to the format string
-fails:String#unpack with '@' directive returns an array by decoding self according to the format string
 fails:String#unpack with 'M' directive returns an array by decoding self according to the format string
 fails:String#unpack with 'm' directive returns an array by decoding self according to the format string
 fails:String#unpack with 'w' directive produces a BER-compressed integer
diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ArrayOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ArrayOps.cs
index e2c3ee9..5f1c44c 100644
--- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ArrayOps.cs
+++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ArrayOps.cs
@@ -215,34 +215,45 @@ namespace IronRuby.Builtins {
                         if (!_native.TryGetValue(c, out tmp)) {
                             throw RubyExceptions.CreateArgumentError("'_' allowed only after types sSiIlL");
                         }
                         c = tmp;
                         i++;
                         c2 = (i < format.Length) ? format[i] : '\0';
                     }
                     if (Char.IsDigit(c2)) {
                         int pos1 = i;
                         i++;
                         while (i < format.Length && Char.IsDigit(format[i])) {
                             i++;
                         }
                         count = Int32.Parse(format.Substring(pos1, (i - pos1)));
                         i--;
+                    } else if (c == '@' && c2 == '-') {
+                        int pos1 = i;
+                        i += 2;
+                        while (i < format.Length && Char.IsDigit(format[i])) {
+                            i++;
+                        }
+                        count = Int32.Parse(format.Substring(pos1, (i - pos1)));
+                        i--;
                     } else if (c2 == '*') {
                         count = null;
                     } else {
                         i--;
+                        if (c == '@') {
+                            count = 0;
+                        }
                     }
                     
                     yield return new FormatDirective(c, count);
                 }
             }
         }
 
         #endregion
 
         #region pack
 
         [RubyMethod("pack")]
         public static MutableString/*!*/ Pack(
             ConversionStorage<IntegerValue>/*!*/ integerConversion, 
             ConversionStorage<MutableString>/*!*/ stringCast, 
diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs
index 06cec4b..c420cb8 100644
--- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs
+++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs
@@ -2601,31 +2601,39 @@ namespace IronRuby.Builtins {
             }
         }
 
         [RubyMethod("unpack")]
         public static RubyArray/*!*/ Unpack(RubyContext/*!*/ context, MutableString/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ format) {
             RubyArray result = new RubyArray(1 + self.Length / 2);
             using (MutableStringStream stream = new MutableStringStream(self)) {
                 BinaryReader reader = new BinaryReader(stream);
                 foreach (ArrayOps.FormatDirective directive in ArrayOps.FormatDirective.Enumerate(format.ToString())) {
                     int count, maxCount;
                     byte[] buffer;
                     MutableString str;
                     int nilCount = 0;
                     switch (directive.Directive) {
                         case '@':
-                            stream.Position = directive.Count.HasValue ? directive.Count.Value : stream.Position;
+                            if (directive.Count.HasValue) {
+                                if (directive.Count.Value > stream.Length) {
+                                    throw RubyExceptions.CreateArgumentError("@ outside of string");
+                                }
+                                stream.Position = directive.Count.Value > 0 ? directive.Count.Value : 0;
+                            }
+                            else {
+                                stream.Position = stream.Length;
+                            }
                             break;
 
                         case 'A':
                         case 'a':
                             maxCount = (int)(stream.Length - stream.Position);
                             count = directive.Count.HasValue ? directive.Count.Value : maxCount;
                             if (count > maxCount) {
                                 count = maxCount;
                             }
                             buffer = reader.ReadBytes(count);
                             str = MutableString.CreateBinary(buffer);
                             if (directive.Directive == 'A') {
                                 // TODO: efficiency?
                                 for (int pos = count - 1; pos >= 0; pos--) {
                                     if (buffer[pos] != 0 && buffer[pos] != 0x20) {
@@ -2671,30 +2679,33 @@ namespace IronRuby.Builtins {
                             }
                             result.Add(str);
                             break;
 
                         case 'Z':
                             maxCount = (int)(stream.Length - stream.Position);
                             count = directive.Count.HasValue ? directive.Count.Value : maxCount;
                             if (count > maxCount) {
                                 count = maxCount;
                             }
                             buffer = reader.ReadBytes(count);
                             str = MutableString.CreateBinary(buffer);
                             for (int pos = 0; pos < count; pos++) {
                                 if (buffer[pos] == 0) {
                                     str.Remove(pos, count - pos);
+                                    if (!directive.Count.HasValue) {
+                                        stream.Seek(pos - count + 1, SeekOrigin.End);
+                                    }
                                     break;
                                 }
                             }
                             result.Add(str);
                             break;
 
                         case 'c':
                             count = CalculateCounts(stream, directive.Count, sizeof(sbyte), out nilCount);
                             for (int j = 0; j < count; j++) {
                                 result.Add((int)reader.ReadSByte());
                             }
                             break;
 
                         case 'C':
                             count = CalculateCounts(stream, directive.Count, sizeof(byte), out nilCount);
@@ -2743,30 +2754,79 @@ namespace IronRuby.Builtins {
                                 if (!BitConverter.IsLittleEndian) {
                                     value = (0x000000FF & (value >> 24) |
                                              0x0000FF00 & (value >> 8) |
                                              0x00FF0000 & (value << 8) |
                                              0xFF000000 & (value << 24));
                                 }
                                 if (value <= Int32.MaxValue) {
                                     result.Add((int)value);
                                 }
                                 else {
                                     result.Add((BigInteger)value);
                                 }
                             }
                             break;
 
+                        case 'q':
+                            count = CalculateCounts(stream, directive.Count, sizeof(long), out nilCount);
+                            for (int j = 0; j < count; j++) {
+                                long value = reader.ReadInt64();
+                                if (!BitConverter.IsLittleEndian) {
+                                    ulong uvalue = (ulong)value;
+                                    uvalue = (0x00000000000000FF & (uvalue >> 56)) |
+                                             (0x000000000000FF00 & (uvalue >> 40)) |
+                                             (0x0000000000FF0000 & (uvalue >> 24)) |
+                                             (0x00000000FF000000 & (uvalue >> 8))  |
+                                             (0x000000FF00000000 & (uvalue << 8))  |
+                                             (0x0000FF0000000000 & (uvalue << 24)) |
+                                             (0x00FF000000000000 & (uvalue << 40)) |
+                                             (0xFF00000000000000 & (uvalue << 56));
+                                    value = (long)uvalue;
+                                }
+                                if (value <= Int32.MaxValue && value >= Int32.MinValue) {
+                                    result.Add((int)value);
+                                }
+                                else {
+                                    result.Add((BigInteger)value);
+                                }
+                            }
+                            break;
+
+                        case 'Q':
+                            count = CalculateCounts(stream, directive.Count, sizeof(ulong), out nilCount);
+                            nilCount = 0;
+                            for (int j = 0; j < count; j++) {
+                                ulong value = reader.ReadUInt64();
+                                if (!BitConverter.IsLittleEndian) {
+                                    value = (0xFF00000000000000 & (value << 56)) |
+                                            (0x00FF000000000000 & (value >> 40)) |
+                                            (0x0000FF0000000000 & (value >> 24)) |
+                                            (0x000000FF00000000 & (value >> 8))  |
+                                            (0x00000000FF000000 & (value << 8))  |
+                                            (0x0000000000FF0000 & (value << 24)) |
+                                            (0x000000000000FF00 & (value << 40)) |
+                                            (0x00000000000000FF & (value << 56));
+                                }
+                                if (value <= Int32.MaxValue) {
+                                    result.Add((int)value);
+                                }
+                                else {
+                                    result.Add((BigInteger)value);
+                                }
+                            }
+                            break;
+
                         case 'm':
                             // TODO: Recognize "==" as end of base 64 encoding
                             int len = (int)(stream.Length - stream.Position);
                             char[] base64 = reader.ReadChars(len);
                             byte[] data = Convert.FromBase64CharArray(base64, 0, len);
                             result.Add(MutableString.CreateBinary(data));
                             break;
 
                         case 's':
                             count = CalculateCounts(stream, directive.Count, sizeof(short), out nilCount);
                             for (int j = 0; j < count; j++) {
                                 result.Add((int)reader.ReadInt16());
                             }
                             break;
 
diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/ClrBigInteger.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/ClrBigInteger.cs
index 25a9fee..e1f5069 100644
--- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/ClrBigInteger.cs
+++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/ClrBigInteger.cs
@@ -160,36 +160,45 @@ namespace IronRuby.Builtins {
 
         /// <summary>
         /// Divides self by other, where other is Bignum or Fixnum
         /// </summary>
         /// <returns>self / other</returns>
         /// <remarks>Uses DivMod to do the division (directly).  Normalizes to a Fixnum if necessary</remarks>
         [RubyMethod("/"), RubyMethod("div")]
         public static object Divide(BigInteger/*!*/ self, [NotNull]BigInteger/*!*/ other) {
             return DivMod(self, other)[0];
         }
 
         /// <summary>
         /// Divides self by other, where other is Float
         /// </summary>
         /// <returns>self / other as Float</returns>
-        [RubyMethod("/"), RubyMethod("div")]
-        public static object Divide(BigInteger/*!*/ self, double other) {
+        [RubyMethod("/")]
+        public static object DivideOp(BigInteger/*!*/ self, double other) {
             return self.ToFloat64() / other;
         }
 
         /// <summary>
+        /// Divides self by other, where other is Float
+        /// </summary>
+        /// <returns>self divided by other as Float</returns>
+        [RubyMethod("div")]
+        public static object Divide(BigInteger/*!*/ self, double other) {
+            return DivMod(self, other)[0];
+        }
+
+        /// <summary>
         /// Divides self by other, where other is not a Float, Fixnum or Bignum
         /// </summary>
         /// <returns>self / other</returns>
         /// <remarks>Coerces self and other using other.coerce(self) then dynamically invokes /</remarks>
         [RubyMethod("/")]
         public static object Divide(BinaryOpStorage/*!*/ coercionStorage, BinaryOpStorage/*!*/ binaryOpSite, object/*!*/ self, object other) {
             return Protocols.CoerceAndApply(coercionStorage, binaryOpSite, "/", self, other);
         }
 
         /// <summary>
         /// Divides self by other, where other is not a Float, Fixnum or Bignum
         /// </summary>
         /// <returns>self.div(other)</returns>
         /// <remarks>Coerces self and other using other.coerce(self) then dynamically invokes div</remarks>
         [RubyMethod("div")]
@@ -288,30 +297,44 @@ namespace IronRuby.Builtins {
 
         #region modulo, %
 
         /// <summary>
         /// Returns self modulo other, where other is Fixnum or Bignum.
         /// </summary>
         /// <returns>self modulo other, as Fixnum or Bignum</returns>
         /// <remarks>Calls divmod directly to get the modulus.</remarks>
         [RubyMethod("%"), RubyMethod("modulo")]
         public static object Modulo(BigInteger/*!*/ self, [NotNull]BigInteger/*!*/ other) {
             RubyArray result = DivMod(self, other);
             return result[1];
         }
 
         /// <summary>
+        /// Returns self modulo other, where other is Float.
+        /// </summary>
+        /// <returns>self modulo other, as Float</returns>
+        /// <remarks>Calls divmod directly to get the modulus.</remarks>
+        [RubyMethod("%"), RubyMethod("modulo")]
+        public static object Modulo(BigInteger/*!*/ self, double other) {
+            if (other == 0.0) {
+                return Double.NaN;
+            }
+            RubyArray result = DivMod(self, other);
+            return result[1];
+        }
+
+        /// <summary>
         /// Returns self % other, where other is not Fixnum or Bignum.
         /// </summary>
         /// <returns>self % other, as Fixnum or Bignum</returns>
         /// <remarks>Coerces self and other using other.coerce(self) then dynamically invokes %</remarks>
         [RubyMethod("%")]
         public static object ModuloOp(BinaryOpStorage/*!*/ coercionStorage, BinaryOpStorage/*!*/ binaryOpSite, object/*!*/ self, object other) {
             return Protocols.CoerceAndApply(coercionStorage, binaryOpSite, "%", self, other);
         }
 
         /// <summary>
         /// Returns self modulo other, where other is not Fixnum or Bignum.
         /// </summary>
         /// <returns>self modulo other, as Fixnum or Bignum</returns>
         /// <remarks>Coerces self and other using other.coerce(self) then dynamically invokes modulo</remarks>
         [RubyMethod("modulo")]
@@ -331,30 +354,51 @@ namespace IronRuby.Builtins {
         /// </summary>
         /// <returns>[self div other, self modulo other] as RubyArray</returns>
         /// <remarks>Normalizes div and mod to Fixnum as necessary</remarks>
         [RubyMethod("divmod")]
         public static RubyArray DivMod(BigInteger/*!*/ self, [NotNull]BigInteger/*!*/ other) {
             BigInteger mod;
             BigInteger div = BigInteger.DivRem(self, other, out mod);
             if (self.Sign != other.Sign && !mod.IsZero()) {
                 div = div - 1;
                 mod = mod + other;
             }
             return RubyOps.MakeArray2(Protocols.Normalize(div), Protocols.Normalize(mod));
         }
 
         /// <summary>
+        /// Returns an array containing the quotient and modulus obtained by dividing self by other, where other is Float.
+        /// If <code>q, r = x.divmod(y)</code>, then 
+        ///     <code>q = floor(float(x)/float(y))</code>
+        ///     <code>x = q*y + r</code>
+        /// </summary>
+        /// <returns>[self div other, self modulo other] as RubyArray</returns>
+        /// <remarks>Normalizes div to Fixnum as necessary</remarks>
+        [RubyMethod("divmod")]
+        public static RubyArray DivMod(BigInteger/*!*/ self, double other) {
+            if (other == 0.0) {
+                throw new FloatDomainError("NaN");
+            }
+
+            double selfFloat = self.ToFloat64();
+            BigInteger div = BigInteger.Create(selfFloat / other);
+            double mod = selfFloat % other;
+
+            return RubyOps.MakeArray2(Protocols.Normalize(div), mod);
+        }
+
+        /// <summary>
         /// Returns an array containing the quotient and modulus obtained by dividing self by other, where other is not Fixnum or Bignum.
         /// If <code>q, r = x.divmod(y)</code>, then 
         ///     <code>q = floor(float(x)/float(y))</code>
         ///     <code>x = q*y + r</code>
         /// </summary>
         /// <returns>Should return [self div other, self modulo other], but the divmod implementation is free to return an arbitrary object.</returns>
         /// <remarks>Coerces self and other using other.coerce(self) then dynamically invokes divmod</remarks>
         [RubyMethod("divmod")]
         public static object DivMod(BinaryOpStorage/*!*/ coercionStorage, BinaryOpStorage/*!*/ binaryOpSite, object/*!*/ self, object other) {
             return Protocols.CoerceAndApply(coercionStorage, binaryOpSite, "divmod", self, other);
         }
 
         #endregion
 
         #region remainder
@@ -362,36 +406,48 @@ namespace IronRuby.Builtins {
         /// <summary>
         /// Returns the remainder after dividing self by other, where other is Fixnum or Bignum.
         /// </summary>
         /// <example>
         /// -1234567890987654321.remainder(13731)      #=> -6966
         /// </example>
         /// <returns>Fixnum or Bignum</returns>
         [RubyMethod("remainder")]
         public static object Remainder(BigInteger/*!*/ self, [NotNull]BigInteger/*!*/ other) {
             BigInteger remainder;
             BigInteger.DivRem(self, other, out remainder);
             return Protocols.Normalize(remainder);
         }
 
         /// <summary>
-        /// Returns the remainder after dividing self by other, where other is not Fixnum or Bignum.
+        /// Returns the remainder after dividing self by other, where other is Float.
         /// </summary>
         /// <example>
         /// -1234567890987654321.remainder(13731.24)   #=> -9906.22531493148
         /// </example>
-        /// <returns>Float, Fixnum or Bignum</returns>
+        /// <returns>Float</returns>
+        [RubyMethod("remainder")]
+        public static double Remainder(BigInteger/*!*/ self, double other) {
+            return self.ToFloat64() % other;
+        }
+
+        /// <summary>
+        /// Returns the remainder after dividing self by other, where other is not Fixnum or Bignum.
+        /// </summary>
+        /// <example>
+        /// -1234567890987654321.remainder(13731)      #=> -6966
+        /// </example>
+        /// <returns>Fixnum or Bignum</returns>
         /// <remarks>Coerces self and other using other.coerce(self) then dynamically invokes remainder</remarks>
         [RubyMethod("remainder")]
         public static object Remainder(BinaryOpStorage/*!*/ coercionStorage, BinaryOpStorage/*!*/ binaryOpSite, object/*!*/ self, object other) {
             return Protocols.CoerceAndApply(coercionStorage, binaryOpSite, "remainder", self, other);
         }
 
         #endregion
 
         #endregion
 
         #region Comparisons
 
         #region <=>
 
         /// <summary>
@@ -750,31 +806,31 @@ namespace IronRuby.Builtins {
         #region to_s
 
         /// <summary>
         /// Returns a string containing the representation of self base 10.
         /// </summary>
         [RubyMethod("to_s")]
         public static MutableString/*!*/ ToString(BigInteger/*!*/ self) {
             return MutableString.Create(self.ToString());
         }
 
         /// <summary>
         /// Returns a string containing the representation of self base radix (2 through 36).
         /// </summary>
         /// <param name="radix">An integer between 2 and 36 inclusive</param>
         [RubyMethod("to_s")]
-        public static MutableString/*!*/ ToString(BigInteger/*!*/ self, uint radix) {
+        public static MutableString/*!*/ ToString(BigInteger/*!*/ self, int radix) {
             if (radix < 2 || radix > 36) {
                 throw RubyExceptions.CreateArgumentError(String.Format("illegal radix {0}", radix));
             }
 
             // TODO: Can we do the ToLower in BigInteger?
             return MutableString.Create(self.ToString((uint)radix).ToLower());
         }
 
         #endregion
 
         #region coerce
 
         /// <summary>
         /// Attempts to coerce other to a Bignum.
         /// </summary>
diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IListOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IListOps.cs
index 9ed59b8..ce53a97 100644
--- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IListOps.cs
+++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IListOps.cs
@@ -15,30 +15,32 @@
 
 using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using Microsoft.Scripting;
 using Microsoft.Scripting.Generation;
 using Microsoft.Scripting.Runtime;
 using Microsoft.Scripting.Utils;
 using IronRuby.Runtime;
 using IronRuby.Runtime.Calls;
 
+using EachSite = System.Func<System.Runtime.CompilerServices.CallSite, object, IronRuby.Builtins.Proc, object>;
+
 namespace IronRuby.Builtins {
 
     [RubyModule(Extends = typeof(IList), Restrictions = ModuleRestrictions.None)]
     [Includes(typeof(Enumerable))]
     public static class IListOps {
         
         #region Helpers
 
         // MRI: Some operations check frozen flag even if they don't change the array content.
         private static void RequireNotFrozen(IList/*!*/ self) {
             RubyArray array = self as RubyArray;
             if (array != null && array.IsFrozen) {
                 throw RubyExceptions.CreateObjectFrozenError();
             }
         }
@@ -290,32 +292,32 @@ namespace IronRuby.Builtins {
 
         internal static int IndexOf(CallSite<Func<CallSite, object, object, object>>/*!*/ equalitySite, IList/*!*/ self, object item) {
             for (int i = 0; i < self.Count; i++) {
                 if (Protocols.IsTrue(equalitySite.Target(equalitySite, item, self[i]))) {
                     return i;
                 }
             }
             return -1;
         }
 
         #endregion
 
         #region ==, <=>, eql?, hash
 
         [RubyMethod("==")]
-        public static bool Equals(ConversionStorage<IList>/*!*/ arrayTryCast, BinaryOpStorage/*!*/ equals, IList/*!*/ self, object other) {
-            IList otherAsArray = Protocols.TryCastToArray(arrayTryCast, other);
+        public static bool Equals(ConversionStorage<IList>/*!*/ arrayTryConvert, BinaryOpStorage/*!*/ equals, IList/*!*/ self, object other) {
+            IList otherAsArray = Protocols.TryConvertToArray(arrayTryConvert, other);
             return otherAsArray != null ? Equals(equals, self, otherAsArray) : false;
         }
 
         [MultiRuntimeAware]
         private static RubyUtils.RecursionTracker _EqualsTracker = new RubyUtils.RecursionTracker();
 
         [RubyMethod("==")]
         public static bool Equals(BinaryOpStorage/*!*/ equals, IList/*!*/ self, [NotNull]IList/*!*/ other) {
             Assert.NotNull(self, other);
 
             if (object.ReferenceEquals(self, other)) {
                 return true;
             }
 
             if (self.Count != other.Count) {
@@ -1521,17 +1523,32 @@ namespace IronRuby.Builtins {
                     seen.Add(key, true);
                     i++;
                 } else if (key == null && !nilSeen) {
                     nilSeen = true;
                     i++;
                 } else {
                     self.RemoveAt(i);
                     modified = true;
                 }
             }
 
             return modified ? self : null;
         }
 
         #endregion
+
+        #region zip 
+
+        [RubyMethod("zip")]
+        public static IList/*!*/ Zip(CallSiteStorage<EachSite>/*!*/ each, ConversionStorage<IList>/*!*/ tryToAry, BlockParam block,
+            object self, [NotNull]params object[] args) {
+
+            IList[] otherArrays = new IList[args.Length];
+            for (int i = 0; i < args.Length; i++) {
+                otherArrays[i] = args[i] as IList != null ? args[i] as IList : Protocols.TryCastToArray(tryToAry, args[i]);
+            }
+            return Enumerable.Zip(each, tryToAry, block, self, otherArrays);
+        }
+
+        #endregion
     }
 }
diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs
index 1fa3d06..c2dea59 100644
--- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs
+++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs
@@ -1870,55 +1870,56 @@ namespace IronRuby.Builtins {
                 new System.Func<IronRuby.Runtime.RubyContext, System.Object, IronRuby.Builtins.Hash>(IronRuby.Builtins.IronRubyOps.ClrOps.GetProfile), 
                 new System.Func<IronRuby.Runtime.RubyContext, IronRuby.Runtime.BlockParam, System.Object, System.Object>(IronRuby.Builtins.IronRubyOps.ClrOps.GetProfile)
             );
             
         }
         
         private static void LoadIronRuby__Clr__BigInteger_Instance(IronRuby.Builtins.RubyModule/*!*/ module) {
             module.DefineLibraryMethod("-", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Subtract), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Object>(IronRuby.Builtins.ClrBigInteger.Subtract), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.Subtract)
             );
             
             module.DefineLibraryMethod("%", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Modulo), 
+                new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Object>(IronRuby.Builtins.ClrBigInteger.Modulo), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.ModuloOp)
             );
             
             module.DefineLibraryMethod("&", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Int32, System.Object>(IronRuby.Builtins.ClrBigInteger.And), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.And), 
                 new System.Func<IronRuby.Runtime.RubyContext, Microsoft.Scripting.Math.BigInteger, IronRuby.Runtime.IntegerValue, System.Object>(IronRuby.Builtins.ClrBigInteger.And)
             );
             
             module.DefineLibraryMethod("*", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Multiply), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Object>(IronRuby.Builtins.ClrBigInteger.Multiply), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.Multiply)
             );
             
             module.DefineLibraryMethod("**", 0x51, 
                 new System.Func<IronRuby.Runtime.RubyContext, Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Power), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Int32, System.Object>(IronRuby.Builtins.ClrBigInteger.Power), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Object>(IronRuby.Builtins.ClrBigInteger.Power), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.Power)
             );
             
             module.DefineLibraryMethod("/", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Divide), 
-                new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Object>(IronRuby.Builtins.ClrBigInteger.Divide), 
+                new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Object>(IronRuby.Builtins.ClrBigInteger.DivideOp), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.Divide)
             );
             
             module.DefineLibraryMethod("-@", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Negate)
             );
             
             module.DefineLibraryMethod("[]", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Int32, System.Int32>(IronRuby.Builtins.ClrBigInteger.Bit), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Int32>(IronRuby.Builtins.ClrBigInteger.Bit)
             );
             
             module.DefineLibraryMethod("^", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Int32, System.Object>(IronRuby.Builtins.ClrBigInteger.Xor), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Xor), 
@@ -1970,66 +1971,69 @@ namespace IronRuby.Builtins {
             );
             
             module.DefineLibraryMethod("coerce", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.ClrBigInteger.Coerce), 
                 new System.Func<IronRuby.Runtime.RubyContext, Microsoft.Scripting.Math.BigInteger, System.Object, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.ClrBigInteger.Coerce)
             );
             
             module.DefineLibraryMethod("div", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Divide), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Object>(IronRuby.Builtins.ClrBigInteger.Divide), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.Div)
             );
             
             module.DefineLibraryMethod("divmod", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.ClrBigInteger.DivMod), 
+                new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, IronRuby.Builtins.RubyArray>(IronRuby.Builtins.ClrBigInteger.DivMod), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.DivMod)
             );
             
             module.DefineLibraryMethod("eql?", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Boolean>(IronRuby.Builtins.ClrBigInteger.Eql), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Int32, System.Boolean>(IronRuby.Builtins.ClrBigInteger.Eql), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Object, System.Boolean>(IronRuby.Builtins.ClrBigInteger.Eql)
             );
             
             module.DefineLibraryMethod("hash", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Int32>(IronRuby.Builtins.ClrBigInteger.Hash)
             );
             
             module.DefineLibraryMethod("modulo", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Modulo), 
+                new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Object>(IronRuby.Builtins.ClrBigInteger.Modulo), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.Modulo)
             );
             
             module.DefineLibraryMethod("quo", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Quotient), 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Object>(IronRuby.Builtins.ClrBigInteger.Quotient), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.Quotient)
             );
             
             module.DefineLibraryMethod("remainder", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, Microsoft.Scripting.Math.BigInteger, System.Object>(IronRuby.Builtins.ClrBigInteger.Remainder), 
+                new System.Func<Microsoft.Scripting.Math.BigInteger, System.Double, System.Double>(IronRuby.Builtins.ClrBigInteger.Remainder), 
                 new System.Func<IronRuby.Runtime.BinaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Object, System.Object, System.Object>(IronRuby.Builtins.ClrBigInteger.Remainder)
             );
             
             module.DefineLibraryMethod("to_f", 0x51, 
                 new System.Func<IronRuby.Runtime.RubyContext, Microsoft.Scripting.Math.BigInteger, System.Double>(IronRuby.Builtins.ClrBigInteger.ToFloat)
             );
             
             module.DefineLibraryMethod("to_s", 0x51, 
                 new System.Func<Microsoft.Scripting.Math.BigInteger, IronRuby.Builtins.MutableString>(IronRuby.Builtins.ClrBigInteger.ToString), 
-                new System.Func<Microsoft.Scripting.Math.BigInteger, System.UInt32, IronRuby.Builtins.MutableString>(IronRuby.Builtins.ClrBigInteger.ToString)
+                new System.Func<Microsoft.Scripting.Math.BigInteger, System.Int32, IronRuby.Builtins.MutableString>(IronRuby.Builtins.ClrBigInteger.ToString)
             );
             
         }
         
         private static void LoadIronRuby__Clr__FlagEnumeration_Instance(IronRuby.Builtins.RubyModule/*!*/ module) {
             module.DefineLibraryMethod("&", 0x51, 
                 new System.Func<IronRuby.Runtime.RubyContext, System.Object, System.Object, System.Object>(IronRuby.Builtins.FlagEnumOps.BitwiseAnd)
             );
             
             module.DefineLibraryMethod("^", 0x51, 
                 new System.Func<IronRuby.Runtime.RubyContext, System.Object, System.Object, System.Object>(IronRuby.Builtins.FlagEnumOps.Xor)
             );
             
             module.DefineLibraryMethod("|", 0x51, 
                 new System.Func<IronRuby.Runtime.RubyContext, System.Object, System.Object, System.Object>(IronRuby.Builtins.FlagEnumOps.BitwiseOr)
@@ -5397,30 +5401,34 @@ namespace IronRuby.Builtins {
             );
             
             module.DefineLibraryMethod("uniq!", 0x51, 
                 new System.Func<IronRuby.Runtime.UnaryOpStorage, IronRuby.Runtime.BinaryOpStorage, System.Collections.IList, System.Collections.IList>(IronRuby.Builtins.IListOps.UniqueSelf)
             );
             
             module.DefineLibraryMethod("unshift", 0x51, 
                 new System.Func<System.Collections.IList, System.Object, System.Collections.IList>(IronRuby.Builtins.IListOps.Unshift), 
                 new System.Func<System.Collections.IList, System.Object[], System.Collections.IList>(IronRuby.Builtins.IListOps.Unshift)
             );
             
             module.DefineLibraryMethod("values_at", 0x51, 
                 new System.Func<IronRuby.Runtime.ConversionStorage<System.Int32>, IronRuby.Runtime.CallSiteStorage<System.Func<System.Runtime.CompilerServices.CallSite, IronRuby.Builtins.RubyClass, System.Object>>, System.Collections.IList, System.Object[], IronRuby.Builtins.RubyArray>(IronRuby.Builtins.IListOps.ValuesAt)
             );
             
+            module.DefineLibraryMethod("zip", 0x51, 
+                new System.Func<IronRuby.Runtime.CallSiteStorage<System.Func<System.Runtime.CompilerServices.CallSite, System.Object, IronRuby.Builtins.Proc, System.Object>>, IronRuby.Runtime.ConversionStorage<System.Collections.IList>, IronRuby.Runtime.BlockParam, System.Object, System.Object[], System.Collections.IList>(IronRuby.Builtins.IListOps.Zip)
+            );
+            
         }
         
         private static void LoadSystem__IComparable_Instance(IronRuby.Builtins.RubyModule/*!*/ module) {
             module.DefineLibraryMethod("<=>", 0x51, 
                 new System.Func<System.IComparable, System.Object, System.Int32>(IronRuby.Builtins.IComparableOps.Compare)
             );
             
         }
         
         private static void LoadSystem__Int16_Instance(IronRuby.Builtins.RubyModule/*!*/ module) {
             LoadIronRuby__Clr__Integer_Instance(module);
             module.DefineLibraryMethod("size", 0x51, 
                 new System.Func<System.Int16, System.Int32>(IronRuby.Builtins.Int16Ops.Size)
             );
             


More information about the Ironruby-core mailing list