Skip to content

Commit

Permalink
* class.c (rb_scan_args): Add support for optional keyword
Browse files Browse the repository at this point in the history
  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
  • Loading branch information
knu committed Sep 10, 2010
1 parent 4f77c49 commit 82abe79
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 83 deletions.
19 changes: 19 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
Fri Sep 10 16:49:20 2010 Akinori MUSHA <[email protected]>

* 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.

Fri Sep 10 10:33:18 2010 NARUSE, Yui <[email protected]>

* random.c (rb_genrand_ulong_limited): renamed from
Expand Down
19 changes: 16 additions & 3 deletions README.EXT
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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

Expand Down
16 changes: 13 additions & 3 deletions README.EXT.ja
Original file line number Diff line number Diff line change
Expand Up @@ -1198,19 +1198,29 @@ 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 ; ��Ƭ���֤�����ά��ǽ�ʰ����ο�
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 := "&" ; ���ƥ졼���֥��å���������뤿���
; ����
--
Expand All @@ -1223,8 +1233,8 @@ sym-for-block-arg := "&" ;
��ά��ǽ��������ά���줿�����ѿ����ͤ�nil(C����Υ�٥�Ǥ�
Qnil)�ˤʤ�ޤ���

�֤��ͤ�Ϳ����줿�����ο��Ǥ������ƥ졼���֥��å��Ͽ����
����
�֤��ͤ�Ϳ����줿�����ο��Ǥ������ץ����ϥå��太��ӥ
ƥ졼���֥��å��Ͽ����ޤ���

** Ruby�᥽�åɸƤӽФ�

Expand Down
29 changes: 28 additions & 1 deletion class.c
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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++;
Expand All @@ -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 *);
Expand Down Expand Up @@ -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 *);
Expand Down
3 changes: 1 addition & 2 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 1 addition & 5 deletions ext/zlib/zlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
72 changes: 26 additions & 46 deletions io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 82abe79

Please sign in to comment.