Ruby缩进多行字符串

Ruby缩进多行字符串,ruby,code-formatting,Ruby,Code Formatting,这是一个最佳实践问题。有明显的方法可以做到这一点,但没有一种方法看起来是完全正确的 我经常需要测试是否生成了一些多行字符串。这通常会破坏压痕,使一切看起来一团糟: class TestHelloWorld < Test::Unit::TestCase def test_hello assert_equal <<EOS, hello_world Hello, world! World greets you EOS end end 有没有什么方法可以测试这种真

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

我经常需要测试是否生成了一些多行字符串。这通常会破坏压痕,使一切看起来一团糟:

class TestHelloWorld < Test::Unit::TestCase
  def test_hello
    assert_equal <<EOS, hello_world
Hello, world!
  World greets you
EOS
  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

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

这是关于格式还是关于内容的测试

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

如果是关于内容的测试,也许你应该把hello_world一行一行分割,然后检查第一行是否包含“hello,world”,第二行是否包含“world问候你”


我认为测试整个多行文本块根本不是一个好的做法。

就我个人而言,我认为Ruby的缩进herdoc是无用的,它们应该更像Bash缩进的herdoc,还可以去除字符串中的空白

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

  • 这也是
  • Facets还提供

如果您正在构建Rails应用程序,请尝试使用
strip\u herdoc
,如果不是,您可能始终需要活动的\u支持核心扩展

您的示例可能如下所示:

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

一次性测试是唯一正确的方法。若不同-测试应显示整个预期结果和整个实际结果。逐行比较等只会使测试失败报告变得毫无价值。正如我在回答中所说的,这实际上取决于您正在测试的内容:内容还是格式?如果你真的想同时测试这两个问题,我认为其他人已经给出了很好的答案。如果你想避免外部依赖,这两个答案可能是公认答案的替代品。他们通过修补
字符串
,将
gsub
移到看不见的地方,使here字符串更具可读性。
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
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
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