From 42c652d1959564bc5fb5147c8c343d8c0589583c Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 25 Oct 2019 22:09:38 +0900 Subject: Fixed range argument condition [Feature #14784] Allows a beginless/endless range, and an end-exclusive range unless the receiver is smaller than its end. --- compar.c | 56 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 19 deletions(-) (limited to 'compar.c') diff --git a/compar.c b/compar.c index fe4cc42833..058d912b4c 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_ <=> _min_ is - * less than zero, _max_ if _obj_ <=> _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 (min, max) form, returns _min_ if _obj_ + * <=> _min_ is less than zero, _max_ if _obj_ + * <=> _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 (range) form, returns _range.begin_ if _obj_ + * <=> _range.begin_ is less than zero, _range.end_ + * if _obj_ <=> _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; } -- cgit v1.2.3