From eab07daf92c9a8a2836923656d9e8f58583a52ba Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:41:10 -0700 Subject: Add Range#max and Range#min tests from Ruby Spec --- mrbgems/mruby-range-ext/test/range.rb | 101 ++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'mrbgems/mruby-range-ext') diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb index efcbdabe4..6b135aeff 100644 --- a/mrbgems/mruby-range-ext/test/range.rb +++ b/mrbgems/mruby-range-ext/test/range.rb @@ -30,3 +30,104 @@ assert('Range#size') do assert_equal Float::INFINITY, (0..Float::INFINITY).size assert_nil ('a'..'z').size end + +assert('Range#max') do + # returns the maximum value in the range when called with no arguments + assert_equal 10, (1..10).max + assert_equal 9, (1...10).max + assert_equal 4294967295, (0...2**32).max + + # returns the maximum value in the Float range when called with no arguments + assert_equal 908.1111, (303.20..908.1111).max + + # raises TypeError when called on an exclusive range and a non Integer value + assert_raise(TypeError) { (303.20...908.1111).max } + + # returns nil when the endpoint is less than the start point + assert_equal nil, (100..10).max + + # returns nil when the endpoint equals the start point and the range is exclusive + assert_equal nil, (5...5).max + + # returns the endpoint when the endpoint equals the start point and the range is inclusive + assert_equal 5, (5..5).max + + # returns nil when the endpoint is less than the start point in a Float range + assert_equal nil, (3003.20..908.1111).max +end + +assert('Range#max given a block') do + # passes each pair of values in the range to the block + acc = [] + (1..10).max do |a, b| + acc << a + acc << b + a + end + (1..10).each do |value| + assert_true acc.include?(value) + end + + # passes each pair of elements to the block in reversed order + acc = [] + (1..5).max do |a, b| + acc << [a, b] + a + end + assert_equal [[2, 1], [3, 2], [4, 3], [5, 4]], acc + + # returns the element the block determines to be the maximum + assert_equal 1, ((1..3).max { |_a, _b| -3 }) + + # returns nil when the endpoint is less than the start point + assert_equal nil, ((100..10).max { |x, y| x <=> y }) + assert_equal nil, ((5...5).max { |x, y| x <=> y }) +end + +assert('Range#min') do + # returns the minimum value in the range when called with no arguments + assert_equal 1, (1..10).min + + # returns the minimum value in the Float range when called with no arguments + assert_equal 303.20, (303.20..908.1111).min + + # returns nil when the start point is greater than the endpoint + assert_equal nil, (100..10).min + + # returns nil when the endpoint equals the start point and the range is exclusive + assert_equal nil, (5...5).max + + # returns the endpoint when the endpoint equals the start point and the range is inclusive + assert_equal 5, (5..5).max + + # returns nil when the start point is greater than the endpoint in a Float range + assert_equal nil, (3003.20..908.1111).max +end + +assert('Range#min given a block') do + # passes each pair of values in the range to the block + acc = [] + (1..10).min do |a, b| + acc << a + acc << b + a + end + (1..10).each do |value| + assert_true acc.include?(value) + end + + # passes each pair of elements to the block in reversed order + acc = [] + (1..5).min do |a, b| + acc << [a, b] + a + end + assert_equal [[2, 1], [3, 1], [4, 1], [5, 1]], acc + + # returns the element the block determines to be the minimum + assert_equal 3, ((1..3).min { |_a, _b| -3 }) + + # returns nil when the start point is greater than the endpoint + assert_equal nil, ((100..10).min { |x, y| x <=> y }) + assert_equal nil, ((5...5).min { |x, y| x <=> y }) +end -- cgit v1.2.3 From 0ad5ba7a0f819cff87460d9b6f5691656ea75ade Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:42:40 -0700 Subject: Add a fast path for Float and Fixnum ranges for Range#max and Range#min If no block is given and the Range has Fixnum or Float endpoints, do not iterate with each and instead compare the endpoints directly. This implementation passes all of the applicable specs from Ruby Spec. --- mrbgems/mruby-range-ext/mrblib/range.rb | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'mrbgems/mruby-range-ext') diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index de7925ba7..e09b2d096 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -25,4 +25,44 @@ class Range end ary end + + def max(&block) + val = self.first + last = self.last + return super if block + + # fast path for numerics + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + raise TypeError if exclude_end? && !last.kind_of?(Fixnum) + return nil if val > last + return nil if val == last && exclude_end? + + max = last + max -= 1 if exclude_end? + return max + end + + # delegate to Enumerable + super + end + + def min(&block) + val = self.first + last = self.last + return super if block + + # fast path for numerics + if (val.kind_of?(Fixnum) || val.kind_of?(Float)) && (last.kind_of?(Fixnum) || last.kind_of?(Float)) + raise TypeError if exclude_end? && !last.kind_of?(Fixnum) + return nil if val > last + return nil if val == last && exclude_end? + + min = val + min -= 1 if exclude_end? + return min + end + + # delegate to Enumerable + super + end end -- cgit v1.2.3 From 56929362f58ba5ad3ebe4131a6cc4259e6479dc0 Mon Sep 17 00:00:00 2001 From: Ryan Lopopolo Date: Tue, 9 Jul 2019 01:48:15 -0700 Subject: Fix Range#min fast path with exclusive range --- mrbgems/mruby-range-ext/mrblib/range.rb | 1 - mrbgems/mruby-range-ext/test/range.rb | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-range-ext') diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index e09b2d096..a149a57dc 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -58,7 +58,6 @@ class Range return nil if val == last && exclude_end? min = val - min -= 1 if exclude_end? return min end diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb index 6b135aeff..b56d6b58e 100644 --- a/mrbgems/mruby-range-ext/test/range.rb +++ b/mrbgems/mruby-range-ext/test/range.rb @@ -87,6 +87,7 @@ end assert('Range#min') do # returns the minimum value in the range when called with no arguments assert_equal 1, (1..10).min + assert_equal 1, (1...10).min # returns the minimum value in the Float range when called with no arguments assert_equal 303.20, (303.20..908.1111).min -- cgit v1.2.3