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:
parent
88135845f1
commit
42c652d195
Notes:
git
2019-10-25 23:31:12 +09:00
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(min, max) -> obj
|
||||||
* obj.clamp(range) -> obj
|
* obj.clamp(range) -> obj
|
||||||
*
|
*
|
||||||
* In the first form, returns _min_ if _obj_ <code><=></code> _min_ is
|
* In <code>(min, max)</code> form, returns _min_ if _obj_
|
||||||
* less than zero, _max_ if _obj_ <code><=></code> _max_ is greater
|
* <code><=></code> _min_ is less than zero, _max_ if _obj_
|
||||||
* than zero and _obj_ otherwise. In the second form, clamps by
|
* <code><=></code> _max_ is greater than zero, and _obj_
|
||||||
* _range.min_ and _range.max_. If _range_ is an exclusive range,
|
* otherwise.
|
||||||
* raises an ArgumentError.
|
|
||||||
*
|
*
|
||||||
* 12.clamp(0, 100) #=> 12
|
* 12.clamp(0, 100) #=> 12
|
||||||
* 523.clamp(0, 100) #=> 100
|
* 523.clamp(0, 100) #=> 100
|
||||||
* -3.123.clamp(0, 100) #=> 0
|
* -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
|
* 12.clamp(0..100) #=> 12
|
||||||
* 523.clamp(0..100) #=> 100
|
* 523.clamp(0..100) #=> 100
|
||||||
* -3.123.clamp(0..100) #=> 0
|
* -3.123.clamp(0..100) #=> 0
|
||||||
*
|
*
|
||||||
* 'd'.clamp('a', 'f') #=> 'd'
|
|
||||||
* 'z'.clamp('a', 'f') #=> 'f'
|
|
||||||
* 'd'.clamp('a'..'f') #=> 'd'
|
* 'd'.clamp('a'..'f') #=> 'd'
|
||||||
* 'z'.clamp('a'..'f') #=> 'f'
|
* '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
|
static VALUE
|
||||||
cmp_clamp(int argc, VALUE *argv, VALUE x)
|
cmp_clamp(int argc, VALUE *argv, VALUE x)
|
||||||
{
|
{
|
||||||
VALUE min, max;
|
VALUE min, max;
|
||||||
int c;
|
int c, excl = 0, allow_nil = 0;
|
||||||
|
|
||||||
if (rb_scan_args(argc, argv, "11", &min, &max) == 1) {
|
if (rb_scan_args(argc, argv, "11", &min, &max) == 1) {
|
||||||
VALUE range = min;
|
VALUE range = min;
|
||||||
int excl;
|
|
||||||
if (!rb_range_values(range, &min, &max, &excl)) {
|
if (!rb_range_values(range, &min, &max, &excl)) {
|
||||||
rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
|
rb_raise(rb_eTypeError, "wrong argument type %s (expected Range)",
|
||||||
rb_builtin_class_name(range));
|
rb_builtin_class_name(range));
|
||||||
}
|
}
|
||||||
if (excl || NIL_P(min) || NIL_P(max)) {
|
allow_nil = 1;
|
||||||
rb_raise(rb_eArgError, "cannot clamp with an exclusive range");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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");
|
rb_raise(rb_eArgError, "min argument must be smaller than max argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
c = cmpint(x, min);
|
if (!NIL_P(min)) {
|
||||||
if (c == 0) return x;
|
c = cmpint(x, min);
|
||||||
if (c < 0) return min;
|
if (c == 0) return x;
|
||||||
c = cmpint(x, max);
|
if (c < 0) return min;
|
||||||
if (c > 0) return max;
|
}
|
||||||
|
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;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,14 +99,21 @@ class TestComparable < Test::Unit::TestCase
|
|||||||
assert_equal(1, @o.clamp(1..1))
|
assert_equal(1, @o.clamp(1..1))
|
||||||
assert_equal(@o, @o.clamp(0..0))
|
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') {
|
assert_raise_with_message(ArgumentError, 'cannot clamp with an exclusive range') {
|
||||||
@o.clamp(1...2)
|
@o.clamp(-1...0)
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
assert_raise_with_message(ArgumentError, 'min argument must be smaller than max argument') {
|
assert_raise_with_message(ArgumentError, 'min argument must be smaller than max argument') {
|
||||||
@o.clamp(2..1)
|
@o.clamp(2..1)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user