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”。
我认为测试整个多行文本块并不是一个好习惯。