summaryrefslogtreecommitdiff
path: root/class.c
diff options
context:
space:
mode:
authorknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-09-10 07:51:58 +0000
committerknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-09-10 07:51:58 +0000
commit82abe79b9fa3b5a648f453076a28ed9566d02ec8 (patch)
tree38c67940337c200adc83b83669049492fb4a3534 /class.c
parent4f77c495cddcdfcbb15e363ba21d09e5a9ddfd37 (diff)
* class.c (rb_scan_args): Add support for optional keyword
argument hash. * README.EXT, README.EXT.ja: Update documentation accordingly. * dir.c (dir_initialize): Make use of the new rb_scan_args() feature. * io.c (rb_io_s_popen, rb_scan_open_args, rb_io_initialize) (rb_io_s_pipe, open_key_args, io_s_foreach, io_s_readlines) (rb_io_s_read, rb_io_set_encoding): Ditto. * transcode.c (str_transcode, econv_args) (econv_primitive_convert): Ditto. * ext/zlib/zlib.c (rb_gzreader_initialize): Ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29214 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'class.c')
-rw-r--r--class.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/class.c b/class.c
index 9ad8ec8539..1d4695bc6c 100644
--- a/class.c
+++ b/class.c
@@ -1376,9 +1376,10 @@ rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
const char *p = fmt;
VALUE *var;
va_list vargs;
- int f_var = 0, f_block = 0;
+ int f_var = 0, f_hash = 0, f_block = 0;
int n_lead = 0, n_opt = 0, n_trail = 0, n_mand;
int argi = 0;
+ VALUE hash = Qnil;
if (ISDIGIT(*p)) {
n_lead = *p - '0';
@@ -1402,6 +1403,10 @@ rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
}
}
block_arg:
+ if (*p == ':') {
+ f_hash = 1;
+ p++;
+ }
if (*p == '&') {
f_block = 1;
p++;
@@ -1416,6 +1421,23 @@ rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
va_start(vargs, fmt);
+ /* capture an option hash - phase 1: pop */
+ if (f_hash && n_mand < argc) {
+ VALUE last = argv[argc - 1];
+
+ if (NIL_P(last)) {
+ /* nil is taken as an empty option hash only if it is not
+ ambiguous; i.e. '*' is not specified and arguments are
+ given more than sufficient */
+ if (!f_var && n_mand + n_opt < argc)
+ argc--;
+ }
+ else {
+ hash = rb_check_convert_type(last, T_HASH, "Hash", "to_hash");
+ if (!NIL_P(hash))
+ argc--;
+ }
+ }
/* capture leading mandatory arguments */
for (i = n_lead; i-- > 0; ) {
var = va_arg(vargs, VALUE *);
@@ -1452,6 +1474,11 @@ rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
if (var) *var = argv[argi];
argi++;
}
+ /* capture an option hash - phase 2: assignment */
+ if (f_hash) {
+ var = va_arg(vargs, VALUE *);
+ if (var) *var = hash;
+ }
/* capture iterator block */
if (f_block) {
var = va_arg(vargs, VALUE *);