Saya mengalami masalah dengan heredoc Ruby yang saya coba buat. Ini mengembalikan spasi putih utama dari setiap baris meskipun saya termasuk operator -, yang seharusnya menyembunyikan semua karakter spasi putih utama. metode saya terlihat seperti ini:
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
dan keluaran saya terlihat seperti ini:
=> " \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"
ini, tentu saja, benar dalam contoh khusus ini, kecuali untuk semua spasi di antara yang pertama "dan \ t. adakah yang tahu apa yang saya lakukan salah di sini?
sumber
Jika Anda menggunakan Rails 3.0 atau yang lebih baru, coba
#strip_heredoc
. Contoh dari dokumen ini mencetak tiga baris pertama tanpa lekukan, sambil mempertahankan lekukan dua spasi dari dua baris terakhir:if options[:usage] puts <<-USAGE.strip_heredoc This command does such and such. Supported options are: -h This message ... USAGE end
Dokumentasi juga mencatat: "Secara teknis, ini mencari baris yang paling tidak menjorok ke dalam di seluruh string, dan menghapus jumlah spasi di awal."
Berikut implementasi dari 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
Dan Anda dapat menemukan pengujian di test / core_ext / string_ext_test.rb .
sumber
require "active_support/core_ext/string"
pertamatry
tidak ditentukan untuk String. Faktanya, tampaknya itu adalah konstruksi khusus relTidak banyak yang harus dilakukan yang saya tahu, saya takut. Saya biasanya melakukan:
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
Itu berfungsi tetapi sedikit hack.
EDIT: Mengambil inspirasi dari Rene Saarsoo di bawah ini, saya menyarankan sesuatu seperti ini sebagai gantinya:
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
Versi ini harus menangani jika baris pertama bukan yang terjauh ke kiri juga.
sumber
EOF
itu sendiri, bukan hanyaString
?\s
termasuk baris baru.Berikut adalah versi yang jauh lebih sederhana dari skrip unindent yang saya gunakan:
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
Gunakan seperti ini:
foo = { bar: <<-ENDBAR.unindent My multiline and indented content here Yay! ENDBAR } #=> {:bar=>"My multiline\n and indented\n content here\nYay!"}
Jika baris pertama mungkin lebih menjorok daripada yang lain, dan ingin (seperti Rails) untuk membatalkan indentasi berdasarkan baris yang paling tidak menjorok ke dalam, Anda mungkin ingin menggunakan:
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
Perhatikan bahwa jika Anda memindai,
\s+
bukan[ \t]+
Anda, mungkin akan menghapus baris baru dari heredoc Anda alih-alih memimpin spasi. Tidak diinginkan!sumber
<<-
di Ruby hanya akan mengabaikan spasi di depan untuk pembatas akhir, memungkinkannya untuk diindentasi dengan benar. Itu tidak menghapus spasi terdepan pada baris di dalam string, terlepas dari apa yang mungkin dikatakan beberapa dokumentasi online.Anda dapat menghapus spasi di depan sendiri dengan menggunakan
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
Atau jika Anda hanya ingin menghapus spasi, keluar dari tab:
<<-EOF.gsub /^ */, '' \tSELECT \t CAST('#{name}' AS VARCHAR(30)) as COLUMN_NAME \t,COUNT(DISTINCT #{name}) AS DISTINCT_COUNT \tFROM #{table.call} EOF
sumber
Beberapa jawaban lain menemukan tingkat lekukan garis paling menjorok , dan menghapus bahwa dari semua lini, tapi mengingat sifat lekukan di pemrograman (yang baris pertama adalah yang paling menjorok), saya pikir Anda harus mencari tingkat lekukan yang baris pertama .
class String def unindent; gsub(/^#{match(/^\s+/)}/, "") end end
sumber
Seperti poster aslinya, saya juga menemukan
<<-HEREDOC
sintaksnya dan sangat kecewa karena tidak berperilaku seperti yang saya kira.Tetapi alih-alih mengotori kode saya dengan gsub-s, saya memperluas kelas 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
sumber
Catatan: Seperti yang ditunjukkan @radiospiel,
String#squish
hanya tersedia dalamActiveSupport
konteksnya.aku percaya
rubyString#squish
lebih dekat dengan apa yang sebenarnya Anda cari:Inilah cara saya menangani contoh Anda:
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
sumber
Opsi lain yang mudah diingat adalah menggunakan permata yang tidak memiliki indentasi
require 'unindent' p <<-end.unindent hello world end # => "hello\n world\n"
sumber
Saya perlu menggunakan sesuatu yang
system
dengannya saya dapat membagised
perintah panjang di seluruh baris dan kemudian menghapus indentasi DAN baris baru ...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
Jadi saya datang dengan ini:
class ::String def strip_heredoc(compress = false) stripped = gsub(/^#{scan(/^\s*/).min_by(&:length)}/, "") compress ? stripped.gsub(/\n/," ").chop : stripped end end
Perilaku default adalah tidak menghapus baris baru, seperti semua contoh lainnya.
sumber
Saya mengumpulkan jawaban dan mendapatkan ini:
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
Ini menghasilkan SQL yang sangat baik dan tidak keluar dari cakupan AR.
sumber