From: Josh Cheek Date: 2011-05-02T04:03:03+09:00 Subject: Re: Understanding Ruby Inside Out --20cf3071cfae466a6204a23b8ef6 Content-Type: text/plain; charset=ISO-8859-1 On Sun, May 1, 2011 at 1:56 PM, Josh Cheek wrote: > On Sun, May 1, 2011 at 4:29 AM, Konstantin Ka wrote: > >> >> Would there be any way that Ruby-Newbie-mme could come along, have a >> look inside the preprogrammed String class and see written there in Ruby >> language >> >> > def rand >> > self.split('').shuffle.join >> > end >> >> ... because that would enable me to go "Oh, sure! It splits the string, >> shuffles it, and joins it back together. Sounds easy!" even if, to find >> out what some of those "1st tier" methods like .split actually do, I'd >> have to go look at the C code. >> >> >> > Check out the gem pry (get it by going to the command line and typing "gem > install pry pry-doc" -- possibly requiring "sudo" privelages, and possibly > not working on 1.8.6) > > Then you can start a pry session with "pry" > Sorry I hit space or something, and it sent the message before I finished. Here is an example session. Pry is a repl (like irb) but it knows how to do lots of really useful things. One of these is reflecting upon code. In this case, I tell it to show me the documentation for String#split, then I tell it to show me the code for String#split For more cool things you can do with it, check out http://rdoc.info/github/banister/pry/master/file/README.markdown $ pry -f pry(main)> show-doc String#split From: string.c in Ruby Core (C Method): Number of lines: 36 Divides str into substrings based on a delimiter, returning an array of these substrings. If pattern is a String, then its contents are used as the delimiter when splitting str. If pattern is a single space, str is split on whitespace, with leading whitespace and runs of contiguous whitespace characters ignored. If pattern is a Regexp, str is divided where the pattern matches. Whenever the pattern matches a zero-length string, str is split into individual characters. If pattern contains groups, the respective matches will be returned in the array as well. If pattern is omitted, the value of $; is used. If $; is nil (which is the default), str is split on whitespace as if ` ' were specified. If the limit parameter is omitted, trailing null fields are suppressed. If limit is a positive number, at most that number of fields will be returned (if limit is 1, the entire string is returned as the only entry in an array). If negative, there is no limit to the number of fields returned, and trailing null fields are not suppressed. " now's the time".split #=> ["now's", "the", "time"] " now's the time".split(' ') #=> ["now's", "the", "time"] " now's the time".split(/ /) #=> ["", "now's", "", "the", "time"] "1, 2.34,56, 7".split(%r{,\s*}) #=> ["1", "2.34", "56", "7"] "hello".split(//) #=> ["h", "e", "l", "l", "o"] "hello".split(//, 3) #=> ["h", "e", "llo"] "hi mom".split(%r{\s*}) #=> ["h", "i", "m", "o", "m"] "mellow yellow".split("ello") #=> ["m", "w y", "w"] "1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"] "1,2,,3,4,,".split(',', 4) #=> ["1", "2", "", "3,4,,"] "1,2,,3,4,,".split(',', -4) #=> ["1", "2", "", "3", "4", "", ""] pry(main)> show-method -l -f String#split From: string.c in Ruby Core (C Method): Number of lines: 214 1: static VALUE 2: rb_str_split_m(int argc, VALUE *argv, VALUE str) 3: { 4: rb_encoding *enc; 5: VALUE spat; 6: VALUE limit; 7: enum {awk, string, regexp} split_type; 8: long beg, end, i = 0; 9: int lim = 0; 10: VALUE result, tmp; 11: 12: if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) { 13: lim = NUM2INT(limit); 14: if (lim <= 0) limit = Qnil; 15: else if (lim == 1) { 16: if (RSTRING_LEN(str) == 0) 17: return rb_ary_new2(0); 18: return rb_ary_new3(1, str); 19: } 20: i = 1; 21: } 22: 23: enc = STR_ENC_GET(str); 24: if (NIL_P(spat)) { 25: if (!NIL_P(rb_fs)) { 26: spat = rb_fs; 27: goto fs_set; 28: } 29: split_type = awk; 30: } 31: else { 32: fs_set: 33: if (TYPE(spat) == T_STRING) { 34: rb_encoding *enc2 = STR_ENC_GET(spat); 35: 36: split_type = string; 37: if (RSTRING_LEN(spat) == 0) { 38: /* Special case - split into chars */ 39: spat = rb_reg_regcomp(spat); 40: split_type = regexp; 41: } 42: else if (rb_enc_asciicompat(enc2) == 1) { 43: if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' '){ 44: split_type = awk; 45: } 46: } 47: else { 48: int l; 49: if (rb_enc_ascget(RSTRING_PTR(spat), RSTRING_END(spat), &l, enc2) == ' ' && 50: RSTRING_LEN(spat) == l) { 51: split_type = awk; 52: } 53: } 54: } 55: else { 56: spat = get_pat(spat, 1); 57: split_type = regexp; 58: } 59: } 60: 61: result = rb_ary_new(); 62: beg = 0; 63: if (split_type == awk) { 64: char *ptr = RSTRING_PTR(str); 65: char *eptr = RSTRING_END(str); 66: char *bptr = ptr; 67: int skip = 1; 68: unsigned int c; 69: 70: end = beg; 71: if (is_ascii_string(str)) { 72: while (ptr < eptr) { 73: c = (unsigned char)*ptr++; 74: if (skip) { 75: if (ascii_isspace(c)) { 76: beg = ptr - bptr; 77: } 78: else { 79: end = ptr - bptr; 80: skip = 0; 81: if (!NIL_P(limit) && lim <= i) break; 82: } 83: } 84: else if (ascii_isspace(c)) { 85: rb_ary_push(result, rb_str_subseq(str, beg, end-beg)); 86: skip = 1; 87: beg = ptr - bptr; 88: if (!NIL_P(limit)) ++i; 89: } 90: else { 91: end = ptr - bptr; 92: } 93: } 94: } 95: else { 96: while (ptr < eptr) { 97: int n; 98: 99: c = rb_enc_codepoint_len(ptr, eptr, &n, enc); 100: ptr += n; 101: if (skip) { 102: if (rb_isspace(c)) { 103: beg = ptr - bptr; 104: } 105: else { 106: end = ptr - bptr; 107: skip = 0; 108: if (!NIL_P(limit) && lim <= i) break; 109: } 110: } 111: else if (rb_isspace(c)) { 112: rb_ary_push(result, rb_str_subseq(str, beg, end-beg)); 113: skip = 1; 114: beg = ptr - bptr; 115: if (!NIL_P(limit)) ++i; 116: } 117: else { 118: end = ptr - bptr; 119: } 120: } 121: } 122: } 123: else if (split_type == string) { 124: char *ptr = RSTRING_PTR(str); 125: char *temp = ptr; 126: char *eptr = RSTRING_END(str); 127: char *sptr = RSTRING_PTR(spat); 128: long slen = RSTRING_LEN(spat); 129: 130: if (is_broken_string(str)) { 131: rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(str))); 132: } 133: if (is_broken_string(spat)) { 134: rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(STR_ENC_GET(spat))); 135: } 136: enc = rb_enc_check(str, spat); 137: while (ptr < eptr && 138: (end = rb_memsearch(sptr, slen, ptr, eptr - ptr, enc)) >= 0) { 139: /* Check we are at the start of a char */ 140: char *t = rb_enc_right_char_head(ptr, ptr + end, eptr, enc); 141: if (t != ptr + end) { 142: ptr = t; 143: continue; 144: } 145: rb_ary_push(result, rb_str_subseq(str, ptr - temp, end)); 146: ptr += end + slen; 147: if (!NIL_P(limit) && lim <= ++i) break; 148: } 149: beg = ptr - temp; 150: } 151: else { 152: char *ptr = RSTRING_PTR(str); 153: long len = RSTRING_LEN(str); 154: long start = beg; 155: long idx; 156: int last_null = 0; 157: struct re_registers *regs; 158: 159: while ((end = rb_reg_search(spat, str, start, 0)) >= 0) { 160: regs = RMATCH_REGS(rb_backref_get()); 161: if (start == end && BEG(0) == END(0)) { 162: if (!ptr) { 163: rb_ary_push(result, str_new_empty(str)); 164: break; 165: } 166: else if (last_null == 1) { 167: rb_ary_push(result, rb_str_subseq(str, beg, 168: rb_enc_fast_mbclen(ptr+beg, 169: ptr+len, 170: enc))); 171: beg = start; 172: } 173: else { 174: if (ptr+start == ptr+len) 175: start++; 176: else 177: start += rb_enc_fast_mbclen(ptr+start,ptr+len,enc); 178: last_null = 1; 179: continue; 180: } 181: } 182: else { 183: rb_ary_push(result, rb_str_subseq(str, beg, end-beg)); 184: beg = start = END(0); 185: } 186: last_null = 0; 187: 188: for (idx=1; idx < regs->num_regs; idx++) { 189: if (BEG(idx) == -1) continue; 190: if (BEG(idx) == END(idx)) 191: tmp = str_new_empty(str); 192: else 193: tmp = rb_str_subseq(str, BEG(idx), END(idx)-BEG(idx)); 194: rb_ary_push(result, tmp); 195: } 196: if (!NIL_P(limit) && lim <= ++i) break; 197: } 198: } 199: if (RSTRING_LEN(str) > 0 && (!NIL_P(limit) || RSTRING_LEN(str) > beg || lim < 0)) { 200: if (RSTRING_LEN(str) == beg) 201: tmp = str_new_empty(str); 202: else 203: tmp = rb_str_subseq(str, beg, RSTRING_LEN(str)-beg); 204: rb_ary_push(result, tmp); 205: } 206: if (NIL_P(limit) && lim == 0) { 207: long len; 208: while ((len = RARRAY_LEN(result)) > 0 && 209: (tmp = RARRAY_PTR(result)[len-1], RSTRING_LEN(tmp) == 0)) 210: rb_ary_pop(result); 211: } 212: 213: return result; 214: } pry(main)> exit --20cf3071cfae466a6204a23b8ef6--