97

作成しようとしている Ruby ヒアドキュメントに問題があります。すべての先頭の空白文字を抑制することになっている - 演算子が含まれていても、各行から先頭の空白を返しています。私の方法は次のようになります。

    def distinct_count
    <<-EOF
        \tSELECT
        \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
        \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
        \tFROM #{table.call}
    EOF
end

私の出力は次のようになります。

    => "            \tSELECT\n            \t CAST('SRC_ACCT_NUM' AS VARCHAR(30)) as
COLUMN_NAME\n            \t,COUNT(DISTINCT SRC_ACCT_NUM) AS DISTINCT_COUNT\n
        \tFROM UD461.MGMT_REPORT_HNB\n"

もちろん、これは、最初の " と \t の間のすべてのスペースを除いて、この特定のインスタンスでは正しいです。ここで私が間違っていることを知っている人はいますか?

4

11 に答える 11

157

ヒアドキュメントの<<-形式は、終了区切り文字の先頭の空白のみを無視します。

Ruby 2.3 以降では、波線のヒアドキュメント ( <<~) を使用して、コンテンツ行の先頭の空白を抑制することができます。

def test
  <<~END
    First content line.
      Two spaces here.
    No space here.
  END
end

test
# => "First content line.\n  Two spaces here.\nNo space here.\n"

Rubyリテラルのドキュメントから:

コンテンツの各行から、最もインデントされていない行のインデントが削除されます。空の行と、リテラルのタブとスペースのみで構成される行は、インデントを決定する目的で無視されますが、エスケープされたタブとスペースは非インデント文字と見なされることに注意してください。

于 2016-01-19T22:33:21.593 に答える
123

Rails 3.0 以降を使用している場合は、 を試してください#strip_heredocドキュメントのこの例では、最後の 2 行の 2 スペースのインデントを保持しながら、最初の 3 行をインデントなしで出力します。

if options[:usage]
  puts <<-USAGE.strip_heredoc
    This command does such and such.
 
    Supported options are:
      -h         This message
      ...
  USAGE
end

ドキュメントには、「技術的には、文字列全体で最もインデントされていない行を探し、その量の先頭の空白を削除します。」

以下はactive_support/core_ext/string/strip.rbからの実装です:

class String
  def strip_heredoc
    indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
    gsub(/^[ \t]{#{indent}}/, '')
  end
end

テストはtest/core_ext/string_ext_test.rbにあります。

于 2012-03-11T10:45:29.840 に答える
44

私が知っていることをすることはあまりありません。私は通常、次のことを行います。

def distinct_count
    <<-EOF.gsub /^\s+/, ""
        \tSELECT
        \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
        \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
        \tFROM #{table.call}
    EOF
end

それは機能しますが、ちょっとしたハックです。

編集: 以下の Rene Saarsoo からインスピレーションを得て、代わりに次のようなものを提案します。

class String
  def unindent 
    gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, "")
  end
end

def distinct_count
    <<-EOF.unindent
        \tSELECT
        \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
        \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
        \tFROM #{table.call}
    EOF
end

このバージョンは、最初の行が左端にない場合にも処理する必要があります。

于 2010-09-22T19:30:15.160 に答える
23

以下は、私が使用している unindent スクリプトのはるかに単純なバージョンです。

class String
  # Strip leading whitespace from each line that is the same as the 
  # amount of whitespace on the first line of the string.
  # Leaves _additional_ indentation on later lines intact.
  def unindent
    gsub /^#{self[/\A[ \t]*/]}/, ''
  end
end

次のように使用します。

foo = {
  bar: <<-ENDBAR.unindent
    My multiline
      and indented
        content here
    Yay!
  ENDBAR
}
#=> {:bar=>"My multiline\n  and indented\n    content here\nYay!"}

最初の行が他の行よりも多くインデントされている可能性があり、(Rails のように) 最もインデントされていない行に基づいてインデントを解除したい場合は、代わりに次を使用できます。

class String
  # Strip leading whitespace from each line that is the same as the 
  # amount of whitespace on the least-indented line of the string.
  def strip_indent
    if mindent=scan(/^[ \t]+/).min_by(&:length)
      gsub /^#{mindent}/, ''
    end
  end
end

\s+代わりにスキャンする[ \t]+と、先頭の空白の代わりにヒアドキュメントから改行が削除される可能性があることに注意してください。望ましくない!

于 2011-04-12T15:58:23.700 に答える
8

<<-Ruby では、終了区切り文字の先頭のスペースのみを無視して、適切にインデントできるようにします。オンラインのドキュメントの内容に関係なく、文字列内の行の先頭のスペースは削除されません。

次を使用して、先頭の空白を自分で削除できますgsub

<<-EOF.gsub /^\s*/, ''
    \tSELECT
    \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
    \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
    \tFROM #{table.call}
EOF

または、タブを残してスペースを削除するだけの場合:

<<-EOF.gsub /^ */, ''
    \tSELECT
    \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME
    \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
    \tFROM #{table.call}
EOF
于 2010-09-22T19:35:06.017 に答える
3

元のポスターのように、私も<<-HEREDOC構文を発見し、思ったように動作しないことにかなりがっかりしました。

しかし、コードを gsub-s で散らかす代わりに、String クラスを拡張しました。

class String
  # Removes beginning-whitespace from each line of a string.
  # But only as many whitespace as the first line has.
  #
  # Ment to be used with heredoc strings like so:
  #
  # text = <<-EOS.unindent
  #   This line has no indentation
  #     This line has 2 spaces of indentation
  #   This line is also not indented
  # EOS
  #
  def unindent
    lines = []
    each_line {|ln| lines << ln }

    first_line_ws = lines[0].match(/^\s+/)[0]
    re = Regexp.new('^\s{0,' + first_line_ws.length.to_s + '}')

    lines.collect {|line| line.sub(re, "") }.join
  end
end
于 2010-12-16T21:41:40.380 に答える
3

注: @radiospiel が指摘したように、コンテキストString#squishでのみ使用できます。ActiveSupport


私は信じているルビーの String#squishあなたが本当に探しているものに近いです:

あなたの例をどのように処理するかは次のとおりです。

def distinct_count
  <<-SQL.squish
    SELECT
      CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME,
      COUNT(DISTINCT #{name}) AS DISTINCT_COUNT
      FROM #{table.call}
  SQL
end
于 2013-04-19T21:58:46.490 に答える
2

覚えやすいもう1つのオプションは、インデントされていないgemを使用することです

require 'unindent'

p <<-end.unindent
    hello
      world
  end
# => "hello\n  world\n"  
于 2014-07-29T03:36:26.123 に答える