зеркало из https://github.com/github/ruby.git
Fixed range argument condition [Feature #14784]
Allows a beginless/endless range, and an end-exclusive range unless the receiver is smaller than its end.
This commit is contained in:
Родитель
88135845f1
Коммит
42c652d195
56
compar.c
56
compar.c
|
@ -179,53 +179,71 @@ cmp_between(VALUE x, VALUE min, VALUE max)
|
|||
* obj.clamp(min, max) -> obj
|
||||
* obj.clamp(range) -> obj
|
||||
*
|
||||
* In the first form, returns _min_ if _obj_ <code><=></code> _min_ is
|
||||
* less than zero, _max_ if _obj_ <code><=></code> _max_ is greater
|
||||
* than zero and _obj_ otherwise. In the second form, clamps by
|
||||
* _range.min_ and _range.max_. If _range_ is an exclusive range,
|
||||
* raises an ArgumentError.
|
||||
* In <code>(min, max)</code> form, returns _min_ if _obj_
|
||||
* <code><=></code> _min_ is less than zero, _max_ if _obj_
|
||||
* <code><=></code> _max_ is greater than zero, and _obj_
|
||||
* otherwise.
|
||||
*
|
||||
* 12.clamp(0, 100) #=> 12
|
||||
* 523.clamp(0, 100) #=> 100
|
||||
* -3.123.clamp(0, 100) #=> 0
|
||||
*
|
||||
* 'd'.clamp('a', 'f') #=> 'd'
|
||||
* 'z'.clamp('a', 'f') #=> 'f'
|
||||
*
|
||||
* In <code>(range)</code> form, returns _range.begin_ if _obj_
|
||||
* <code><=></code> _range.begin_ is less than zero, _range.end_
|
||||
* if _obj_ <code><=></code> _range.end_ is greater than zero, and
|
||||
* _obj_ otherwise.
|
||||
*
|
||||
* 12.clamp(0..100) #=> 12
|
||||
* 523.clamp(0..100) #=> 100
|
||||
* -3.123.clamp(0..100) #=> 0
|
||||
*
|
||||
* 'd'.clamp('a', 'f') #=> 'd'
|
||||
* 'z'.clamp('a', 'f') #=> 'f'
|
||||
* 'd'.clamp('a'..'f') #=> 'd'
|
||||
* 'z'.clamp('a'..'f') #=> 'f'
|
||||
*
|
||||
* 12.clamp(0...100) #=> ArgumentError
|
||||
* If _range.begin_ is +nil+, it is considered smaller than _obj_,
|
||||
* and if _range.end_ is +nil+, it is considered greater than
|
||||
* _obj_.
|
||||
*
|
||||
* -20.clamp(0..) #=> 0
|
||||
* 523.clamp(..100) #=> 100
|
||||
*
|
||||
* When _range.end_ is excluded, and _obj_ is greater than or
|
||||
* equal to _range.end_, an exception is raised.
|
||||
*
|
||||
* 100.clamp(0...100) # ArgumentError
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
cmp_clamp(int argc, VALUE *argv, VALUE x)
|
||||
{
|
||||
VALUE min, max;
|
||||
int c;
|
||||
int c, excl = 0, allow_nil = 0;
|
||||
|
||||
if (rb_scan_args(argc, argv, "11", &min, &max) == 1) {
|
||||
VALUE range = min;
|
||||
int excl;
|
||||
if (!rb_range_values(range, &min, &max, &excl)) {
|
||||
rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
|
||||
rb_builtin_class_name(range));
|
||||
}
|
||||
if (excl || NIL_P(min) || NIL_P(max)) {
|
||||
rb_raise(rb_eArgError, "cannot clamp with an exclusive range");
|
||||
}
|
||||
allow_nil = 1;
|
||||
}
|
||||
if (cmpint(min, max) > 0) {
|
||||
if (!(allow_nil && (NIL_P(min) || NIL_P(max))) && cmpint(min, max) > 0) {
|
||||
rb_raise(rb_eArgError, "min argument must be smaller than max argument");
|
||||
}
|
||||
|
||||
c = cmpint(x, min);
|
||||
if (c == 0) return x;
|
||||
if (c < 0) return min;
|
||||
c = cmpint(x, max);
|
||||
if (c > 0) return max;
|
||||
if (!NIL_P(min)) {
|
||||
c = cmpint(x, min);
|
||||
if (c == 0) return x;
|
||||
if (c < 0) return min;
|
||||
}
|
||||
if (!NIL_P(max)) {
|
||||
c = cmpint(x, max);
|
||||
if (excl && c >= 0) rb_raise(rb_eArgError, "cannot clamp with an exclusive range");
|
||||
if (c > 0) return max;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
|
|
@ -99,14 +99,21 @@ class TestComparable < Test::Unit::TestCase
|
|||
assert_equal(1, @o.clamp(1..1))
|
||||
assert_equal(@o, @o.clamp(0..0))
|
||||
|
||||
assert_equal(1, @o.clamp(1...2))
|
||||
assert_equal(1, @o.clamp(1..))
|
||||
assert_equal(1, @o.clamp(1...))
|
||||
assert_equal(@o, @o.clamp(0...2))
|
||||
assert_equal(@o, @o.clamp(0..))
|
||||
assert_equal(@o, @o.clamp(0...))
|
||||
assert_equal(@o, @o.clamp(..2))
|
||||
assert_equal(@o, @o.clamp(...2))
|
||||
assert_equal(-1, @o.clamp(-2..-1))
|
||||
assert_equal(@o, @o.clamp(-2..0))
|
||||
assert_equal(@o, @o.clamp(-2..))
|
||||
assert_equal(@o, @o.clamp(-2...))
|
||||
|
||||
assert_raise_with_message(ArgumentError, 'cannot clamp with an exclusive range') {
|
||||
@o.clamp(1...2)
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, 'cannot clamp with an exclusive range') {
|
||||
@o.clamp(1...)
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, 'cannot clamp with an exclusive range') {
|
||||
@o.clamp(...2)
|
||||
@o.clamp(-1...0)
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, 'min argument must be smaller than max argument') {
|
||||
@o.clamp(2..1)
|
||||
|
|
Загрузка…
Ссылка в новой задаче