From: Nobuyoshi Nakada Date: 2008-07-06T16:17:50+09:00 Subject: [ruby-dev:35379] [Feature:1.9] rb_scan_args() for keyword arguments なかだです。 rb_scan_args()でキーワード引数に対応するパッチを発掘しました。 rb_scan_args(argc, argv, "11:foo", &mandatory, &optional, &foo) とか rb_scan_args(argc, argv, "11::", &mandatory, &optional, rb_intern("foo"), &foo, (ID)0) とか書けるようになるはずだったと思います。 Index: class.c =================================================================== --- class.c (revision 17903) +++ class.c (working copy) @@ -871,4 +871,5 @@ rb_scan_args(int argc, const VALUE *argv const char *p = fmt; VALUE *var; + VALUE opt = 0; va_list vargs; @@ -876,4 +877,13 @@ rb_scan_args(int argc, const VALUE *argv if (*p == '*') goto rest_arg; + if (strchr(fmt, ':')) { + if (argc > 0 && TYPE(opt = argv[argc-1]) == T_HASH) { + --argc; + } + else { + opt = 0; + } + if (*p == ':') goto keyword; + } if (ISDIGIT(*p)) { @@ -895,9 +905,6 @@ rb_scan_args(int argc, const VALUE *argv for (; i i) { - if (var) *var = argv[i]; - } - else { - if (var) *var = Qnil; + if (var) { + *var = argc > i ? argv[i] : Qnil; } } @@ -905,5 +912,32 @@ rb_scan_args(int argc, const VALUE *argv } - if(*p == '*') { + keyword: + if (*p == ':') { + if (p[1] == ':') { + ID name; + while ((name = va_arg(vargs, ID)) != 0) { + var = va_arg(vargs, VALUE*); + if (var) { + *var = opt ? rb_hash_lookup(opt, name) : Qnil; + } + } + } + else { + do { + const char *beg = ++p; + if (*p != '_' && !ISALPHA(*p)) goto error; + while (*p == '_' || ISALNUM(*p)) p++; + if (*p && !strchr(":*&", *p)) goto error; + var = va_arg(vargs, VALUE*); + if (var) { + *var = opt ? + rb_hash_lookup(opt, rb_intern2(beg, p - beg)) : + Qnil; + } + } while (*p == ':'); + } + } + + if (*p == '*') { rest_arg: var = va_arg(vargs, VALUE*); -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦