Ruby缩进多行字符串

时间:2010-07-28 07:13:24

标签: ruby code-formatting

这是一个最佳实践问题。有明显的方法可以做到这一点,它们都没有恰到好处。

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

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真的感觉不对。

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

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

4 个答案:

答案 0 :(得分:9)

如果您正在构建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

答案 1 :(得分:7)

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

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

答案 2 :(得分:0)

我不确定其中任何一种都可称为“最佳实践”,但这里有四种可能性

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部分。

答案 3 :(得分:0)

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

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

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

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