[#42194] Enhancing Numeric#step — "Akinori MUSHA" <knu@...>

 Numeric#step の仕様の拡張を提案します。

26 messages 2010/09/08
[#42196] Re: Enhancing Numeric#step — Yukihiro Matsumoto <matz@...> 2010/09/08

まつもと ゆきひろです

[#42200] Re: Enhancing Numeric#step — "Akinori MUSHA" <knu@...> 2010/09/08

At Wed, 8 Sep 2010 22:46:57 +0900,

[#42204] Re: Enhancing Numeric#step — Yukihiro Matsumoto <matz@...> 2010/09/09

まつもと ゆきひろです

[#42232] 1.9.2 readline can't handle cursorkeys, mbcs chars etc (msvcrt) — arton <artonx@...>

artonです。

11 messages 2010/09/10

[#42269] [Ruby 1.9-Bug#3836] Kernel.system, spawnがスペースを含むパスで動作しない — Hiroki Najima <redmine@...>

チケット #3836 が更新されました。 (by Hiroki Najima)

12 messages 2010/09/16
[#42270] WindowsでのKernel.systemの挙動、一貫性について — NAJIMA Hiroki <h.najima@...> 2010/09/16

名島(Nazy)と申します。

[#42310] ビジースレッドがあるとコンテキストスイッチが起きづらくなる — kuwamoto shintaro <beuniv@...>

こんにちは。

9 messages 2010/09/29
[#42315] [bug:trunk] ビジースレッドがあるとコンテキストスイッチが起きづらくなる — "U.Nakamura" <usa@...> 2010/09/30

こんにちは、なかむら(う)です。

[ruby-dev:42221] Re: Enhancing Numeric#step

From: "Akinori MUSHA" <knu@...>
Date: 2010-09-10 01:24:12 UTC
List: ruby-dev #42221
At Thu, 9 Sep 2010 11:04:19 +0900,
I wrote:
> At Thu, 9 Sep 2010 09:59:45 +0900,
> matz wrote:
> > たとえば、
> >
> >   rb_scan_args(argc, argv, "02:", &limit, &step, &kw);
>
>  若干記法は違いますが、前に提案しました。 [ruby-dev:38048]
>
> > でキーワード辞書を取れたり、

 パッチを添付します。':'を末尾('&'を置く場合はその直前)に置く
形に改めました。いかがでしょうか。

--
Akinori MUSHA / http://akinori.org/

diff --git a/README.EXT b/README.EXT
index ac0d7cc..c2b2d9d 100644
--- a/README.EXT
+++ b/README.EXT
@@ -1105,12 +1105,13 @@ according to the format string.  The format can be described in ABNF
 as follows:

 --
-scan-arg-spec  := param-arg-spec [block-arg-spec]
+scan-arg-spec  := param-arg-spec [option-hash-arg-spec] [block-arg-spec]

 param-arg-spec := pre-arg-spec [post-arg-spec] / post-arg-spec / pre-opt-post-arg-spec
 pre-arg-spec   := num-of-leading-mandatory-args [num-of-optional-args]
 post-arg-spec  := sym-for-variable-length-args [num-of-trailing-mandatory-args]
 pre-opt-post-arg-spec := num-of-leading-mandatory-args num-of-optional-args num-of-trailing-mandatory-args
+option-hash-arg-spec := sym-for-option-hash-arg
 block-arg-spec := sym-for-block-arg

 num-of-leading-mandatory-args  := DIGIT ; The number of leading
@@ -1122,6 +1123,18 @@ sym-for-variable-length-args   := "*"   ; Indicates that variable
                                         ; captured as a ruby array
 num-of-trailing-mandatory-args := DIGIT ; The number of trailing
                                         ; mandatory arguments
+sym-for-option-hash-arg        := ":"   ; Indicates that an option
+                                        ; hash is captured if the last
+                                        ; argument is a hash or can be
+                                        ; converted to a hash with
+                                        ; #to_hash.  When the last
+                                        ; argument is nil, it is
+                                        ; captured if it is not
+                                        ; ambiguous to take it as
+                                        ; empty option hash; i.e. '*'
+                                        ; is not specified and
+                                        ; arguments are given more
+                                        ; than sufficient.
 sym-for-block-arg              := "&"   ; Indicates that an iterator
                                         ; block should be captured if
                                         ; given
@@ -1134,8 +1147,8 @@ assigned to captured arguments.  For omitted arguments, variables are
 set to Qnil.  NULL can be put in place of a variable reference, which
 means the corresponding captured argument(s) should be just dropped.

-The number of given arguments, excluding an iterator block, is
-returned.
+The number of given arguments, excluding an option hash or iterator
+block, is returned.

 ** Invoking Ruby method

diff --git a/README.EXT.ja b/README.EXT.ja
index 95c4ee2..54ab449 100644
--- a/README.EXT.ja
+++ b/README.EXT.ja
@@ -1198,12 +1198,13 @@ rb_scan_args(int argc, VALUE *argv, const char *fmt, ...)
   トは,ABNFで記述すると以下の通りです.

 --
-scan-arg-spec  := param-arg-spec [block-arg-spec]
+scan-arg-spec  := param-arg-spec [option-hash-arg-spec] [block-arg-spec]

 param-arg-spec := pre-arg-spec [post-arg-spec] / post-arg-spec / pre-opt-post-arg-spec
 pre-arg-spec   := num-of-leading-mandatory-args [num-of-optional-args]
 post-arg-spec  := sym-for-variable-length-args [num-of-trailing-mandatory-args]
 pre-opt-post-arg-spec := num-of-leading-mandatory-args num-of-optional-args num-of-trailing-mandatory-args
+option-hash-arg-spec := sym-for-option-hash-arg
 block-arg-spec := sym-for-block-arg

 num-of-leading-mandatory-args  := DIGIT ; 先頭に置かれる省略不能な引数の数
@@ -1211,6 +1212,15 @@ num-of-optional-args           := DIGIT ; 続
 sym-for-variable-length-args   := "*"   ; 続いて置かれる可変長引数を
                                         ; Rubyの配列で取得するための指定
 num-of-trailing-mandatory-args := DIGIT ; 終端に置かれる省略不能な引数の数
+sym-for-option-hash-arg        := ":"   ; オプションハッシュを取得する
+                                        ; ための指定; 省略不能な引数の
+                                        ; 数よりも多くの引数が指定され,
+                                        ; 最後の引数がハッシュ(または
+                                        ; #to_hashで変換可能)の場合に
+                                        ; 取得される.最後の引数がnilの
+                                        ; 場合,可変長引数指定がなく,
+                                        ; 省略不能引数の数よりも多くの
+                                        ; 引数が指定された場合に取得される
 sym-for-block-arg              := "&"   ; イテレータブロックを取得するための
                                         ; 指定
 --
@@ -1223,8 +1233,8 @@ sym-for-block-arg              := "&"   ;
   省略可能引数が省略された時の変数の値はnil(C言語のレベルでは
   Qnil)になります.

-  返り値は与えられた引数の数です.イテレータブロックは数えま
-  せん.
+  返り値は与えられた引数の数です.オプションハッシュおよびイ
+  テレータブロックは数えません.

 ** Rubyメソッド呼び出し

diff --git a/class.c b/class.c
index 9ad8ec8..1d4695b 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 *);
diff --git a/dir.c b/dir.c
index 483c8be..f9867e4 100644
--- a/dir.c
+++ b/dir.c
@@ -390,11 +390,10 @@ dir_initialize(int argc, VALUE *argv, VALUE dir)
     }
     fsenc = rb_filesystem_encoding();

-    rb_scan_args(argc, argv, "11", &dirname, &opt);
+    argc = rb_scan_args(argc, argv, "1:", &dirname, &opt);

     if (!NIL_P(opt)) {
         VALUE v, enc=Qnil;
-        opt = rb_convert_type(opt, T_HASH, "Hash", "to_hash");

         v = rb_hash_aref(opt, sym_enc);
         if (!NIL_P(v)) enc = v;
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 20218a9..970b857 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -3067,11 +3067,7 @@ rb_gzreader_initialize(int argc, VALUE *argv, VALUE obj)
     int err;

     Data_Get_Struct(obj, struct gzfile, gz);
-    if (argc > 1) {
-	opt = rb_check_convert_type(argv[argc-1], T_HASH, "Hash", "to_hash");
-	if (!NIL_P(opt)) argc--;
-    }
-    rb_scan_args(argc, argv, "1", &io);
+    rb_scan_args(argc, argv, "1:", &io, &opt);

     /* this is undocumented feature of zlib */
     err = inflateInit2(&gz->z.stream, -MAX_WBITS);
diff --git a/io.c b/io.c
index 169158b..7a4be8a 100644
--- a/io.c
+++ b/io.c
@@ -5238,21 +5238,6 @@ pipe_open_s(VALUE prog, const char *modestr, int fmode, convconfig_t *convconfig
     return pipe_open(&earg, prog, modestr, fmode, convconfig);
 }

-static VALUE
-pop_last_hash(int *argc_p, VALUE *argv)
-{
-    VALUE last, tmp;
-    if (*argc_p == 0)
-        return Qnil;
-    last = argv[*argc_p-1];
-    if (NIL_P(last)) return Qnil;
-    tmp = rb_check_convert_type(last, T_HASH, "Hash", "to_hash");
-    if (NIL_P(tmp))
-        return Qnil;
-    (*argc_p)--;
-    return tmp;
-}
-
 /*
  *  call-seq:
  *     IO.popen(cmd, mode="r" [, opt])               -> io
@@ -5344,8 +5329,7 @@ rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
     int oflags, fmode;
     convconfig_t convconfig;

-    opt = pop_last_hash(&argc, argv);
-    rb_scan_args(argc, argv, "11", &pname, &pmode);
+    argc = rb_scan_args(argc, argv, "11:", &pname, &pmode, &opt);

     rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
     modestr = rb_io_oflags_modestr(oflags);
@@ -5389,12 +5373,11 @@ rb_scan_open_args(int argc, VALUE *argv,
         VALUE *fname_p, int *oflags_p, int *fmode_p,
         convconfig_t *convconfig_p, mode_t *perm_p)
 {
-    VALUE opt=Qnil, fname, vmode, vperm;
+    VALUE opt, fname, vmode, vperm;
     int oflags, fmode;
     mode_t perm;

-    opt = pop_last_hash(&argc, argv);
-    rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
+    argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
     FilePathValue(fname);

     rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
@@ -6462,8 +6445,7 @@ rb_io_initialize(int argc, VALUE *argv, VALUE io)

     rb_secure(4);

-    opt = pop_last_hash(&argc, argv);
-    rb_scan_args(argc, argv, "11", &fnum, &vmode);
+    argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
     rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);

     fd = NUM2INT(fnum);
@@ -7776,8 +7758,7 @@ rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
     int fmode = 0;
     VALUE ret;

-    opt = pop_last_hash(&argc, argv);
-    rb_scan_args(argc, argv, "02", &v1, &v2);
+    argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
     if (rb_pipe(pipes) == -1)
         rb_sys_fail(0);

@@ -7824,22 +7805,20 @@ struct foreach_arg {
 };

 static void
-open_key_args(int argc, VALUE *argv, struct foreach_arg *arg)
+open_key_args(int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
 {
-    VALUE opt, v;
+    VALUE path, v;

-    FilePathValue(argv[0]);
+    path = *argv++;
+    argc--;
+    FilePathValue(path);
     arg->io = 0;
-    arg->argc = argc - 1;
-    arg->argv = argv + 1;
-    if (argc == 1) {
-      no_key:
-	arg->io = rb_io_open(argv[0], INT2NUM(O_RDONLY), INT2FIX(0666), Qnil);
+    arg->argc = argc;
+    arg->argv = argv;
+    if (NIL_P(opt)) {
+	arg->io = rb_io_open(path, INT2NUM(O_RDONLY), INT2FIX(0666), Qnil);
 	return;
     }
-    opt = pop_last_hash(&arg->argc, arg->argv);
-    if (NIL_P(opt)) goto no_key;
-
     v = rb_hash_aref(opt, sym_open_args);
     if (!NIL_P(v)) {
 	VALUE args;
@@ -7853,13 +7832,13 @@ open_key_args(int argc, VALUE *argv, struct foreach_arg *arg)
 	}
 #endif
 	args = rb_ary_tmp_new(n);
-	rb_ary_push(args, argv[0]);
+	rb_ary_push(args, path);
 	rb_ary_concat(args, v);
 	arg->io = rb_io_open_with_args((int)n, RARRAY_PTR(args));
 	rb_ary_clear(args);	/* prevent from GC */
 	return;
     }
-    arg->io = rb_io_open(argv[0], Qnil, Qnil, opt);
+    arg->io = rb_io_open(path, Qnil, Qnil, opt);
 }

 static VALUE
@@ -7902,11 +7881,12 @@ io_s_foreach(struct foreach_arg *arg)
 static VALUE
 rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
 {
+    VALUE opt;
     struct foreach_arg arg;

-    rb_scan_args(argc, argv, "13", NULL, NULL, NULL, NULL);
+    argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
     RETURN_ENUMERATOR(self, argc, argv);
-    open_key_args(argc, argv, &arg);
+    open_key_args(argc, argv, opt, &arg);
     if (NIL_P(arg.io)) return Qnil;
     return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
 }
@@ -7938,10 +7918,11 @@ io_s_readlines(struct foreach_arg *arg)
 static VALUE
 rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
 {
+    VALUE opt;
     struct foreach_arg arg;

-    rb_scan_args(argc, argv, "13", NULL, NULL, NULL, NULL);
-    open_key_args(argc, argv, &arg);
+    argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
+    open_key_args(argc, argv, opt, &arg);
     if (NIL_P(arg.io)) return Qnil;
     return rb_ensure(io_s_readlines, (VALUE)&arg, rb_io_close, arg.io);
 }
@@ -8001,11 +7982,11 @@ seek_before_access(VALUE argp)
 static VALUE
 rb_io_s_read(int argc, VALUE *argv, VALUE io)
 {
-    VALUE offset;
+    VALUE opt, offset;
     struct foreach_arg arg;

-    rb_scan_args(argc, argv, "13", NULL, NULL, &offset, NULL);
-    open_key_args(argc, argv, &arg);
+    argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
+    open_key_args(argc, argv, opt, &arg);
     if (NIL_P(arg.io)) return Qnil;
     if (!NIL_P(offset)) {
 	struct seek_arg sarg;
@@ -8684,8 +8665,7 @@ rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
     rb_io_t *fptr;
     VALUE v1, v2, opt;

-    opt = pop_last_hash(&argc, argv);
-    rb_scan_args(argc, argv, "11", &v1, &v2);
+    argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
     GetOpenFile(io, fptr);
     io_encoding_set(fptr, v1, v2, opt);
     return io;
diff --git a/transcode.c b/transcode.c
index c718182..17bad37 100644
--- a/transcode.c
+++ b/transcode.c
@@ -2666,12 +2666,9 @@ str_transcode(int argc, VALUE *argv, VALUE *self)
     int ecflags = 0;
     VALUE ecopts = Qnil;

-    if (0 < argc) {
-        opt = rb_check_convert_type(argv[argc-1], T_HASH, "Hash", "to_hash");
-        if (!NIL_P(opt)) {
-            argc--;
-            ecflags = rb_econv_prepare_opts(opt, &ecopts);
-        }
+    argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opt);
+    if (!NIL_P(opt)) {
+	ecflags = rb_econv_prepare_opts(opt, &ecopts);
     }
     return str_transcode0(argc, argv, self, ecflags, ecopts);
 }
@@ -2908,25 +2905,28 @@ econv_args(int argc, VALUE *argv,
     int *ecflags_p,
     VALUE *ecopts_p)
 {
-    VALUE opt, opthash, flags_v, ecopts;
+    VALUE opt, flags_v, ecopts;
     int sidx, didx;
     const char *sname, *dname;
     rb_encoding *senc, *denc;
     int ecflags;

-    rb_scan_args(argc, argv, "21", snamev_p, dnamev_p, &opt);
+    argc = rb_scan_args(argc, argv, "21:", snamev_p, dnamev_p, &flags_v, &opt);

-    if (NIL_P(opt)) {
-        ecflags = 0;
+    if (!NIL_P(flags_v)) {
+	if (!NIL_P(opt)) {
+	    rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..3)",
+		argc + 1);
+	}
+        ecflags = NUM2INT(rb_to_int(flags_v));
         ecopts = Qnil;
     }
-    else if (!NIL_P(flags_v = rb_check_to_integer(opt, "to_int"))) {
-        ecflags = NUM2INT(flags_v);
-        ecopts = Qnil;
+    else if (!NIL_P(opt)) {
+        ecflags = rb_econv_prepare_opts(opt, &ecopts);
     }
     else {
-        opthash = rb_convert_type(opt, T_HASH, "Hash", "to_hash");
-        ecflags = rb_econv_prepare_opts(opthash, &ecopts);
+        ecflags = 0;
+        ecopts = Qnil;
     }

     senc = NULL;
@@ -3543,7 +3543,7 @@ econv_primitive_convert(int argc, VALUE *argv, VALUE self)
     unsigned long output_byteend;
     int flags;

-    rb_scan_args(argc, argv, "23", &input, &output, &output_byteoffset_v, &output_bytesize_v, &opt);
+    argc = rb_scan_args(argc, argv, "23:", &input, &output, &output_byteoffset_v, &output_bytesize_v, &flags_v, &opt);

     if (NIL_P(output_byteoffset_v))
         output_byteoffset = 0; /* dummy */
@@ -3555,15 +3555,15 @@ econv_primitive_convert(int argc, VALUE *argv, VALUE self)
     else
         output_bytesize = NUM2LONG(output_bytesize_v);

-    if (NIL_P(opt)) {
-        flags = 0;
-    }
-    else if (!NIL_P(flags_v = rb_check_to_integer(opt, "to_int"))) {
-        flags = NUM2INT(flags_v);
+    if (!NIL_P(flags_v)) {
+	if (!NIL_P(opt)) {
+	    rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..5)",
+		argc + 1);
+	}
+	flags = NUM2INT(rb_to_int(flags_v));
     }
-    else {
+    else if (!NIL_P(opt)) {
         VALUE v;
-        opt = rb_convert_type(opt, T_HASH, "Hash", "to_hash");
         flags = 0;
         v = rb_hash_aref(opt, sym_partial_input);
         if (RTEST(v))
@@ -3572,6 +3572,9 @@ econv_primitive_convert(int argc, VALUE *argv, VALUE self)
         if (RTEST(v))
             flags |= ECONV_AFTER_OUTPUT;
     }
+    else {
+        flags = 0;
+    }

     StringValue(output);
     if (!NIL_P(input))

In This Thread