懒惰评估“#{}” - ruby​​中的字符串

时间:2012-10-20 16:51:45

标签: ruby string eval

我开始在我的代码中放置print语句。为了不使输出混乱,我做了类似的事情:

dputs LEVEL, "string"

其中LEVEL为0表示错误,1表示重要... 5表示详细,并与DEBUG_LEVEL进行比较。现在我的问题是,在一个声明中:

dputs 5, "#{big_class.inspect}"

总是评估字符串,如果我将DEBUG_LEVEL设置为1.此评估可能需要很长时间。我最喜欢的解决方案是:

dputs 5, '#{big_class.inspect}'

然后根据需要评估字符串。但是我没有设法以我能评估的形式获得字符串。所以我能想到的唯一想法是:

dputs( 5 ){ "#{big_class.inspect}" }

但这看起来很难看。那么我该如何评估一个'#{}'字符串?

4 个答案:

答案 0 :(得分:6)

您可以dputs使用sprintf(通过%)来完成此操作。这样它就可以决定不构建内插字符串,除非它知道它将打印它:

def dputs(level, format_str, *vars)
  puts(format_str % vars) if level <= LEVEL
end

LEVEL = 5
name = 'Andrew'
dputs 5, 'hello %s', name
#=> hello Andrew

或者,正如您所建议的那样,您可以传递一个块,该块将推迟插值直到块实际运行:

def dputs(level, &string)
  raise ArgumentError.new('block required') unless block_given?
  puts string.call if level <= LEVEL
end

答案 1 :(得分:1)

我认为你不能在那里躲避丑陋。插值发生在调用dput之前,除非你把它放在一个块中,这会推迟它直到dputs评估它。我不知道dput来自哪里,所以我不确定它的语义是什么,但我猜这个块会让你得到你想要的懒惰评估。不漂亮,但它确实起到了作用。

答案 2 :(得分:1)

我认为这没什么价值,但我想出了:

2.3.1 :001 > s = '#{a}'
 => "\#{a}"
2.3.1 :002 > a = 1
 => 1
2.3.1 :003 > instance_eval s.inspect.gsub('\\', '')
 => "1"
2.3.1 :004 > s = 'Hello #{a} and #{a+1}!'
 => "Hello \#{a} and \#{a+1}!"
2.3.1 :005 > instance_eval s.inspect.gsub('\\', '')
 => "Hello 1 and 2!"

不要在生产中使用它:)

答案 3 :(得分:0)

好吧,显然我太懒了。我认为必须有一个更干净的方法来做到这一点,Ruby是最好的编程语言和所有;)评估像

这样的字符串
a = '#{1+1} some text #{big_class.inspect}'

仅在需要时,我找不到比通过字符串更好的方式和 eval 所遇到的所有“#{}”:

str = ""
"#{b}\#{}".scan( /(.*?)(#\{[^\}]*\})/ ){
  str += $1
  str += eval( $2[2..-2] ).to_s
}

如果你没有明确,你可以摆脱临时变量 str

"#{b}\#{}".scan( /(.*?)(#\{[^\}]*\})/ ).collect{|c|
  c[0] + eval( c[1][2..-2] ).to_s
}.join

String.scan-method遍历每个'#{}' - 块,因为可能有不止一个,评估它( 2 ..- 2 会删除“#{ “和”}“)并将其与字符串的其余部分放在一起。

对于不以'#{}' - 块结尾的字符串的角落情况,添加一个空块,只是为了确定。

但是,在Ruby工作了几年之后,这仍然感觉很笨拙和C-ish。也许是时候学习一门新语了!