From: Akinori MUSHA Date: 2010-09-29T11:21:09+09:00 Subject: [ruby-dev:42305] Re: Introducing "rb_scan_keyword_args()" (was Re: Re: Enhancing Numeric#step) --pgp-sign-Multipart_Wed_Sep_29_11:21:08_2010-1 Content-Type: text/plain; charset=ISO-2022-JP At Mon, 13 Sep 2010 12:48:37 +0900, I wrote: > At Sun, 12 Sep 2010 19:51:21 +0900, > I wrote: > > At Thu, 9 Sep 2010 09:59:45 +0900, > > matz wrote: > > > でキーワード辞書を取れたり、 > > > > > > rb_scan_keywords(kw, "by", &step, "to", &limit, NULL); > > > > > > で、キーワード辞書を分解したりするようなAPIはどうだろうかと > > > 考えています。 > > > >  少し考えてから、 rb_scan_keyword_args() というものを設計・実装 > > してみました。仕様は以下の差分中に(日本語も)あるので見てみて > > ください。 > > > >  改良点として、 fmt の頭に ':' を置くと、キーワード名として > > const char * でなく ID を取るという機能を付けると、何度も呼び > > 出されることを考慮して効率のために rb_intern() の結果を取って > > おくようなところでも使えるのかなと思っています。 > >  rb_intern() 程度の手間は強いてもいいかなと思ったので、IDを取る > ようにしました。(パッチは省きます)  もうだいぶ経つので後ほど入れようと思います。以下のようなAPIです。 =begin rb_scan_keyword_args(VALUE hash, const char *fmt, ...) Retrieve keyword arguments from hash (Qnil is allowed and treated the same as empty hash) according to the format string and an arbitrary number of pairs of a keyword's ID and a VALUE reference that follow, terminated by a single occurrence of NULL. Another VALUE reference may be put after the NULL, to which unlisted keyword arguments are captured in a hash. The format can be described in ABNF as follows: -- scan-kw-arg-spec := [num-of-mandatory-args] how-to-deal-with-unlisted-spec how-to-deal-with-unlisted-spec := sym-for-capture / sym-for-raise / sym-for-warn num-of-mandatory-args := DIGIT ; The number of mandatory ; keywords sym-for-capture := "*" ; Indicates that all the ; keywords that are not on the ; list should be captured as a ; ruby hash. sym-for-raise := "!" ; Indicates that an ; ArgumentError should be ; raised if any keyword that ; are not on the list is given. sym-for-warning := "" ; Indicates that a soft warning ; should be emitted raised if ; any keyword that are not on ; the list is given. Typical usage of this function is as follows: /* * The keywords and are mandatory, and is optional; * If any other keyword arguments are given, an ArgumentError is raised. */ rb_scan_keyword_args(opt, "2!", rb_intern("x"), &x, rb_intern("y"), &y, rb_intern("color"), &color, NULL); /* * The keywords and are mandatory, and is optional; * If other keyword arguments are given, they are packed into a hash * and assigned to the variable rest. */ rb_scan_keyword_args(opt, "2*", rb_intern("x"), &x, rb_intern("y"), &y, rb_intern("color"), &color, NULL, &rest); /* Unknown parameters can just be dropped by passing a NULL. */ rb_scan_keyword_args(opt, "2*", rb_intern("x"), &x, rb_intern("y"), &y, rb_intern("color"), &color, NULL, NULL); /* * The keywords , , and are all optional; * If any other keyword arguments are given, a soft warning (only * reported in verbose mode) is emitted. */ rb_scan_keyword_args(opt, "0", rb_intern("x"), &x, rb_intern("y"), &y, rb_intern("color"), &color, NULL); For each optional keyword arguments that are not given, the corresponding VALUE reference is set to Qundef unlike rb_scan_args() which sets Qnil. This is because in rb_scan_args() distinction between nil and unspecified can be made by checking argc but in rb_scan_keyword_args() there is no concept of argc where hash is unordered. If you want to settle more than nine mandatory keyword arguments, split up the retrieval into several steps, i.e. retrieve the first nine arguments with "9*", apply "9*" to the captured rest to retrieve the next nine, and so on. =end -- Akinori MUSHA / http://akinori.org/ --pgp-sign-Multipart_Wed_Sep_29_11:21:08_2010-1 Content-Type: application/pgp-signature Content-Transfer-Encoding: 7bit -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (FreeBSD) iEYEABECAAYFAkyiopQACgkQkgvvx5/Z4e4eiQCgp71hy3Pr68FjuZSQRh4sxBRi GbwAn1cZf0I2iUKJ9ff3OJFdVHqkxG9a =2cpF -----END PGP SIGNATURE----- --pgp-sign-Multipart_Wed_Sep_29_11:21:08_2010-1--