Feature #442

name referencing in sprintf

Added by mame (Yusuke Endoh) almost 4 years ago. Updated about 1 year ago.

[ruby-dev:35851]
Status:Closed Start date:
Priority:Low Due date:
Assignee:matz (Yukihiro Matsumoto) % Done:

100%

Category:-
Target version:1.9.1 Release Candidate

Description

遠藤です。

1.9 では正規表現で名前を使った参照ができるので、sprintf でも
名前を使った参照ができると便利じゃないでしょうか。


$ ./ruby -e 'puts "%<foo>d : %<bar>f" % { :foo => 1, :bar => 2 }'
1 : 2.000000

$ ./ruby -e 'printf("%<foo>d : %<bar>f\n", :foo => 1, :bar => 2)'
1 : 2.000000


あまりテストしていませんが、たたき台の実装です。


Index: sprintf.c
===================================================================
--- sprintf.c	(revision 18638)
+++ sprintf.c	(working copy)
@@ -103,18 +103,28 @@
 } while (0)

 #define GETARG() (nextvalue != Qundef ? nextvalue : \
-    posarg < 0 ? \
+    posarg == -1 ? \
     (rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered",
nextarg), 0) : \
+    posarg == -2 ? \
+    (rb_raise(rb_eArgError, "unnumbered(%d) mixed with named", nextarg), 0) : \
     (posarg = nextarg++, GETNTHARG(posarg)))

 #define GETPOSARG(n) (posarg > 0 ? \
     (rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n,
posarg), 0) : \
+    posarg == -2 ? \
+    (rb_raise(rb_eArgError, "numbered(%d) after named", n), 0) : \
     ((n < 1) ? (rb_raise(rb_eArgError, "invalid index - %d$", n), 0) : \
 	       (posarg = -1, GETNTHARG(n))))

 #define GETNTHARG(nth) \
     ((nth >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0)
: argv[nth])

+#define GETNAMEARG(id) (posarg > 0 ? \
+    (rb_raise(rb_eArgError, "named after unnumbered(%d)", posarg), 0) : \
+    posarg == -1 ? \
+    (rb_raise(rb_eArgError, "named after numbered"), 0) : \
+    rb_hash_aref(get_hash(&hash, argc, argv), id))
+
 #define GETNUM(n, val) \
     for (; p < end && rb_enc_isdigit(*p, enc); p++) {	\
 	int next_n = 10 * n + (*p - '0'); \
@@ -141,7 +151,22 @@
     val = NUM2INT(tmp); \
 } while (0)

+static VALUE
+get_hash(volatile VALUE *hash, int argc, const VALUE *argv)
+{
+    VALUE tmp;

+    if (*hash != Qundef) return *hash;
+    if (argc != 2) {
+	rb_raise(rb_eArgError, "one hash required");
+    }
+    tmp = rb_check_convert_type(argv[1], T_HASH, "Hash", "to_hash");
+    if (NIL_P(tmp)) {
+	rb_raise(rb_eArgError, "one hash required");
+    }
+    return (*hash = tmp);
+}
+
 /*
  *  call-seq:
  *     format(format_string [, arguments...] )   => string
@@ -412,6 +437,7 @@
     VALUE nextvalue;
     VALUE tmp;
     VALUE str;
+    volatile VALUE hash = Qundef;

 #define CHECK_FOR_WIDTH(f)				 \
     if ((f) & FWIDTH) {					 \
@@ -513,6 +539,22 @@
 	    flags |= FWIDTH;
 	    goto retry;

+	  case '<':
+	    {
+		const char *start = p;
+		ID id;
+		for (; p < end && *p != '>'; ) {
+		    p += rb_enc_mbclen(p, end, enc);
+		}
+		if (p >= end) {
+		    rb_raise(rb_eArgError, "malformed name - unmatched parenthesis");
+		}
+		id = rb_intern3(start + 1, p - start - 1, enc);
+		nextvalue = GETNAMEARG(ID2SYM(id));
+		p++;
+		goto retry;
+	    }
+
 	  case '*':
 	    CHECK_FOR_WIDTH(flags);
 	    flags |= FWIDTH;

-- 
Yusuke ENDOH <mame@tsg.ne.jp>

Related issues

related to ruby-trunk - Bug #3574: Missing documentation for sprintf named argument support Closed 07/15/2010

Associated revisions

Revision 19641
Added by matz (Yukihiro Matsumoto) over 3 years ago

* sprintf.c (rb_str_format): add %<name>s style named argument support. a patch from Yusuke Endoh <mame at tsg.ne.jp> in [ruby-dev:35851]. * sprintf.c (rb_str_format): add gettext style named format (%{name}) support. inspired by [ruby-dev:35852]. * sprintf.c (GETNAMEARG): should raise KeyError exception when no named argument found. * hash.c (rb_hash_fetch): export fetch function.

History

Updated by Tietew (Toru Iwase) almost 4 years ago

On Fri, 15 Aug 2008 13:08:12 +0900
In article <e0b1e5700808142111y1831avac797602ee30279a@mail.gmail.com>
[[ruby-dev:35851] [Feature:1.9] name referencing in sprintf]
"Yusuke ENDOH" <mame@tsg.ne.jp> wrote:

> 1.9 では正規表現で名前を使った参照ができるので、sprintf でも
> 名前を使った参照ができると便利じゃないでしょうか。
> 
> $ ./ruby -e 'puts "%<foo>d : %<bar>f" % { :foo => 1, :bar => 2 }'

Ruby-GetText で %{foo} というのを使っているので、合わせてあると嬉しい人
が多いかと。書式指定はできないのですが。

# {} は書式指定無し版、<> は有り版 にするとか?



-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by nobu (Nobuyoshi Nakada) almost 4 years ago

なかだです。

At Fri, 15 Aug 2008 14:20:15 +0900,
Tietew wrote in [ruby-dev:35852]:
> On Fri, 15 Aug 2008 13:08:12 +0900
> In article <e0b1e5700808142111y1831avac797602ee30279a@mail.gmail.com>
> [[ruby-dev:35851] [Feature:1.9] name referencing in sprintf]
> "Yusuke ENDOH" <mame@tsg.ne.jp> wrote:
> 
> > 1.9 では正規表現で名前を使った参照ができるので、sprintf でも
> > 名前を使った参照ができると便利じゃないでしょうか。
> > 
> > $ ./ruby -e 'puts "%<foo>d : %<bar>f" % { :foo => 1, :bar => 2 }'

[ruby-dev:16351]ではPythonと同じく %(foo)d としていました。

> Ruby-GetText で %{foo} というのを使っているので、合わせてあると嬉しい人
> が多いかと。書式指定はできないのですが。
> 
> # {} は書式指定無し版、<> は有り版 にするとか?

Ruby-GetTextの実装を確認していないのですが、%{}以外のものがあっ
ても大丈夫なのでしょうか。

-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

Updated by Tietew (Toru Iwase) almost 4 years ago

On Fri, 15 Aug 2008 16:28:56 +0900
In article <20080815073149.4930AE0AFF@mail.bc9.jp>
[[ruby-dev:35853] Re: [Feature:1.9] name referencing in sprintf]
Nobuyoshi Nakada <nobu@ruby-lang.org> wrote:

> > Ruby-GetText で %{foo} というのを使っているので、合わせてあると嬉しい人
> > が多いかと。書式指定はできないのですが。
> > 
> > # {} は書式指定無し版、<> は有り版 にするとか?
> 
> Ruby-GetTextの実装を確認していないのですが、%{}以外のものがあっ
> ても大丈夫なのでしょうか。

Ruby-GetText は String#% だけを書き換えていて、右辺が Hash だったら %{...} 
を置換し、さもなければ元のものを呼んでいます。

こういうふうになります:
  "%d %{foo}" % { :foo => 'bar' }    # => "%d bar"
  "%d %{foo}" % 123                  # => "123 %{foo}"


-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by znz (Kazuhiro NISHIYAMA) almost 4 years ago

西山和広です。

At Fri, 15 Aug 2008 13:08:12 +0900,
Yusuke ENDOH wrote:
> 
> 1.9 では正規表現で名前を使った参照ができるので、sprintf でも
> 名前を使った参照ができると便利じゃないでしょうか。
> 
> 
> $ ./ruby -e 'puts "%<foo>d : %<bar>f" % { :foo => 1, :bar => 2 }'
> 1 : 2.000000
> 
> $ ./ruby -e 'printf("%<foo>d : %<bar>f\n", :foo => 1, :bar => 2)'
> 1 : 2.000000
> 
> 
> あまりテストしていませんが、たたき台の実装です。

正規表現の例を出すのなら、Hash限定ではなく[]メソッドを呼んだ方が
便利なのではないでしょうか。


-- 
|ZnZ(ゼット エヌ ゼット)
|西山和広(Kazuhiro NISHIYAMA)

Updated by ko1 (Koichi Sasada) over 3 years ago

  • Assignee set to matz (Yukihiro Matsumoto)

Updated by yugui (Yuki Sonoda) over 3 years ago

  • Target version set to 1.9.1 Release Candidate

Updated by matz (Yukihiro Matsumoto) over 3 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100
Applied in changeset r19641.

Also available in: Atom PDF