Ruby: Kan ik een reeks van meerdere regels schrijven zonder aaneenschakeling?

Is er een manier om dit er een beetje beter uit te laten zien?

conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7 ' +
          'from table1, table2, table3, etc, etc, etc, etc, etc, ' +
          'where etc etc etc etc etc etc etc etc etc etc etc etc etc'

Zoals, is er een manier om aaneenschakeling te impliceren?


Antwoord 1, autoriteit 100%

Er zijn stukjes in dit antwoord die me hebben geholpen te krijgen wat ik nodig had (eenvoudige aaneenschakeling van meerdere regels ZONDER extra witruimte), maar aangezien geen van de daadwerkelijke antwoorden het had, compileer ik ze hier:

str = 'this is a multi-line string'\
  ' using implicit concatenation'\
  ' to prevent spare \n\'s'
=> "this is a multi-line string using implicit concatenation to eliminate spare
\\n's"

Als bonus is hier een versie met grappige HEREDOC-syntaxis (via deze link):

p <<END_SQL.gsub(/\s+/, " ").strip
SELECT * FROM     users
         ORDER BY users.id DESC
END_SQL
# >> "SELECT * FROM users ORDER BY users.id DESC"

Dit laatste zou vooral voor situaties zijn die meer flexibiliteit in de verwerking vereisten. Persoonlijk vind ik het niet leuk, het zet de verwerking op een rare plek w.r.t. de string (d.w.z. ervoor, maar met gebruik van instance-methoden die meestal daarna komen), maar hij is er. Houd er rekening mee dat als u de laatste END_SQLidentifier laat inspringen (wat gebruikelijk is, aangezien dit waarschijnlijk in een functie of module zit), u de afgebroken syntaxis moet gebruiken (dat wil zeggen, p <<-END_SQLin plaats van p <<END_SQL). Anders zorgt de inspringende witruimte ervoor dat de identifier wordt geïnterpreteerd als een voortzetting van de string.

Dit scheelt niet veel typen, maar het ziet er voor mij leuker uit dan het gebruik van +-tekens.

Ook (ik zeg in een bewerking, enkele jaren later), als je Ruby 2.3+ gebruikt, de operator <<~ is ook beschikbaar, waardoor extra inspringing uit de laatste tekenreeks wordt verwijderd. In dat geval zou u de aanroep .gsubmoeten kunnen verwijderen (hoewel dit kan afhangen van zowel de begininspringing als uw uiteindelijke behoeften).

EDIT: Nog een toevoegen:

p %{
SELECT * FROM     users
         ORDER BY users.id DESC
}.gsub(/\s+/, " ").strip
# >> "SELECT * FROM users ORDER BY users.id DESC"

Antwoord 2, autoriteit 31%

In ruby 2.0 kun je nu gewoon %

. gebruiken

Bijvoorbeeld:

   SQL = %{
      SELECT user, name
      FROM users
      WHERE users.id = #{var}
      LIMIT #{var2}
    }

Antwoord 3, autoriteit 27%

Ja, als u het niet erg vindt dat er extra nieuwe regels worden ingevoegd:

conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7
            from table1, table2, table3, etc, etc, etc, etc, etc,
            where etc etc etc etc etc etc etc etc etc etc etc etc etc'

U kunt ook een Heredoc :

conn.exec <<-eos
   select attr1, attr2, attr3, attr4, attr5, attr6, attr7
   from table1, table2, table3, etc, etc, etc, etc, etc,
   where etc etc etc etc etc etc etc etc etc etc etc etc etc
eos

Antwoord 4, Autoriteit 8%

Er zijn meerdere syntaxis voor multi-line snaren zoals je al hebt gelezen. Mijn favoriet is perl-stijl:

conn.exec %q{select attr1, attr2, attr3, attr4, attr5, attr6, attr7
      from table1, table2, table3, etc, etc, etc, etc, etc,
      where etc etc etc etc etc etc etc etc etc etc etc etc etc}

De multi-line-tekenreeks begint met% q, gevolgd door een {, [of (, en vervolgens beëindigd door het overeenkomstige omgekeerde teken.% Q staat geen interpolatie toe;% Q doet dit, zodat u dingen als deze kunt schrijven:

conn.exec %Q{select attr1, attr2, attr3, attr4, attr5, attr6, attr7
      from #{table_names},
      where etc etc etc etc etc etc etc etc etc etc etc etc etc}

Ik heb eigenlijk geen idee hoe deze soorten multi-line snaren worden genoemd, dus laten we ze gewoon perl multilines noemen.

Merk echter op dat of u PERL-multilines of heredocs gebruikt als Mark en Peter hebben gesuggereerd, u eindigt met mogelijk onnodige witvakken. Zowel in mijn voorbeelden als hun voorbeelden, de “van” en “waar” lijnen leidende witruimtes bevatten vanwege hun inkeping in de code. Als deze witruimte niet gewenst is, moet u aaneengeschakelde snaren gebruiken zoals u nu doet.


Antwoord 5, Autoriteit 5%

is soms de moeite waard om nieuwe lijntekens te verwijderen \nzoals:

conn.exec <<-eos.squish
 select attr1, attr2, attr3, attr4, attr5, attr6, attr7
 from table1, table2, table3, etc, etc, etc, etc, etc,
 where etc etc etc etc etc etc etc etc etc etc etc etc etc
eos

Antwoord 6, Autoriteit 4%

U kunt ook dubbele aanhalingstekens gebruiken

x = """
this is 
a multiline
string
"""
2.3.3 :012 > x
 => "\nthis is\na multiline\nstring\n"

Indien nodig om de regel te verwijderen “\ n” Gebruik backslash “\” aan het einde van elke regel


Antwoord 7, Autoriteit 2%

Andere opties:

#multi line string
multiline_string = <<EOM
This is a very long string
that contains interpolation
like #{4 + 5} \n\n
EOM
puts multiline_string
#another option for multiline string
message = <<-EOF
asdfasdfsador #{2+2} this month.
asdfadsfasdfadsfad.
EOF
puts message

Antwoord 8, Autoriteit 2%

De kronkelende HEREDOC<<~is wat u zoekt als u een tekenreeks met meerdere regels wilt definiëren met nieuwe regels en de juiste inspringing( beschikbaar sinds Ruby 2.3):

conn.exec <<~EOS
            select attr1, attr2, attr3, attr4, attr5, attr6, attr7
            from table1, table2, table3, etc, etc, etc, etc, etc
            where etc etc etc etc etc etc etc etc etc etc etc etc etc
          EOS
# -> "select...\nfrom...\nwhere..."

Als de juiste inspringing geen probleem is, dan kunnen enkele en dubbele aanhalingstekensmeerdere regels in Ruby omspannen:

conn.exec "select attr1, attr2, attr3, attr4, attr5, attr6, attr7 
           from table1, table2, table3, etc, etc, etc, etc, etc, 
           where etc etc etc etc etc etc etc etc etc etc etc etc etc"    
# -> "select...\n           from...\n           where..."

Als enkele of dubbele aanhalingstekens omslachtig zijn omdat er veel escapes nodig zijn, dan is de percentage letterlijke notatie%de meest flexibele oplossing:

conn.exec %(select attr1, attr2, attr3, attr4, attr5, attr6, attr7
            from table1, table2, table3, etc, etc, etc, etc, etc
            where (ProductLine = 'R' OR ProductLine = "S") AND Country = "...")
# -> "select...\n            from...\n            where..."

Als het de bedoeling is om de nieuwe regels te vermijden (die zowel de kronkelige HEREDOC, aanhalingstekens als de letterlijke procenttekenreeks zullen veroorzaken), dan kan een voortzetting van de regelworden gebruikt door een backslash \als het laatste niet-spatieteken in een regel. Dit zet de regel voort en zorgt ervoor dat Ruby de strings rug aan rug samenvoegt (pas op voor die spaties binnen de string tussen aanhalingstekens):

conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7 ' \
          'from table1, table2, table3, etc, etc, etc, etc, etc, ' \
          'where etc etc etc etc etc etc etc etc etc etc etc etc etc'
# -> "select...from...where..."

Als je Rails gebruikt, String.squishzal de reeks van voorloop- en volgspaties verwijderen en alle opeenvolgende witruimten (nieuwe regels, tabbladen en alles) samenvouwen tot één enkele spatie:

conn.exec "select attr1, attr2, attr3, attr4, attr5, attr6, attr7 
           from table1, table2, table3, etc, etc, etc, etc, etc, 
           where etc etc etc etc etc etc etc etc etc etc etc etc etc".squish
# -> "select...attr7 from...etc, where..."

Meer details:

Ruby HEREDOC-syntaxis

De Here Document Notation for Stringsis een manier om lange blokken tekst inline in code aan te duiden. Het wordt gestart door <<gevolgd door een door de gebruiker gedefinieerde String (de End of String-terminator). Alle volgende regels worden aaneengeschakeld totdat de End of String-terminator wordt gevonden aan het hele beginvan een regel:

puts <<HEREDOC 
Text Text Text Text
Bla Bla
HEREDOC
# -> "Text Text Text Text\nBlaBla"

Het einde van de string-terminator kan vrij worden gekozen, maar het is gebruikelijk om iets als “EOS” (einde van het string) te gebruiken of iets dat overeenkomt met het domein van de string, zoals “SQL”.

Heredoc ondersteunt interpolatie Standaard of wanneer de EOS-terminator dubbel is vermeld:

price = 10
print <<"EOS"  # comments can be put here
1.) The price is #{price}.
EOS
# -> "1.) The price is 10."

Interpolatie kan worden uitgeschakeld als de EOS-terminator één is vermeld:

print <<'EOS' # Disabled interpolation
3.) The price is #{price}.
EOS
# -> "3.) The price is #{price}."

Een belangrijke beperking van de <<HEREDOCis dat het einde van het string-terminator aan het begin van de regel moet zijn:

 puts <<EOS 
    def foo
      print "foo"
    end
  EOS
EOS
#-> "....def foo\n......print "foo"\n....end\n..EOS"

Om dit te ronden, is de <<-SYNTAX gemaakt. Hiermee kan de EOS-terminator ingesprongen zijn om de code er leuker uit te zien. De lijnen tussen de <<-en EOS Terminator worden nog steeds gebruikt in hun volledige uitbreiding, inclusief alle inspringing:

def printExample
  puts <<-EOS # Use <<- to indent End of String terminator
    def foo
      print "foo"
    end
  EOS
end
# -> "....def foo\n......print "foo"\n....end"

Sinds Ruby 2.3 hebben we nu de kronkelige HEREDOC <<~die voorloopspaties verwijdert:

puts <<~EOS # Use the squiggly HEREDOC <<~ to remove leading whitespace (since Ruby 2.3!)
  def foo
    print "foo"
  end
EOS
# -> "def foo\n..print "foo"\nend"

Lege regels en regels die alleen tabs en spatie bevatten, worden genegeerd door <<~

puts <<~EOS.inspect 
  Hello
    World!
EOS
#-> "Hello\n..World!"

Als zowel tabs als spaties worden gebruikt, worden tabs beschouwd als gelijk aan 8 spaties.
Als de minst ingesprongen regel zich in het midden van een tabblad bevindt, wordt dit tabblad niet verwijderd.

puts <<~EOS.inspect
<tab>One Tab
<space><space>Two Spaces
EOS
# -> "\tOne Tab\nTwoSpaces"

HEREDOC kan gekke dingen doen, zoals het uitvoeren van commando’s met backticks:

puts <<`EOC`            
echo #{price}
echo #{price * 2}
EOC

HEREDOC Stringdefinities kunnen worden “gestapeld”, wat betekent dat de eerste EOS-terminator (EOSFOO hieronder) de eerste string beëindigt en de tweede start (EOSBAR hieronder):

print <<EOSFOO, <<EOSBAR    # you can stack them
I said foo.
EOSFOO
I said bar.
EOSBAR

Ik denk niet dat iemand het ooit als zodanig zou gebruiken, maar de <<EOSis eigenlijk gewoon een letterlijke tekenreeks en kan overal worden geplaatst waar een tekenreeks normaal gesproken kan worden geplaatst:

p>

def func(a,b,c)
  puts a
  puts b
  puts c
end
func(<<THIS, 23, <<THAT) 
Here's a line
or two.
THIS
and here's another.
THAT

Als je geen Ruby 2.3 hebt, maar Rails >=3.0, dan kun je String.strip_heredocgebruiken, wat hetzelfde doet als <<~

# File activesupport/lib/active_support/core_ext/string/strip.rb, line 22
class String
  def strip_heredoc
    gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
  end
end
puts <<-USAGE.strip_heredoc # If no Ruby 2.3, but Rails >= 3.0
  This command does such and such.
  Supported options are:
    -h         This message
    ...
USAGE

Problemen oplossen

Als je fouten ziet wanneer Ruby je bestand ontleedt, dan heb je hoogstwaarschijnlijk extra voorloop- of volgspaties met een HEREDOC of extra volgspaties met een kronkelige HEREDOC. Bijvoorbeeld:

Wat je ziet:

   database_yml = <<~EOS
      production:
        database: #{fetch(:user)}
        adapter: postgresql
        pool: 5
        timeout: 5000
    EOS  

Wat Ruby je vertelt:

SyntaxError: .../sample.rb:xx: can't find string "EOS" anywhere before EOF
...sample.rb:xx: syntax error, unexpected end-of-input, expecting `end'

Wat is er fout:

Zoek de extra spaties na de beëindigende EOS.

Percentage letterlijke tekenreeksen

Zie RubyDocvoor het gebruik van het procentteken gevolgd door een tekenreeks tussen haakjes, zoals een %(...), %[...], %{...}, enz. of een paar niet-alfanumerieke tekens zoals %+...+

Laatste woorden

Als laatste, om het antwoord te krijgen op de oorspronkelijke vraag “Is er een manier om aaneenschakeling te impliceren?”
antwoordde: Ruby impliceert altijd aaneenschakeling als twee strings (enkele en dubbele aanhalingstekens) rug aan rug worden gevonden:

puts "select..." 'from table...' "where..."
# -> "select...from table...where..."

Het voorbehoud is dat dit niet werkt over regeleinden heen, omdat Ruby een einde-instructie interpreteert en de opeenvolgende regel van alleen strings op een regel niets doet.


Antwoord 9, autoriteit 2%

conn.exec = <<eos
  select attr1, attr2, attr3, attr4, attr5, attr6, attr7
  from table1, table2, table3, etc, etc, etc, etc, etc,
  where etc etc etc etc etc etc etc etc etc etc etc etc etc
eos

Antwoord 10, autoriteit 2%

Onlangs met de nieuwe functies in Ruby 2.3 kun je met de nieuwe squiggly HEREDOConze multiline-strings op een mooie manier schrijven met een minimale verandering, dus gebruik dit in combinatie met de .squish(als je rails gebruikt) laat je op een leuke manier multiline schrijven!
als je alleen ruby gebruikt, kun je een <<~SQL.split.join(" ")doen, wat bijnade hetzelfde

[1] pry(main)> <<~SQL.squish
[1] pry(main)*   select attr1, attr2, attr3, attr4, attr5, attr6, attr7
[1] pry(main)*   from table1, table2, table3, etc, etc, etc, etc, etc,
[1] pry(main)*   where etc etc etc etc etc etc etc etc etc etc etc etc etc
[1] pry(main)* SQL
=> "select attr1, attr2, attr3, attr4, attr5, attr6, attr7 from table1, table2, table3, etc, etc, etc, etc, etc, where etc etc etc etc etc etc etc etc etc etc etc etc etc"

ref: https ://infinum.co/the-capsized-eight/multiline-strings-ruby-2-3-0-the-squiggly-heredoc


Antwoord 11

Om te voorkomen dat de haakjes voor elke regel worden gesloten, kunt u eenvoudig dubbele aanhalingstekens met een backslash gebruiken om aan de nieuwe regel te ontsnappen:

"select attr1, attr2, attr3, attr4, attr5, attr6, attr7 \
from table1, table2, table3, etc, etc, etc, etc, etc, \
where etc etc etc etc etc etc etc etc etc etc etc etc etc"

Antwoord 12

conn.exec 'select attr1, attr2, attr3, attr4, attr5, attr6, attr7 ' <<
        'from table1, table2, table3, etc, etc, etc, etc, etc, ' <<
        'where etc etc etc etc etc etc etc etc etc etc etc etc etc'

<< is de aaneenschakelingsoperator voor strings


Antwoord 13

Als u nietextra spaties en nieuwe regels vindt, kunt u gebruik maken van

conn.exec %w{select attr1, attr2, attr3, attr4, attr5, attr6, attr7
  from table1, table2, table3, etc, etc, etc, etc, etc,
  where etc etc etc etc etc etc etc etc etc etc etc etc etc} * ' '

(gebruik% w voor geïnterpoleerde snaren)


Antwoord 14

conn.exec [
  "select attr1, attr2, attr3, ...",
  "from table1, table2, table3, ...",
  "where ..."
].join(' ')

Deze suggestie heeft het voordeel hier-documenten en lange snaren die auto-indenters elk deel van de string op de juiste manier kunnen inspringen. Maar het komt op een efficiëntiekosten.


Antwoord 15

Elegant antwoord vandaag:

<<~TEXT
Hi #{user.name}, 
Thanks for raising the flag, we're always happy to help you.
Your issue will be resolved within 2 hours.
Please be patient!
Thanks again,
Team #{user.organization.name}
TEXT

Er is een verschil in <<-TEXTEN <<~TEXT, de voormalige behoudt de spatiëring in blok en laatstgenoemden niet.

Er zijn ook andere opties.
Zoals aaneenschakeling etc. Maar deze is in het algemeen logischer.

Als ik hier ongelijk heb, laat het me weten hoe …


Antwoord 16

zoals jij, ik was ook op zoek naar een oplossing die geen newlines omvat. (Hoewel ze mogelijk veilig zijn in SQL, ze zijn niet veilig in mijn geval en heb ik een groot blok tekst om mee om te gaan)

Dit is misschien wel zo lelijk, maar je kunt backslash-escape-newlines in een hereedoc backlash om ze uit de resulterende tekenreeks te laten weglopen:

conn.exec <<~END_OF_INPUT
    select attr1, attr2, attr3, attr4, attr5, attr6, attr7 \
    from table1, table2, table3, etc, etc, etc, etc, etc, \
    where etc etc etc etc etc etc etc etc etc etc etc etc etc
  END_OF_INPUT

Houd er rekening mee dat u dit niet kunt betalen zonder interpolatie (I.E. <<~'END_OF_INPUT'), dus wees voorzichtig. #{expressions}worden hier geëvalueerd, terwijl ze niet in je originele code staan. A. Wilsons antwoordis om die reden misschien beter.

Other episodes