summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-range-ext
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2019-07-17 10:35:41 +0900
committerGitHub <[email protected]>2019-07-17 10:35:41 +0900
commitd605b72c1d6fa4564a0a5e88535504b6850463b5 (patch)
tree774fc0de56002abb3bb2b1c3387ff08f91876d17 /mrbgems/mruby-range-ext
parent2af92d0ebcbeca6d3d85a27c8193273080a63090 (diff)
parent9af3b7c6258de327218dd04e69d76ae68caf17b1 (diff)
downloadmruby-d605b72c1d6fa4564a0a5e88535504b6850463b5.tar.gz
mruby-d605b72c1d6fa4564a0a5e88535504b6850463b5.zip
Merge branch 'master' into i110/inspect-recursion
Diffstat (limited to 'mrbgems/mruby-range-ext')
-rw-r--r--mrbgems/mruby-range-ext/mrblib/range.rb44
-rw-r--r--mrbgems/mruby-range-ext/src/range.c31
-rw-r--r--mrbgems/mruby-range-ext/test/range.rb102
3 files changed, 159 insertions, 18 deletions
diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb
index e5d1fb079..a149a57dc 100644
--- a/mrbgems/mruby-range-ext/mrblib/range.rb
+++ b/mrbgems/mruby-range-ext/mrblib/range.rb
@@ -15,10 +15,7 @@ class Range
raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 1)" unless args.length == 1
nv = args[0]
- raise TypeError, "no implicit conversion from nil to integer" if nv.nil?
- raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless nv.respond_to?(:to_int)
- n = nv.to_int
- raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless n.kind_of?(Integer)
+ n = nv.__to_int
raise ArgumentError, "negative array size (or size too big)" unless 0 <= n
ary = []
each do |i|
@@ -28,4 +25,43 @@ 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
+ return min
+ end
+
+ # delegate to Enumerable
+ super
+ end
end
diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c
index aca71cc01..fb76fe0d8 100644
--- a/mrbgems/mruby-range-ext/src/range.c
+++ b/mrbgems/mruby-range-ext/src/range.c
@@ -1,3 +1,7 @@
+#ifdef MRB_WITHOUT_FLOAT
+# error Conflict 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb'
+#endif
+
#include <mruby.h>
#include <mruby/range.h>
#include <math.h>
@@ -40,7 +44,7 @@ r_lt(mrb_state *mrb, mrb_value a, mrb_value b)
* ("a".."z").cover?("cc") #=> true
*/
static mrb_value
-mrb_range_cover(mrb_state *mrb, mrb_value range)
+range_cover(mrb_state *mrb, mrb_value range)
{
mrb_value val;
struct RRange *r = mrb_range_ptr(mrb, range);
@@ -48,11 +52,11 @@ mrb_range_cover(mrb_state *mrb, mrb_value range)
mrb_get_args(mrb, "o", &val);
- beg = r->edges->beg;
- end = r->edges->end;
+ beg = RANGE_BEG(r);
+ end = RANGE_END(r);
if (r_le(mrb, beg, val)) {
- if (r->excl) {
+ if (RANGE_EXCL(r)) {
if (r_lt(mrb, val, end))
return mrb_true_value();
}
@@ -82,14 +86,13 @@ mrb_range_cover(mrb_state *mrb, mrb_value range)
* (10...20).last(3) #=> [17, 18, 19]
*/
static mrb_value
-mrb_range_last(mrb_state *mrb, mrb_value range)
+range_last(mrb_state *mrb, mrb_value range)
{
mrb_value num;
mrb_value array;
- struct RRange *r = mrb_range_ptr(mrb, range);
if (mrb_get_args(mrb, "|o", &num) == 0) {
- return r->edges->end;
+ return mrb_range_end(mrb, range);
}
array = mrb_funcall(mrb, range, "to_a", 0);
@@ -108,7 +111,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range)
*/
static mrb_value
-mrb_range_size(mrb_state *mrb, mrb_value range)
+range_size(mrb_state *mrb, mrb_value range)
{
struct RRange *r = mrb_range_ptr(mrb, range);
mrb_value beg, end;
@@ -116,9 +119,9 @@ mrb_range_size(mrb_state *mrb, mrb_value range)
mrb_bool num_p = TRUE;
mrb_bool excl;
- beg = r->edges->beg;
- end = r->edges->end;
- excl = r->excl;
+ beg = RANGE_BEG(r);
+ end = RANGE_END(r);
+ excl = RANGE_EXCL(r);
if (mrb_fixnum_p(beg)) {
beg_f = (mrb_float)mrb_fixnum(beg);
}
@@ -165,9 +168,9 @@ mrb_mruby_range_ext_gem_init(mrb_state* mrb)
{
struct RClass * s = mrb_class_get(mrb, "Range");
- mrb_define_method(mrb, s, "cover?", mrb_range_cover, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, s, "last", mrb_range_last, MRB_ARGS_OPT(1));
- mrb_define_method(mrb, s, "size", mrb_range_size, MRB_ARGS_NONE());
+ mrb_define_method(mrb, s, "cover?", range_cover, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, s, "last", range_last, MRB_ARGS_OPT(1));
+ mrb_define_method(mrb, s, "size", range_size, MRB_ARGS_NONE());
}
void
diff --git a/mrbgems/mruby-range-ext/test/range.rb b/mrbgems/mruby-range-ext/test/range.rb
index efcbdabe4..b56d6b58e 100644
--- a/mrbgems/mruby-range-ext/test/range.rb
+++ b/mrbgems/mruby-range-ext/test/range.rb
@@ -30,3 +30,105 @@ 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
+ 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