Feature #10130

String format with nested hash

Added by sawa (Tsuyoshi Sawada) over 6 years ago. Updated about 5 years ago.

Target version:


When we do string format with hashes, we have the restriction that the hash cannot be a nested one. When we want to handle more complicated string formats, for example in templates, it is more convenient if we can use a nested hash.

"Author: %{} (%{author.affiliation}), %{date}" % {author: {name: "Ruby Taro", affiliation: "Ruby co."}, date: "2014, 8, 14"}
#=> "Author: Ruby Taro (Ruby co.), 2014, 8, 14"

Updated by avit (Andrew Vit) over 6 years ago

I would have expected [] for hash syntax in the string template:

"Author: %{author[:name]} (%{author[:affiliation]}), %{date}"

For it to work with dots seems inconsistent, unless the hash value responds to those methods.

Updated by matz (Yukihiro Matsumoto) over 6 years ago

  • Category set to core
  • Status changed from Open to Rejected
  • Assignee set to matz (Yukihiro Matsumoto)

Rejected, for several reasons:

(1) is not a canonical way to access nested hash.
(2) this feature add more complexity than it gains.
(3) you can just use #{author[:name]} to embed.


Updated by sawa (Tsuyoshi Sawada) about 5 years ago

Now that we have Hash#dig and Array#dig coming for Ruby 2.3, I think that this proposal of mine from the past makes more sense.

Regarding Matz' point (2), this proposal should parallel the feature of dig. It doesn't add extra cognitive load to us beyond what we would be knowing about dig in the coming version of Ruby.

Regarding Matz' point (3), string format (%{}) cannot be replaced by string interpolation (#{}) when we want a static string that is to be used as a template, to which values would be inserted later to output a page. Interpolation requires dynamic evaluation of the string each time.

Regarding Matz' point (1), instead of using the period as the delimiter, we can use a comma (followed by optional space characters), which would resemble how dig is called.

"Author: %{author, name} (%{author, affiliation}), %{date}" % {author: {name: "Ruby Taro", affiliation: "Ruby co."}, date: "2014, 8, 14"}
#=> "Author: Ruby Taro (Ruby co.), 2014, 8, 14"

This requires a key with a comma inside %{} not to be interpreted as a single symbol but as a sequence of symbols separated by the comma (followed by space characters). Since it is rare that a comma is used in a symbol, I don't think it will affect existing code.

Updated by sawa (Tsuyoshi Sawada) about 5 years ago

What about using a sequence of space characters as delimiter?

h = {
  author: {
    name: "Ruby Taro",
    affiliation: "Ruby co.",
  date: "2014, 8, 14"

"Author: %{author name} (%{author affiliation}), %{date}" % h
#=> "Author: Ruby Taro (Ruby co.), 2014, 8, 14"

"%{author name} works at %{author affiliation}" % h
#=> "Ruby Taro works at Ruby co."

This is reminiscent of (and hence consistent with) %w{} and %i{} notations, which also use a sequence of space characters as delimiter.

Also available in: Atom PDF