挿入 - ruby 空白文字




Ruby HEREDOCから先行する空白文字を削除するにはどうすればよいですか? (8)

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

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の実装は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.rbtest/core_ext/string_ext_test.rb見つけることができます。

私が作ろうとしているRubyのheredocに問題があります。 先行するすべての空白文字を抑止するはずの - 演算子を含めても、各行から先頭の空白を戻しています。 私の方法は次のようになります:

    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の間のすべてのスペースを除いて正しいです。誰かが私がここで間違っていることを知っていますか?


heredocの<<-形式は、終わりの区切り文字の先頭の空白を無視します。

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

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 リテラルドキュメントから

インデントされていない行のインデントは、コンテンツの各行から削除されます。 リテラルタブとスペースのみで構成される空白行と行は、インデントを決定するために無視されますが、エスケープされたタブとスペースはインデントされていない文字とみなされます。


注意: @radiospielが指摘したように、 String#squish ActiveSupportActiveSupportコンテキストでのみ利用可能です。

私は信じている ルビー 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

ここでは、使用しているインデントされていないスクリプトのはるかに単純なバージョンです:

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

[ \t]+代わりに\s+をスキャンすると、空白を誘導するのではなく、あなたのheredocから改行を取り除くことになります。 望ましくない!


もう一つの覚えやすいオプションはインデントのない宝石を使うことです

require 'unindent'

p <<-end.unindent
    hello
      world
  end
# => "hello\n  world\n"  

他のいくつかの答えは、インデントされていない行のインデントレベルを見つけて、すべての行から削除しますが、プログラミングのインデントの性質(最初の行がインデントされていないこと)を考慮して、一行目

class String
  def unindent; gsub(/^#{match(/^\s+/)}/, "") end
end

私は答えを集め、これを得た:

class Match < ActiveRecord::Base
  has_one :invitation
  scope :upcoming, -> do
    joins(:invitation)
    .where(<<-SQL_QUERY.strip_heredoc, Date.current, Date.current).order('invitations.date ASC')
      CASE WHEN invitations.autogenerated_for_round IS NULL THEN invitations.date >= ?
      ELSE (invitations.round_end_time >= ? AND match_plays.winner_id IS NULL) END
    SQL_QUERY
  end
end

優れたSQLを生成し、ARスコープから外に出ない。


私は長いsedコマンドを行間で分割し、インデントと改行を取り除くことができるsystem何かを使う必要がありました...

def update_makefile(build_path, version, sha1)
  system <<-CMD.strip_heredoc(true)
    \\sed -i".bak"
    -e "s/GIT_VERSION[\ ]*:=.*/GIT_VERSION := 20171-2342/g"
    -e "s/GIT_VERSION_SHA1[\ ]:=.*/GIT_VERSION_SHA1 := 2342/g"
    "/tmp/Makefile"
  CMD
end

だから私はこれを思いついた:

class ::String
  def strip_heredoc(compress = false)
    stripped = gsub(/^#{scan(/^\s*/).min_by(&:length)}/, "")
    compress ? stripped.gsub(/\n/," ").chop : stripped
  end
end

デフォルトの動作は、他のすべての例と同様に改行を取り除くことです。





heredoc