Ruby缩进多行字符串

这是一个最佳实践问题。 有明显的方法可以做到这一点,其中没有一个看起来很正确。

我经常需要测试是否产生了一些多行字符串。 这通常会打破缩进,使一切看起来像一团糟:

class TestHelloWorld < Test::Unit::TestCase def test_hello assert_equal <<EOS, hello_world Hello, world! World greets you EOS end end 

使用<<-我可以在这里缩进doc标记,但它不会剥离heredoc中的缩进,它仍然看起来很可怕。

 class TestHelloWorld < Test::Unit::TestCase def test_hello assert_equal <<-EOS, hello_world Hello, world! World greets you EOS end end 

这让我缩进,但测试线的可读性受到影响。 这个gsub真的感觉gsub

 class TestHelloWorld < Test::Unit::TestCase def test_hello assert_equal <<-EOS.gsub(/^ {6}/, ""), hello_world Hello, world! World greets you EOS end end 

有没有办法测试那些真正可读的多行字符串?

就我个人而言,我认为Ruby的缩进heredocs是无用的,它们应该更像Bash缩进的heredocs,并且还会删除字符串中的空格…

无论如何,有几个图书馆试图处理这种情况。 有很多库试图解决这个问题:

  • Martin Aumont的Unindent图书馆也是Facets图书馆的一部分
  • Facets还提供String#margin
  • Sunlight Labs的Unindentable
  • Samuel Dana的缩进图书馆

如果您正在构建Rails应用程序,请尝试使用strip_heredoc ,否则您可能始终需要active_support核心扩展。

您的示例可能如下所示:

 require 'active_support/core_ext' class TestHelloWorld < Test::Unit::TestCase def test_hello assert_equal <<-EOS.strip_heredoc, hello_world Hello, world! World greets you EOS end end 

如果您确实不想包含它们,则会从active_support复制以下代码,以及如何处理格式设置的示例。

 class String def try(*a, &b) if a.empty? && block_given? yield self else __send__(*a, &b) end end def strip_heredoc indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0 gsub(/^[ \t]{#{indent}}/, '') end end 

我不确定这些可以被称为“最佳实践”,但这里有四种可能性

 class Hello def self.world "Hello, world! World greets you " end end require 'test/unit' class TestHelloWorld < Test::Unit::TestCase #Define a constant array of multiline strings and test against the array # see test_hello_4 # Alternatively store the multi-line strings in a Yaml fixture file and load # them into a constant Hash or Array within a setup method MLINE = [ "Hello, world! World greets you ", "Another multi line string", ] # Create a method to return the string def test_hello_1 assert_equal Hello.world, hello_world_string() end # Create the string using embedded newlines def test_hello_2 assert_equal Hello.world, "Hello, world!\n World greets you\n" end # if you only have 1 in the test then put it in a DATA section def test_hello_3 assert_equal Hello.world, DATA.read end def test_hello_4 assert_equal Hello.world, MLINE[0] end def hello_world_string "Hello, world! World greets you " end end __END__ Hello, world! World greets you 

全部通过

 Loaded suite test_hello_world Started .... Finished in 0.00083 seconds. 4 tests, 4 assertions, 0 failures, 0 errors 

我个人更喜欢带嵌入换行符的字符串(方法2),除非字符串很长,在这种情况下我会选择DATA部分。

它是关于格式化还是关于内容的测试?

如果它是关于格式化的测试,也许你的测试太高了,你应该测试一个“Formatter”类,你可能会找到一种方法来测试类,使得多行文本比较无用。 然后,您将能够模拟Formatter类以检查它是否将接收所需的所有内容。 例如,Formatter可以是一个具有add_line方法的类,该方法在给定每个参数后添加“\ n”,并返回将返回多行字符串的formatted_string 。 一旦你测试了Formatter类,你就必须检查它是否被正确调用。 这样,您就可以将内容测试与格式测试分开。

如果它是关于内容的测试,也许你应该按行拆分hello_world,然后检查第一行是否包含“Hello,world”,第二行包含“World greets you”。

我认为测试整个多行文本块并不是一个好习惯。