summaryrefslogtreecommitdiff
path: root/compar.c
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2019-10-25 22:09:38 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-10-25 23:30:47 +0900
commit42c652d1959564bc5fb5147c8c343d8c0589583c (patch)
tree4d5a3f1344d97f8e6f65e299e702bb7326f5dc49 /compar.c
parent88135845f10f4b8ea3b67584a2c899ad365fd6bb (diff)
Fixed range argument condition [Feature #14784]
Allows a beginless/endless range, and an end-exclusive range unless the receiver is smaller than its end.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2611
Diffstat (limited to 'compar.c')
-rw-r--r--compar.c56
1 files changed, 37 insertions, 19 deletions
diff --git a/compar.c b/compar.c
index fe4cc42..058d912 100644
--- a/compar.c
+++ b/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;
}