5

我开始在我的代码中添加打印语句。为了不弄乱输出,我做了类似的事情:

dputs LEVEL, "string"

其中LEVEL0 表示错误,1 表示重要 .. 5 表示详细,并与DEBUG_LEVEL. 现在我的问题是,在这样的声明中:

dputs 5, "#{big_class.inspect}"

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

dputs 5, '#{big_class.inspect}'

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

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

但这看起来很丑陋。那么如何评估 '#{}' 字符串呢?

4

4 回答 4

6

您可以通过dputs使用sprintf(via %) 来做到这一点。这样它就可以决定不构建内插字符串,除非它知道要打印它:

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
于 2012-10-20T17:17:53.947 回答
1

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

于 2012-10-20T17:19:24.003 回答
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!"

不要在生产中使用它:)

于 2017-09-12T19:05:44.050 回答
0

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

a = '#{1+1} some text #{big_class.inspect}'

仅在需要时,我没有找到比遍历字符串并评估遇到的所有“#{}”更好的方法:

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 方法遍历每个 '#{}' 块,因为可能不止一个块,评估它(2..-2删除了“#{”和“}”)并将其放在一起与字符串的其余部分。

对于不以'#{}'块结尾的字符串的极端情况,添加一个空块,以确保。

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

于 2012-10-22T20:54:29.980 回答