Ruby 用引号内的变量格式化字符串

Ruby format string with variable inside quotes

如果我这样做

template_string = "class=btn submit-button %<additional_classes>"
format(template_string, additional_classes: 'some-class')

有效。但是,如果我这样做

template_string = "class='btn submit-button %<additional_classes>'"
format(template_string, additional_classes: 'some-class')

失败,给出

ArgumentError:
  malformed format string - %'

(注意第二个 template_string 中 类 周围的引号 - 这是两个 Ruby 代码块之间的唯一区别)。我如何让它发挥作用?换句话说,我如何生成以下内容?

class='btn submit-button some-class'

我不相信我可以只使用插值,因为有时我需要传入其他变量。也就是说,我做不到

additional_classes = 'some-class'
"class='btn submit-button #{additional_classes}'"

因为有时我想重用相同的字符串 "template" 但传入其他变量,以生成如下字符串:

class='btn submit-button some-other-class'

class='btn submit-button some-third-class'

来自fine manual

format(format_string [, arguments...] ) → string
[...]
For more complex formatting, Ruby supports a reference by name. %<name>s style uses format style, but %{name} style doesn't.

文档没有尽可能清楚,但是当您使用 %<...> 形式时,它期望看到 %<name>s 其中 name 是散列键和 s 是格式类型:s 代表字符串,d 代表数字,... 如果你说:

%<additional_classes>'

然后 format 将尝试在没有此类类型说明符时将 ' 解释为一种类型,因此您会得到一个 ArgumentError,因为格式字符串格式错误。

您可能想改用 %{...} 形式:

template_string = "class='btn submit-button %{additional_classes}'"
#--------------------------------------------^------------------^

您的格式字符串缺少 field type specifier。字段类型说明符在格式字符串中是必需的。

我不清楚为什么第一个示例没有引发错误,因为缺少必需的字段类型说明符。这可能是一个错误,或者我完全误读了文档。

但是,我不清楚为什么你认为这个例子有效:

template_string = "class=btn submit-button %<additional_classes>"
format(template_string, additional_classes: 'some-class')
#=> 'class=btn submit-button %'
#                            ↑

如您所见,% 没有被解释为格式字符串的一部分,而是被解释为文字 %。我会认为这是一个错误,它应该会引发错误,就像第二个示例一样。

在第二个例子中,你可以清楚地看到问题所在:

ArgumentError: malformed format string - %'
                                          ↑

由于格式字符串必须有字段类型说明符,并且 % 之后的唯一字符(字段名称除外)是 ',这被解释为字段类型说明符。由于 ' 不是合法的字段类型,format 会引发一个错误,它明确告诉您它将 ' 解释为格式字符串的一部分。

既然你想格式化字符串,你应该使用s(字符串)字段类型说明符:

template_string = "class=btn 'submit-button %<additional_classes>s'"
#                                                                ↑

format(template_string, additional_classes: 'some-class')
#=> "class=btn 'submit-button some-class'"
#                             ↑↑↑↑↑↑↑↑↑↑↑

或者,您可以使用 %{} 形式:

template_string = "class=btn 'submit-button %{additional_classes}'"
#                                            ↑                  ↑

format(template_string, additional_classes: 'some-class')
#=> "class=btn 'submit-button some-class'"
#                             ↑↑↑↑↑↑↑↑↑↑↑