मैं रूबी HEREDOC से प्रमुख व्हाट्सएप चार्ट कैसे निकालूं?


91

मैं एक रूबी 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 के बीच के सभी रिक्त स्थान को छोड़कर। क्या किसी को पता है कि मैं यहाँ क्या गलत कर रहा हूँ?

जवाबों:


143

<<-हियरडॉक के रूप केवल अंत सीमांकक के लिए प्रमुख सफ़ेद ध्यान नहीं देता।

रूबी 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"

रूबी शाब्दिक प्रलेखन से :

सामग्री की प्रत्येक पंक्ति से सबसे कम-इंडेंटेड लाइन का इंडेंटेशन हटा दिया जाएगा। ध्यान दें कि खाली पंक्तियों और लाइनों में केवल शाब्दिक टैब और रिक्त स्थान होते हैं, जो इंडेंटेशन निर्धारित करने के उद्देश्यों के लिए नजरअंदाज कर दिए जाएंगे, लेकिन बच गए टैब और रिक्त स्थान को गैर-इंडेंटेशन वर्ण माना जाता है।


11
मुझे लगता है कि सवाल पूछने के 5 साल बाद भी यह एक प्रासंगिक विषय है। अद्यतन प्रतिक्रिया के लिए धन्यवाद!
क्रिस ड्रेपियर

1
@ChrisDrappier निश्चित नहीं है कि यह संभव है, लेकिन मैं इस प्रश्न के लिए स्वीकृत उत्तर को इस एक में बदलने का सुझाव दूंगा क्योंकि आजकल यह स्पष्ट रूप से समाधान है।
द डेडिसेशनल

123

यदि आप रेल 3.0 या नए का उपयोग कर रहे हैं, तो प्रयास करें #strip_heredocडॉक्स से यह उदाहरण पहली तीन पंक्तियों को बिना किसी इंडेंटेशन के प्रिंट करता है, जबकि अंतिम दो लाइनों को दो-स्थान के स्थान पर बनाए रखता है:

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

प्रलेखन यह भी नोट करता है: "तकनीकी रूप से, यह पूरे स्ट्रिंग में सबसे कम इंडेंटेड लाइन की तलाश करता है, और अग्रणी व्हाट्सएप की उस राशि को निकालता है।"

यहाँ सक्रिय_बिलिटी / core_ext / string / strip.rb से कार्यान्वयन है :

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

और आप परीक्षण / core_ext / string_ext_test.rb में परीक्षण पा सकते हैं ।


2
आप अभी भी रेल 3 के बाहर इसका उपयोग कर सकते हैं!
आइकनोकॉस्ट

3
iconoclast सही है; सिर्फ require "active_support/core_ext/string"पहला
डेविड जे।

2
रूबी 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

इस संस्करण को तब संभालना चाहिए जब पहली पंक्ति बाईं ओर भी सबसे दूर न हो।


1
मैं पूछने के लिए गंदा महसूस करता हूं, लेकिन EOFकेवल के बजाय खुद के डिफ़ॉल्ट व्यवहार को हैक करने के बारे में क्या String?
22

1
निश्चित रूप से EOF का व्यवहार पार्सिंग के दौरान निर्धारित किया जाता है, इसलिए मुझे लगता है कि आप, @patcon क्या सुझाव दे रहे हैं, इसमें रूबी के लिए स्रोत कोड को बदलना होगा, और फिर आपका कोड रूबी के अन्य संस्करणों पर अलग तरह से व्यवहार करेगा।
ईनामार्मग्नस

2
मैं कामना करता हूं कि रूबी के डैश HEREDOC सिंटेक्स ने बैश में अधिक काम किया, फिर हमें यह समस्या नहीं होगी! ( इस बैश उदाहरण देखें )
TrinitronX

प्रो-टिप: इन दोनों में से किसी एक को कंटेंट में खाली लाइनों के साथ आज़माएँ और फिर याद रखें कि \sइसमें न्यूलाइन शामिल हैं।
होरोज

मैंने कोशिश की कि रूबी 2.2 पर और किसी भी समस्या पर ध्यान न दे। आपके लिए क्या ख़ुशी है? ( 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

1
-1 सिर्फ इंडेंटेशन राशि के बजाय सभी प्रमुख व्हाट्सएप को अलग करने के लिए।
फ्रॉग्ज

7
@Phrogz ओपी ने उल्लेख किया कि उसने उम्मीद की थी कि "सभी प्रमुख व्हाट्सएप पात्रों को दबा दें," तो मैंने एक जवाब दिया कि ऐसा किया, साथ ही एक ने केवल रिक्त स्थान नहीं छींटे, न कि टैब, जो कि वह देख रहा था। कई महीनों बाद आ रहा है, जवाब देने के लिए कि ओपी के लिए काम किया है, और अपने स्वयं के प्रतिस्पर्धी जवाब पोस्ट लंगड़ा की तरह है।
ब्रायन कैंपबेल

@BrianCampbell मुझे खेद है कि आप ऐसा महसूस करते हैं; कोई अपराध नहीं था। मुझे आशा है कि आप मुझ पर विश्वास करेंगे जब मैं कहता हूं कि मैं अपने स्वयं के उत्तर के लिए वोट प्राप्त करने के प्रयास में नीच नहीं हूं, लेकिन सिर्फ इसलिए कि मैं इसी तरह की कार्यक्षमता के लिए एक ईमानदार खोज के माध्यम से इस सवाल पर आया था और यहां उत्तर उप-इष्टतम पाया। आप सही हैं कि यह ओपी की सटीक आवश्यकता को हल करता है, लेकिन इतना अधिक-सामान्य समाधान प्रदान करता है जो अधिक कार्यक्षमता प्रदान करता है। मुझे यह भी उम्मीद है कि आप सहमत होंगे कि एक के बाद पोस्ट किए गए उत्तर अभी भी साइट के लिए पूरे मूल्यवान हैं, खासकर यदि वे सुधार की पेशकश करते हैं।
फ्रॉग्ज

4
अंत में, मैं "प्रतिस्पर्धी उत्तर" वाक्यांश को संबोधित करना चाहता था। न तो आप और न ही मैं प्रतियोगिता में होना चाहिए, न ही मुझे विश्वास है कि हम हैं। (हालांकि यदि हम हैं, तो आप इस समय 27.4k प्रतिनिधि के साथ जीत रहे हैं। :) हम व्यक्तिगत रूप से (ओपी) और गुमनाम (Google के माध्यम से आने वाले) दोनों समस्याओं वाले व्यक्तियों की मदद करते हैं। अधिक (मान्य) उत्तर मदद करते हैं। उस नस में, मैं अपने पतन पर पुनर्विचार करता हूं। आप सही कह रहे हैं कि आपका जवाब हानिकारक, भ्रामक या अतिरंजित नहीं था। मैंने अब आपके प्रश्न को सिर्फ इसलिए संपादित किया है कि मैं आपके द्वारा छोड़े गए प्रतिनिधि के 2 अंकों को दे सकूं।
फ्रॉग्ज

1
@Phrogz क्रोधी होने के बारे में क्षमा करें; मेरे पास "-1 के साथ एक समस्या है जो मुझे पसंद नहीं है" उत्तर के लिए उत्तर जो पर्याप्त रूप से ओपी को संबोधित करते हैं। जब पहले से ही उत्कीर्ण या स्वीकृत उत्तर हैं, जो लगभग नहीं, बल्कि काफी हैं, तो आप जो चाहते हैं, वह भविष्य में किसी के लिए अधिक उपयोगी साबित होता है, केवल यह स्पष्ट करने के लिए कि आपको क्या लगता है कि उत्तर टिप्पणी में बेहतर हो सकता है, बल्कि डाउनवोटिंग से। एक अलग उत्तर पोस्ट करना जो बहुत नीचे दिखाई देगा और आमतौर पर किसी और को नहीं देखा जाएगा जिसे समस्या है। यदि जवाब वास्तव में गलत है या भ्रामक है तो मैं केवल अपमानित करता हूं।
ब्रायन कैंपबेल

6

कुछ अन्य उत्तर की खरोज स्तर को खोजने के लिए कम से कम दांतेदार लाइन , और सभी लाइनों से हटाते हैं, लेकिन प्रोग्रामिंग (कि पहली पंक्ति से कम इंडेंट है) में खरोज की प्रकृति को देखते हुए मुझे लगता है कि आप में से खरोज स्तर के लिए दिखना चाहिए पहली पंक्ति

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

1
Psst: क्या होगा यदि पहली पंक्ति रिक्त है?
फ्रॉग्ज

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

3
मंकीपैच के लिए +1 और केवल इंडेंटिंग व्हाट्सएप छीनने के लिए, लेकिन एक अत्यधिक जटिल कार्यान्वयन के लिए -1।
फ्रॉग्ज

फ्रॉग्ज के साथ सहमत, यह वास्तव में वैचारिक रूप से सबसे अच्छा जवाब है, लेकिन कार्यान्वयन बहुत जटिल है
einarmagnus

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

डाउन वोट के लिए धन्यवाद, लेकिन मेरा मानना ​​है कि हम सभी को एक टिप्पणी से बेहतर लाभ होगा जो बताएगा कि इस समाधान से क्यों बचा जाना चाहिए।
मारियस ब्यूटिक

1
बस एक अनुमान है, लेकिन स्ट्रिंग # स्क्विश शायद माणिक का उचित हिस्सा नहीं है, लेकिन रेल का; जब तक यह active_support का उपयोग नहीं करता है।
रेडियोस्पाइल

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

यह उत्कृष्ट SQL उत्पन्न करता है और AR स्कोप से बाहर नहीं जाता है।


यह पढ़ना मुश्किल है।
सेबेस्टियन पाल्मा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.