Problem of discrete membership at Range#=== is that it returns unexpected result when treating float-like Classes. Class Time is represented as float so (Time.new...Time.new+5)===Time.new returns false. Time#to_int should be added | add check if object can to_f Or apply my patch which idea is that object should care if he is at given range I choose Comparable#between? but I rather change its arguments to low.between?(value, high,excl) because now value doesnt know what range represents and can only guess that they are same type.(I dont know how frequently its used. ) Written String#between? with has linear time to size of strings . BTW Now I know that I am addicted to ruby because I tried three times post it to ruby-core / ruby-lang.rb Index: range.c =================================================================== RCS file: /src/ruby/range.c,v retrieving revision 1.84 diff -u -p -r1.84 range.c --- range.c 3 Aug 2006 06:21:03 -0000 1.84 +++ range.c 11 Aug 2006 16:54:46 -0000 @@ -14,7 +14,7 @@ #include "env.h" VALUE rb_cRange; -static ID id_cmp, id_succ, id_beg, id_end, id_excl; +static ID id_cmp, id_succ, id_beg, id_end, id_excl,id_between; #define EXCL(r) RTEST(rb_ivar_get((r), id_excl)) #define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v) ? Qtrue : Qfalse) @@ -139,6 +139,15 @@ r_lt(VALUE a, VALUE b) if (rb_cmpint(r, a, b) < 0) return Qtrue; return Qfalse; } +static int +r_eq(VALUE a, VALUE b) +{ + VALUE r = rb_funcall(a, id_cmp, 1, b); + + if (NIL_P(r)) return Qfalse; + if (rb_cmpint(r, a, b) == 0) return Qtrue; + return Qfalse; +} static int r_le(VALUE a, VALUE b) @@ -621,23 +630,10 @@ range_include(VALUE range, VALUE val) { VALUE beg = rb_ivar_get(range, id_beg); VALUE end = rb_ivar_get(range, id_end); - int nv = FIXNUM_P(beg) || FIXNUM_P(end) || - rb_obj_is_kind_of(beg, rb_cNumeric) || - rb_obj_is_kind_of(end, rb_cNumeric); - - if (nv || - !NIL_P(rb_check_to_integer(beg, "to_int")) || - !NIL_P(rb_check_to_integer(end, "to_int"))) { - if (r_le(beg, val)) { - if (EXCL(range)) { - if (r_lt(val, end)) return Qtrue; - } - else { - if (r_le(val, end)) return Qtrue; - } - } - return Qfalse; - } + if (rb_respond_to(val,id_between)){ + if (EXCL(range) && r_eq(val, end)) return Qfalse; + return rb_funcall(val,id_between,2,beg,end); + } ruby_frame->this_func = rb_intern("include?"); return rb_call_super(1, &val); } @@ -758,4 +754,6 @@ Init_Range(void) id_beg = rb_intern("begin"); id_end = rb_intern("end"); id_excl = rb_intern("excl"); + id_between = rb_intern("between?"); + } Index: string.c =================================================================== RCS file: /src/ruby/string.c,v retrieving revision 1.255 diff -u -p -r1.255 string.c --- string.c 26 Jul 2006 07:43:16 -0000 1.255 +++ string.c 11 Aug 2006 16:56:15 -0000 @@ -997,6 +997,34 @@ rb_str_cmp_m(VALUE str1, VALUE str2) return LONG2NUM(result); } +static inline int str_same(const char a,const char b){ + if (a==b||b<'0') + return 1; + if ('0'<= a && a<='9') return ('0'<=b && b<='9'); + if ('a'<= a && a<='z') return ('a'<=b && b<='z'); + if ('A'<= a && a<='Z') return ('A'<=b && b<='Z'); + return 0; +} +static VALUE rb_str_between(VALUE self,VALUE low,VALUE hig){ + str=rb_funcall(self,rb_intern("to_str"),0);//dont know what will inherance do with it + low=rb_funcall(low,rb_intern("to_str"),0); + hig=rb_funcall(hig,rb_intern("to_str"),0); + char *s=RSTRING(str)->ptr,*l=RSTRING(low)->ptr,*h=RSTRING(hig)->ptr; + int ss=RSTRING(str)->len,sl=RSTRING(low)->len,sh=RSTRING(hig)->len; + if ( ss<sl && ss>sh) return Qfalse; + int i; + for (i=0;i<sl;i++) + if (!str_same(l[i],s[i])) return Qfalse; + for (i=sl;i<ss;i++) + if (!str_same(l[ss-1],s[i])) return Qfalse; + if (sl==ss){ + if (strcmp(l,s)>0)return Qfalse; + } + if (ss==sh){ + if (strcmp(s,h)>=0)return Qfalse; + } + return Qtrue; +} + /* * call-seq: * str.casecmp(other_str) => -1, 0, +1 @@ -4293,6 +4321,7 @@ Init_String(void) rb_define_method(rb_cString, "initialize_copy", rb_str_replace, 1); rb_define_method(rb_cString, "<=>", rb_str_cmp_m, 1); rb_define_method(rb_cString, "==", rb_str_equal, 1); + rb_define_method(rb_cString, "between?", rb_str_between, 2); rb_define_method(rb_cString, "eql?", rb_str_eql, 1); rb_define_method(rb_cString, "hash", rb_str_hash_m, 0); rb_define_method(rb_cString, "casecmp", rb_str_casecmp, 1);