Aufbrechen langer Zeichenfolgen in mehreren Zeilen in Ruby, ohne Zeilenumbrüche zu entfernen

221

Wir haben uns kürzlich bei meinem Job für einen Ruby Style Guide entschieden. Eines der Erlasse ist, dass keine Zeile breiter als 80 Zeichen sein sollte. Da es sich um ein Rails-Projekt handelt, haben wir häufig etwas längere Zeichenfolgen - dh " Benutzer X wollte Ihnen eine Nachricht zu Thing Y senden ", die nicht immer innerhalb der 80-Zeichen-Stilbeschränkung liegt.

Ich verstehe, dass es drei Möglichkeiten gibt, eine lange Zeichenfolge über mehrere Zeilen zu führen:

  • HEREDOC
  • % Q {}
  • Tatsächliche Verkettung von Zeichenfolgen.

Alle diese Fälle erfordern jedoch mehr Rechenzyklen, was albern erscheint. String-Verkettung natürlich, aber für HEREDOCund %Qich muss die Zeilenumbrüche über so etwas entfernen .gsub(/\n$/, '').

Gibt es eine reine Syntaxmethode, die gleichbedeutend damit ist, dass nur die gesamte Zeichenfolge in einer Zeile steht? Das Ziel ist natürlich, keine zusätzlichen Zyklen zu verbringen, nur weil ich möchte, dass mein Code etwas besser lesbar ist. (Ja, mir ist klar, dass man diesen Kompromiss viel machen muss ... aber für die Saitenlänge scheint das einfach albern.)

Update: Backslashes sind nicht genau das, was ich möchte, da Sie die Einrückung verlieren, was sich wirklich auf den Stil / die Lesbarkeit auswirkt.

Beispiel:

if foo
  string = "this is a \  
string that spans lines"  
end

Ich finde das oben etwas schwer zu lesen.

EDIT : Ich habe unten eine Antwort hinzugefügt; Drei Jahre später haben wir jetzt den schnörkellosen Heredoc.

chug2k
quelle
Es kann sich lohnen, diese Zeichenfolgen herauszufiltern.
Cheezmeister
👎🏼 Es ist unklar, ob Sie \nZeilenumbrüche beibehalten möchten oder nicht. Die Top-Antwort behält sie nicht - Ihre Antwort jedoch. Die Frage lautet "ohne Zeilenumbrüche zu entfernen" - die Beschreibung lautet jedoch "[...] Ich muss die Zeilenumbrüche entfernen."
Bryan Dimas

Antworten:

432

Vielleicht ist es das, wonach Sie suchen?

string = "line #1"\
         "line #2"\
         "line #3"

p string # => "line #1line #2line #3"
Jessehz
quelle
4
huh. Ja, das ist ziemlich perfekt. macht das tatsächlich eine Verkettung unter der Haube? (versteckt ein +?)
chug2k
13
Ich bin mir ziemlich sicher, dass es nicht so ist. Ich habe versucht, String # + zu deaktivieren und neu zu definieren, und es scheint, als würde nichts dorthin gesendet.
Jessehz
Es funktioniert auch, wenn die Zeichenfolgen nebeneinander in derselben Zeile stehen, aber das ist nicht sehr nützlich.
Jessehz
3
Ich mag auch Emilys Lösung. Aber aus irgendeinem Grund fühle ich mich mit diesem wohler, weil führende Leerzeichen in den folgenden Zeilen eingerückt werden können, ohne sich selbst zu überlegen.
Amin Ariana
5
Lesen Sie zur Verkettung die Antwort von Amadan auf diese verwandte Frage . Er verwendet den Bytecode, um zu beweisen, dass er Zeichenfolgen nicht verkettet, sondern als eine lange behandelt.
Tom Hundt
55

Sie können \damit angeben, dass eine beliebige Ruby-Zeile in der nächsten Zeile fortgesetzt wird. Dies funktioniert auch mit Strings:

string = "this is a \
string that spans lines"

puts string.inspect

wird ausgegeben "this is a string that spans lines"

Emily
quelle
11
huh. das ist ziemlich einfach. Nun, es ist wahrscheinlich zu viel verlangt, aber ich kann die nächste Zeile nicht einrücken. Es wäre ideal, wenn ich es mit dem Gleichheitszeichen abgleichen könnte.
Chug2k
5
Hinweis: Nach diesem Backslash können keine Leerzeichen mehr vorhanden sein. Es muss das letzte Zeichen sein.
Julian Mann
3
Siehe die Antwort von @Jessehz. Der Weg, um gut formatierten Code mit korrektem Einzug zu erhalten, besteht darin, jede Zeile in Anführungszeichen zu setzen.
oder
36

Drei Jahre später gibt es in Ruby 2.3 eine Lösung: Der schnörkellose Heredoc.

class Subscription
  def warning_message
    <<~HEREDOC
      Subscription expiring soon!
      Your free trial will expire in #{days_until_expiration} days.
      Please update your billing information.
    HEREDOC
  end
end

Link zum Blog-Beitrag: https://infinum.co/the-capsized-eight/articles/multiline-strings-ruby-2-3-0-the-squiggly-heredoc

Der Einzug der am wenigsten eingerückten Zeile wird aus jeder Zeile des Inhalts entfernt.

chug2k
quelle
29
Für alle anderen, die sich fragen: <<~HEREDOCBehält die Zeilenumbruchzeichen bei, es werden nur die Einrückungen entfernt. ZBline 1\nline 2\nline 3\n
Bryan Dimas
1
Das Entfernen von Zeilenumbrüchen erfordert jedoch noch zusätzliche Berechnungen, was die implizierte OP-Art nicht wünschenswert war.
Henrebotha
1
@henrebotha Ja, aber OP sagte expliziter, dass sie das "Äquivalent dazu haben wollen, nur die gesamte Zeichenfolge in einer Zeile zu haben", was keine neuen Zeilen erfordern würde.
Nick
Sie haben in Ihrer Frage also ausdrücklich angegeben, dass Sie keinen Heredoc verwenden möchten und die Zeilenumbrüche entfernen müssen. Ihre Antwort hier verwendet einen Heredoc und erfordert die "Nachbearbeitung", die Sie vermeiden wollten.
Lamont
17

Ich hatte dieses Problem, als ich versuchte, eine sehr lange URL zu schreiben. Das Folgende funktioniert.

image_url = %w(
    http://minio.127.0.0.1.xip.io:9000/
    bucket29/docs/b7cfab0e-0119-452c-b262-1b78e3fccf38/
    28ed3774-b234-4de2-9a11-7d657707f79c?
    X-Amz-Algorithm=AWS4-HMAC-SHA256&
    X-Amz-Credential=ABABABABABABABABA
    %2Fus-east-1%2Fs3%2Faws4_request&
    X-Amz-Date=20170702T000940Z&
    X-Amz-Expires=3600&X-Amz-SignedHeaders=host&
    X-Amz-Signature=ABABABABABABABABABABAB
    ABABABABABABABABABABABABABABABABABABA
).join

Beachten Sie, dass beim Erstellen der URL-Zeichenfolge keine Zeilenumbrüche oder Leerzeichen vorhanden sein dürfen. Wenn Sie Zeilenumbrüche wünschen, verwenden Sie HEREDOC.

Hier haben Sie Einrückung für Lesbarkeit, einfache Änderung, ohne die umständlichen Anführungszeichen und Backslashes in jeder Zeile. Die Kosten für das Verbinden der Saiten sollten vernachlässigbar sein.

Zack Xu
quelle
10

Ich habe Zacks Antwort geändert, da ich Leerzeichen und Interpolation, aber keine Zeilenumbrüche wollte, und verwendet:

%W[
  It's a nice day "#{name}"
  for a walk!
].join(' ')

wo name = 'fred'dies produziertIt's a nice day "fred" for a walk!

iheggie
quelle