Hi Jim,
I'm a bit late but daytime work got in the way and then I was out of
the country for two weeks :-)
I got rid of the duplicated logic in IListOps.ReverseIndex and
ArrayOps.ReverseEach by implementing a new internal method
(IListOps.ReverseEnumerateIndexes):
http://github.com/nrk/ironruby/commit/76db817d1766b788f995afb02e12c5a72955c77f
As for the specs, I just slightly modified an existing one in a way
that does not affect the test but helped me to discover the bug
(actually this change uses a different condition from the one I used
one month ago as it exposed another bug which got fixed in the above
mentioned commit):
http://github.com/nrk/ironruby/commit/e5497cf87fc479b2bf2ca0b812d979354a86f44c
See also the attached diff.
Thanks,
Daniele
On Thu, Apr 23, 2009 at 22:08, Jim Deville <[email protected]> wrote:
> Can you add specs for rindex that expose the bug you fixed? Also, is there
> any shared place that you could put the following code:
> if (self.Count < originalSize) {
> i = originalSize - i - 1 + self.Count;
> originalSize = self.Count;
> }
>
> It would be nice to get rid of the duplicated logic, but I can't think of
> where it should go.
>
> Other than that, looks good.
> JD
>
>> -----Original Message-----
>> From: [email protected] [mailto:ironruby-core-
>> [email protected]] On Behalf Of Daniele Alessandri
>> Sent: Thursday, April 23, 2009 12:59 PM
>> To: [email protected]
>> Subject: [Ironruby-core] Review: fixes for Array#rindex and
>> Array#reverse_each
>>
>> Hi,
>> I just pushed two fixes on my repository, the first one addresses a bug
>> in Array#rindex (there was a bug in my last commit) and the second one
>> makes Array#reverse_each compliant with the rubyspecs.
>>
>> http://github.com/nrk/ironruby/commit/d2b18f5d01a49cb62a2ea0c205e1cf123
>> 3ac94e0
>>
>> >From the commit message:
>>
>> * Fixed a bug in IListOps.ReverseIndex (core/array/rindex specs were
>> passing, this bug was triggered under certain conditions different from
>> the ones defined in the specs)
>>
>> * Fixed ArrayOps.ReverseEach to make it not fail when elemens in the
>> array are removed from inside a block.
>>
>> See also the attached diff.
>>
>> Thanks,
>> Daniele
>>
>> --
>> Daniele Alessandri
>> http://www.clorophilla.net/blog/
>> http://twitter.com/JoL1hAHN
> _______________________________________________
> Ironruby-core mailing list
> [email protected]
> http://rubyforge.org/mailman/listinfo/ironruby-core
>
--
Daniele Alessandri
http://www.clorophilla.net/blog/
http://twitter.com/JoL1hAHN
diff --git
a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/core/array/rindex_spec.rb
b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/core/array/rindex_spec.rb
index 4971cf3..6e43c2b 100644
---
a/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/core/array/rindex_spec.rb
+++
b/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/core/array/rindex_spec.rb
@@ -17,31 +17,31 @@ describe "Array#rindex" do
it "returns size-1 if last element == to object" do
[2, 1, 3, 2, 5].rindex(5).should == 4
end
it "returns 0 if only first element == to object" do
[2, 1, 3, 1, 5].rindex(2).should == 0
end
it "returns nil if no element == to object" do
[1, 1, 3, 2, 1, 3].rindex(4).should == nil
end
it "does not fail when removing elements from block" do
sentinel = mock('sentinel')
- ary = [0, 0, 1, 1, 3, 2, 1, sentinel]
+ ary = [0, 0, 1, 1, 3, 2, 1, sentinel, 4]
sentinel.instance_variable_set(:@ary, ary)
def sentinel.==(o) @ary.slice!(1..-1); false; end
ary.rindex(0).should == 0
end
it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
empty.rindex(empty).should == 0
empty.rindex(1).should be_nil
array = ArraySpecs.recursive_array
array.rindex(1).should == 0
array.rindex([array]).should == 3
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 f83c4c7..301007a 100644
--- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ArrayOps.cs
+++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ArrayOps.cs
@@ -546,31 +546,27 @@ namespace IronRuby.Builtins {
[RubyMethod("reverse!")]
public static RubyArray/*!*/ InPlaceReverse(RubyContext/*!*/ context,
RubyArray/*!*/ self) {
RubyUtils.RequiresNotFrozen(context, self);
self.Reverse();
return self;
}
[RubyMethod("reverse_each")]
public static object ReverseEach(RubyContext/*!*/ context, BlockParam
block, RubyArray/*!*/ self) {
Assert.NotNull(context, self);
if (self.Count > 0 && block == null) {
throw RubyExceptions.NoBlockGiven();
}
- for (int originalSize = self.Count, i = originalSize - 1; i >= 0;
i--) {
+ foreach (int index in IListOps.ReverseEnumerateIndexes(self)) {
object result;
- if (block.Yield(self[i], out result)) {
+ if (block.Yield(self[index], out result)) {
return result;
}
- if (self.Count < originalSize) {
- i = originalSize - i - 1 + self.Count;
- originalSize = self.Count;
- }
}
return self;
}
#endregion
}
}
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 e1197ad..3224c55 100644
--- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IListOps.cs
+++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IListOps.cs
@@ -138,30 +138,40 @@ namespace IronRuby.Builtins {
if (array != null) {
return array.CreateInstance();
}
// interop - call a default ctor to get an instance:
var allocate = allocateStorage.GetCallSite("allocate", 0);
var cls = allocateStorage.Context.GetClassOf(list);
var result = allocate.Target(allocate, cls) as IList;
if (result != null) {
return result;
}
throw RubyExceptions.CreateTypeError(String.Format("{0}#allocate
should return IList", cls.Name));
}
+ internal static IEnumerable<Int32>/*!*/
ReverseEnumerateIndexes(IList/*!*/ collection) {
+ for (int originalSize = collection.Count, i = originalSize - 1; i
>= 0; i--) {
+ yield return i;
+ if (collection.Count < originalSize) {
+ i = originalSize - (originalSize - collection.Count);
+ originalSize = collection.Count;
+ }
+ }
+ }
+
#endregion
#region initialize_copy, replace, clear, to_a, to_ary
[RubyMethod("replace")]
[RubyMethod("initialize_copy", RubyMethodAttributes.PrivateInstance)]
public static IList/*!*/ Replace(RubyContext/*!*/ context, IList/*!*/
self, [NotNull, DefaultProtocol]IList/*!*/ other) {
RubyUtils.RequiresNotFrozen(context, self);
self.Clear();
AddRange(self, other);
return self;
}
[RubyMethod("clear")]
@@ -1022,37 +1032,33 @@ namespace IronRuby.Builtins {
return Index(equals, self, item) != null;
}
[RubyMethod("index")]
public static object Index(BinaryOpStorage/*!*/ equals, IList/*!*/
self, object item) {
for (int i = 0; i < self.Count; ++i) {
if (Protocols.IsEqual(equals, self[i], item)) {
return i;
}
}
return null;
}
[RubyMethod("rindex")]
public static object ReverseIndex(BinaryOpStorage/*!*/ equals,
IList/*!*/ self, object item) {
- for (int originalSize = self.Count, i = originalSize - 1; i >= 0;
i--) {
- if (Protocols.IsEqual(equals, self[i], item)) {
- return i;
- }
- if (self.Count < originalSize) {
- i = originalSize - i - 1 + self.Count;
- originalSize = self.Count;
+ foreach (int index in IListOps.ReverseEnumerateIndexes(self)) {
+ if (Protocols.IsEqual(equals, self[index], item)) {
+ return index;
}
}
return null;
}
#endregion
#region indexes, indices, values_at
[RubyMethod("indexes")]
[RubyMethod("indices")]
public static object Indexes(ConversionStorage<int>/*!*/ fixnumCast,
CallSiteStorage<Func<CallSite, RubyClass, object>>/*!*/
allocateStorage,
IList/*!*/ self, [NotNull]params object[]/*!*/ values) {
fixnumCast.Context.ReportWarning("Array#indexes and Array#indices
are deprecated; use Array#values_at");
_______________________________________________
Ironruby-core mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/ironruby-core