আমি রুবি হারডোক থেকে নেতৃস্থানীয় হোয়াইটস্পেস চরগুলি কীভাবে সরিয়ে দেব?


94

আমি যে রুবি হেরিডোকটি তৈরির চেষ্টা করছি তাতে আমার সমস্যা হচ্ছে। এটি প্রতিটি লাইন থেকে অগ্রণী হোয়াইটস্পেসটি ফিরিয়ে দিচ্ছে যদিও আমি অপারেটরকে অন্তর্ভুক্ত করছি, যা সমস্ত নেতৃস্থানীয় হোয়াইটস্পেসের অক্ষরগুলিকে দমন করবে বলে মনে করা হচ্ছে। আমার পদ্ধতিটি এমন দেখাচ্ছে:

    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" এর মধ্যে সমস্ত জায়গাগুলি বাদে এটি অবশ্যই এই নির্দিষ্ট উদাহরণে ঠিক আছে? কেউ কি জানেন যে আমি এখানে কী ভুল করছি?

উত্তর:


146

<<-হেরডোকের ফর্মটি কেবল শেষ সীমানার জন্য শীর্ষস্থানীয় সাদা স্থানকে উপেক্ষা করে।

রুবি ২.৩ এর সাথে এবং পরে আপনি <<~সামগ্রীর লাইনের শীর্ষস্থানীয় সাদা অংশটি দমন করতে স্কুইগ্লি হেরিডোক ( ) ব্যবহার করতে পারেন :

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"

রুবি আক্ষরিক ডকুমেন্টেশন থেকে :

অন্ততপরিবর্তিত লাইনের ইন্ডেন্টেশন সামগ্রীটির প্রতিটি লাইন থেকে সরানো হবে। নোট করুন যে খালি লাইন এবং লাইনগুলি কেবলমাত্র আক্ষরিক ট্যাব এবং স্পেসের সমন্বয়ে ইন্ডেন্টেশন নির্ধারণের উদ্দেশ্যে অগ্রাহ্য করা হবে তবে পালানো ট্যাব এবং স্পেসগুলি নন-ইনডেন্টেশন অক্ষর হিসাবে বিবেচিত হবে।


13
আমি ভালবাসি যে আমি প্রশ্ন জিজ্ঞাসার 5 বছর পরে এটি এখনও একটি প্রাসঙ্গিক বিষয়। আপডেট প্রতিক্রিয়া জন্য ধন্যবাদ!
ক্রিস ড্র্যাপিয়ার

4
@ ক্রিসড্রেপ্পিয়ার এটি সম্ভব কিনা তা সম্পর্কে নিশ্চিত নন, তবে আমি এই প্রশ্নের উত্তর গৃহীত উত্তরকে উত্তর দিয়ে পরিবর্তিত করার পরামর্শ দেব কারণ আজকাল এটি পরিষ্কারভাবে সমাধান হয়ে গেছে।
TheDeadSerious 10

123

আপনি যদি রেল ..০ বা আরও নতুন ব্যবহার করছেন তবে চেষ্টা করুন #strip_heredoc। শেষ দুটি লাইনের দ্বি-স্থানের ইন্ডেন্টেশনটি ধরে রেখে ডক্সের এই উদাহরণটি প্রথম তিনটি লাইন প্রবিষ্টকরণ ছাড়াই মুদ্রণ করে:

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

ডকুমেন্টেশনটি আরও উল্লেখ করে: "প্রযুক্তিগতভাবে, এটি পুরো স্ট্রিংয়ের মধ্যে কমপক্ষে ইন্ডেন্টেড লাইনের সন্ধান করে এবং সেই পরিমাণ নেতৃস্থানীয় হোয়াইটস্পেস সরিয়ে দেয়" "

সক্রিয়_সাম্পোর্ট / কোর_সেক্সট / স্ট্রিং / স্ট্রিপ.আরবি থেকে বাস্তবায়ন এখানে রয়েছে :

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

এবং আপনি পরীক্ষা / কোর_সেক্সট / স্ট্রিং_েক্সট_স্টেস্ট.আরবিতে পরীক্ষাগুলি খুঁজে পেতে পারেন ।


4
আপনি এখনও এটি 3 রেলের বাইরে ব্যবহার করতে পারেন!
আইকনোক্লাস্ট 25'12

4
আইকনোক্লাস্ট সঠিক; ঠিক require "active_support/core_ext/string"প্রথম
ডেভিড জে

4
রুবিতে কাজ করছে বলে মনে হচ্ছে না 1.8.7: স্ট্রিংয়ের tryজন্য সংজ্ঞায়িত করা হয়নি। বাস্তবে, দেখে মনে হচ্ছে এটি রেল-নির্দিষ্ট নির্মাণ
ওথিয়াস

45

আমি জানি যে আমি ভয় করি তা করার মতো বেশি কিছু নয়। আমি সাধারণত:

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

এটি কাজ করে তবে কিছুটা হ্যাক।

সম্পাদনা: নীচে রেনি সরসুর কাছ থেকে অনুপ্রেরণা গ্রহণ করে, আমি পরিবর্তে এর মতো কিছু প্রস্তাব করব:

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

এই সংস্করণটি হ্যান্ডেল করা উচিত যখন প্রথম লাইনটি খুব দূরে বাম দিকে না থাকে।


4
আমি জিজ্ঞাসা করার জন্য নোংরা বোধ করি, তবে কেবল EOFনিজের চেয়ে নিজের ডিফল্ট আচরণ হ্যাক করার কী আছে String?
প্যাটকন

4
অবশ্যই ইওএফের আচরণটি পার্সিংয়ের সময় নির্ধারিত হয়েছে, তাই আমি মনে করি আপনি, @ পেটকন, যা রুবীর জন্য উত্স কোড পরিবর্তন করার পরামর্শ দিচ্ছেন, এবং তারপরে আপনার কোডটি রুবির অন্যান্য সংস্করণে আলাদাভাবে আচরণ করবে।
einarmagnus

4
আমি চাই রুবির ড্যাশ হারডোক সিনট্যাক্স ব্যাশ-এর ​​মতো আরও কাজ করত, তবে আমাদের এই সমস্যাটি না হত! ( এই বাশের উদাহরণ দেখুন )
ত্রিনিট্রনএক্স

প্রো-টিপ: সামগ্রীর ফাঁকা রেখাগুলির সাথে এগুলির মধ্যে দুটি চেষ্টা করুন এবং তারপরে মনে রাখবেন \sএতে নিউলাইন রয়েছে।
ফ্রোগজ

আমি রুবি ২.২ এ চেষ্টা করেছি এবং কোনও সমস্যা লক্ষ্য করিনি। আপনার জন্য কি ঘটবে? ( repl.it/B09p )
einarmagnus

23

আমি যে আনইনেন্ডেন্ট স্ক্রিপ্টটি ব্যবহার করি এটির একটি আরও সহজ সংস্করণ এখানে:

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!"}

যদি প্রথম লাইনটি অন্যের চেয়ে বেশি ইনডেন্টড হতে পারে এবং (রেলের মতো) সর্বনিম্ন-ইনডেন্টড লাইনের ভিত্তিতে আনইন্ডেন্ট করতে চায় তবে আপনি পরিবর্তে এটি ব্যবহার করতে চাইতে পারেন:

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]+শীর্ষস্থানীয় হোয়াইটস্পেসের পরিবর্তে আপনার হেরেডোক থেকে নতুন লাইনগুলি সরিয়ে নেওয়া যেতে পারে। কাম্য নয়!


8

<<-রুবিতে কেবল শেষ ডিলিমিটারের জন্য অগ্রণী স্থানটিকে অগ্রাহ্য করা হবে, এটি যথাযথভাবে ইন্টেন্ট করা যাবে। অনলাইনে কিছু ডকুমেন্টেশন যা বলে তা সত্ত্বেও এটি স্ট্রিংয়ের অভ্যন্তরে লাইনগুলিতে শীর্ষস্থান সজ্জিত করে না।

আপনি ব্যবহার করে নেতৃস্থানীয় হোয়াইটস্পেস স্ট্রিপ করতে পারেন 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

4
-1 কেবলমাত্র ইনডেন্টেশনের পরিমাণের পরিবর্তে সমস্ত নেতৃস্থানীয় হোয়াইটস্পেস ছড়িয়ে দেওয়ার জন্য।
ফোগজ

7
@ ফ্রোগজ ওপি উল্লেখ করেছে যে তিনি আশা করেছিলেন যে এটি "সমস্ত শীর্ষস্থানীয় হোয়াইটস্পেস চরিত্রগুলিকে দমন করবে", তাই আমি একটি উত্তর দিয়েছি যে এটি করেছে, পাশাপাশি কেবলমাত্র ফাঁকা স্থানগুলি ছিনিয়ে নিয়েছে, ট্যাবগুলিকে নয়, যদি সে খুঁজছিল তবে। বেশ কয়েক মাস পরে আসছেন, ওপির পক্ষে কাজ করে এমন উত্তরগুলিকে নিম্নমুখী করা এবং আপনার নিজের প্রতিযোগিতামূলক উত্তর পোস্ট করা এক ধরণের লম্পট।
ব্রায়ান ক্যাম্পবেল

@ ব্রায়ান ক্যাম্পবেল আমি দুঃখিত আপনি এমনটি অনুভব করেছেন; কোনও অপরাধের উদ্দেশ্য ছিল না। আমি আশা করি আপনি আমাকে বিশ্বাস করবেন যখন আমি বলি যে আমি আমার নিজের উত্তরের জন্য ভোট অর্জনের প্রয়াসকে অগ্রাহ্য করছি না, তবে কেবল এই কারণেই অনুরূপ কার্যকারিতাটির জন্য একটি সৎ অনুসন্ধানের মাধ্যমে আমি এই প্রশ্নটির উপরে এসেছি এবং উত্তরগুলি এখানে এখানে উপ-সর্বোত্তম পেয়েছি। আপনি ঠিক বলেছেন যে এটি ওপি-র সঠিক চাহিদা সমাধান করে, তবে এটি আরও সামান্য-সাধারণ সমাধান দেয় যা আরও কার্যকারিতা সরবরাহ করে। আমি এও আশা করি যে আপনি একমত হবেন যে কোনও এক গৃহীত হওয়ার পরে পোস্ট করা উত্তরগুলি এখনও সামগ্রিকভাবে মূল্যবান, বিশেষত যদি তারা উন্নতি প্রস্তাব করে।
ফ্রোগজ

4
অবশেষে, আমি "প্রতিযোগিতামূলক উত্তর" বাক্যাংশটি সম্বোধন করতে চেয়েছিলাম। আপনার বা আমারও প্রতিযোগিতা হওয়া উচিত নয়, বা আমরা বিশ্বাস করি না যে আমরা আছি। (যদিও আমরা যদি থাকি তবে আপনি এই মুহুর্তের হিসাবে 27.4k প্রতিনিধি নিয়ে জিতছেন :) আমরা সমস্যার ব্যক্তিদের সাহায্য, উভয় ব্যক্তিগতভাবে (ওপি) ও বেনামে (ঐ Google এর মাধ্যমে আসার)। আরও (বৈধ) উত্তরগুলি সহায়তা করে। সেই শিরাতে আমি আমার ডাউনটাতে পুনর্বিবেচনা করি। আপনারা ঠিক বলেছেন যে আপনার উত্তরটি ক্ষতিকারক, বিভ্রান্তিকর, বা অতিরিক্ত নয়। আমি এখন আপনার প্রশ্নটি সম্পাদিত করেছি যাতে আমি আপনার কাছ থেকে দূরে সরিয়ে নেওয়া 2 পয়েন্টের প্রতিদান দিতে পারি।
ফ্রোগজ

4
@ ফ্রোগজ ক্ষুধার্ত হওয়ায় দুঃখিত; ওপিকে পর্যাপ্তরূপে সম্বোধন করে এমন উত্তরগুলির জন্য "আমার পছন্দ না এমন কোনও কিছুর জন্য" -1 নিয়ে আমার সমস্যা আছে। ইতিমধ্যে যখন আপভোটেড বা স্বীকৃত উত্তর রয়েছে যা প্রায়, তবে বেশিরভাগ নয়, আপনি যা চান তা করুন, ভবিষ্যতের যে কারও পক্ষে এটি আরও স্পষ্ট করে তুলবে যে আপনি কীভাবে মনে করেন যে উত্তরটি কোনও মন্তব্যে আরও ভাল হতে পারে, বরং ডাউনটিভয়েটিং এবং একটি পৃথক উত্তর পোস্ট করা যা নীচে প্রদর্শিত হবে এবং সাধারণত সমস্যা আছে এমন কারও দ্বারা দেখা যাবে না। উত্তরটি যদি ভুল হয় বা বিভ্রান্তিকর হয় তবে আমি কেবল ডাউনটিই দিয়েছি।
ব্রায়ান ক্যাম্পবেল

6

আরও কিছু উত্তর কমপক্ষে ইন্ডেন্টেড লাইনের ইন্ডেন্টেশন স্তরটি আবিষ্কার করে , এবং সমস্ত লাইন থেকে মুছে, কিন্তু প্রোগ্রামিং (যে প্রথম লাইন অন্তত ইন্ডেন্টযুক্ত হয়) মধ্যে খাঁজ প্রকৃতি বিবেচনায়, আমার মনে হয় তোমাদের খাঁজ স্তরের জন্য হওয়া উচিত প্রথম লাইন

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

4
পিএসএস্ট: যদি প্রথম লাইনটি ফাঁকা হয়?
ফ্রোগজ

3

মূল পোস্টারের মতো, আমিও এটি আবিষ্কার করেছিলাম <<-HEREDOC সিনট্যাক্সটি এবং হতাশ হয়েছি যে এটি আচরণ করা উচিত বলে আমি ভেবেছিলাম যে এটি আচরণ করে না।

তবে gsub-s দিয়ে আমার কোড লিটারের পরিবর্তে আমি স্ট্রিং ক্লাসটি বাড়িয়েছি:

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

4
মানকিপ্যাচের জন্য +1 এবং কেবলমাত্র ইনডেন্টিং হোয়াইটস্পেস বাদ দেওয়া, তবে অতিরিক্ত-জটিল বাস্তবায়নের জন্য -1।
ফ্রোগজ

ফোগ্রজের সাথে সম্মত হন, ধারণাটিগতভাবে এটিই সেরা উত্তর, তবে বাস্তবায়ন খুব জটিল
আইনারম্যাগাস

2

দ্রষ্টব্য: @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

নিচের ভোটের জন্য ধন্যবাদ, তবে আমি বিশ্বাস করি যে আমরা এই মন্তব্যটি কেন এড়ানো উচিত সে বিষয়ে একটি মন্তব্য দিয়ে আমরা আরও ভালভাবে উপকৃত হব।
মারিয়াস বাটুক

4
কেবল একটি অনুমান, তবে স্ট্রিং # স্কুইশ সম্ভবত রুবির যথাযথ অংশ নয়, তবে রেলের; যেমন- অ্যাক্টিভ_সপোর্ট ব্যবহার না করে এটি কাজ করবে না।
রেডিওস্পিল

2

অপরটি সহজ মনে রাখার বিকল্পটি হ'ল আনইন্ডেন্ট রত্ন

require 'unindent'

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

2

আমার এমন কিছু ব্যবহার করা দরকার systemযার সাহায্যে আমি লম্বা লম্বা sedকমান্ডগুলি বিভক্ত করতে পারি এবং তারপরে ইনডেন্টেশন এবং নিউলাইনগুলি সরিয়ে ফেলি ...

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

ডিফল্ট আচরণ হ'ল অন্যান্য লাইনের মতো নিউলাইনগুলি স্ট্রিপ না করা।


1

আমি উত্তর সংগ্রহ করেছি এবং এটি পেয়েছি:

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

এটি দুর্দান্ত এসকিউএল উত্পন্ন করে এবং এআর স্কোপগুলির বাইরে যায় না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.