Ruby 缩进多行字符串
这是一个最佳实践问题。有很多明显的方法可以做到这一点,但没有一个看起来完全正确。
我经常需要测试是否生成了一些多行字符串。这通常会破坏缩进,使一切看起来一团糟:
class TestHelloWorld < Test::Unit::TestCase
def test_hello
assert_equal <<EOS, hello_world
Hello, world!
World greets you
EOS
end
end
使用 <<-
我可以在此处缩进文档标记,但它不会删除heredoc内的缩进,它看起来仍然很糟糕。
class TestHelloWorld < Test::Unit::TestCase
def test_hello
assert_equal <<-EOS, hello_world
Hello, world!
World greets you
EOS
end
end
这让我可以缩进,但测试行的可读性会受到影响。这个gsub
在这里真的感觉不太对劲。
class TestHelloWorld < Test::Unit::TestCase
def test_hello
assert_equal <<-EOS.gsub(/^ {6}/, ""), hello_world
Hello, world!
World greets you
EOS
end
end
有什么方法可以测试这样的多行字符串是否真的可读?
It's a best-practice question. There are obvious ways to do that, none of them just seem quite right.
Quite often I need to test that some multi-line string gets produced. This normally breaks indentation making everything look like a mess:
class TestHelloWorld < Test::Unit::TestCase
def test_hello
assert_equal <<EOS, hello_world
Hello, world!
World greets you
EOS
end
end
With <<-
I can indent here doc marker, but it doesn't strip indentation inside heredoc, it still looks horrible.
class TestHelloWorld < Test::Unit::TestCase
def test_hello
assert_equal <<-EOS, hello_world
Hello, world!
World greets you
EOS
end
end
This lets me indent but readability of test line suffers. This gsub
really doesn't feel right here.
class TestHelloWorld < Test::Unit::TestCase
def test_hello
assert_equal <<-EOS.gsub(/^ {6}/, ""), hello_world
Hello, world!
World greets you
EOS
end
end
Is there any way to test such multi-line strings that's really readable?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您正在构建 Rails 应用程序,请尝试使用
strip_heredoc
,否则您可能始终需要 active_support 核心扩展。您的示例可能如下所示:
如果您确实不想包含它们,请从 active_support 复制以下代码作为如何处理格式的示例。
If you're building a Rails application, try using
strip_heredoc
, if not you could always require active_support core extensions.Your Example might look like this:
If you really don't want to include them, the following code is copied from active_support as and example of how you might handle the formatting.
就我个人而言,我认为 Ruby 的缩进此处文档毫无用处,它们应该更像 Bash 缩进此处文档,并且还去除字符串内的空格……
无论如何,有几个库尝试处理这种情况。有很多库试图解决此问题:
String#margin
Personally, I think that Ruby's indented heredocs are useless and they should work more like Bash indented heredocs and also strip whitespace inside the string …
Anyway, there are a couple of libraries that try to deal with this situation. There is a wide array of libraries that try to fix this problem:
String#margin
我不确定这些是否可以称为“最佳实践”,但这里有四种可能性
全部通过
我个人更喜欢嵌入换行符的字符串(方法2)除非字符串很长在这种情况下我会使用DATA部分。
I'm not sure any of these could be called "Best Practice" but here are four possibilities
All passing
I would personally prefer the string with embedded newlines (Method 2) unless the string was very long in which case I would go with the DATA section.
是关于格式的测试还是关于内容的测试?
如果这是一个关于格式化的测试,也许你的测试水平太高了,你应该测试一个“Formatter”类,你可能会找到一种方法来测试该类,使多行文本比较变得毫无用处。然后,您将能够模拟 Formatter 类以检查它是否会收到所需的所有内容。例如,Formatter 可以是一个具有 add_line 方法的类,该方法在给出的每个参数后添加一个“\n”,以及一个 formatted_string 将返回多行字符串。一旦您测试了 Formatter 类,您只需检查它是否被正确调用。这样,您就可以将内容测试与格式测试分开。
如果是关于内容的测试,也许你应该将 hello_world 按行分割,然后检查第一行是否包含“Hello, world”,第二行包含“World问候你”。
我认为测试整个多行文本块根本不是一个好的做法。
Is it a test about formatting or about the content ?
If it's a test about formatting, maybe your test is too high level, and you should test a "Formatter" class and you'll probably find a way to test the class in a way that makes the multiline text comparison useless. And then, you would be able to mock the Formatter class to check that it will receive all the content it needs. For example, the Formatter could be a class that have a add_line method which adds a "\n" after each argument it is given and a formatted_string that will return the multiline string. Once you've tested the Formatter class, you'll just have to check it is called correctly. This way, you separate the tests for the content from the tests for the format.
If it's a test about the content, maybe you should just split the hello_world by line, and then check that the first line contains "Hello, world" and the second one contains "World greets you".
I don't think it's a good practice at all to test a whole multiline block of text.