upto(p1, p2 = v2)
  public
  
    
    
Iterates through successive values, starting at str and ending at
other_str inclusive, passing each
value in turn to the block. The String#succ
method is used to generate each value.  If
optional second argument exclusive is omitted or is false, the last value
will be included; otherwise it will be excluded.
"a8".upto("b6") {|s| print s, ' ' }
for s in "a8".."b6"
  print s, ' '
end
produces:
a8 a9 b0 b1 b2 b3 b4 b5 b6
a8 a9 b0 b1 b2 b3 b4 b5 b6
   
  
    Show source    
    
      static VALUE
rb_str_upto(int argc, VALUE *argv, VALUE beg)
{
    VALUE end, exclusive;
    VALUE current, after_end;
    ID succ;
    int n, excl;
    rb_encoding *enc;
    rb_scan_args(argc, argv, "11", &end, &exclusive);
    RETURN_ENUMERATOR(beg, argc, argv);
    excl = RTEST(exclusive);
    CONST_ID(succ, "succ");
    StringValue(end);
    enc = rb_enc_check(beg, end);
    if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 &&
        is_ascii_string(beg) && is_ascii_string(end)) {
        char c = RSTRING_PTR(beg)[0];
        char e = RSTRING_PTR(end)[0];
        if (c > e || (excl && c == e)) return beg;
        for (;;) {
            rb_yield(rb_enc_str_new(&c, 1, enc));
            if (!excl && c == e) break;
            c++;
            if (excl && c == e) break;
        }
        return beg;
    }
    n = rb_str_cmp(beg, end);
    if (n > 0 || (excl && n == 0)) return beg;
        
    after_end = rb_funcall(end, succ, 0, 0);
    current = beg;
    while (!rb_str_equal(current, after_end)) {
        rb_yield(current);
        if (!excl && rb_str_equal(current, end)) break;
        current = rb_funcall(current, succ, 0, 0);
        StringValue(current);
        if (excl && rb_str_equal(current, end)) break;
        if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
            break;
    }
    return beg;
}