Rozbijanie długich łańcuchów na wielu liniach w Rubim bez usuwania nowych linii


221

Niedawno w mojej pracy zdecydowaliśmy się na przewodnik w stylu ruby. Jednym z edyktów jest to, że żaden wiersz nie powinien być szerszy niż 80 znaków. Ponieważ jest to projekt Railsowy, często mamy łańcuchy, które są nieco dłuższe - tzn. „ Użytkownik X chciał wysłać Ci wiadomość o Rzecz Y ”, która nie zawsze mieści się w limicie 80 znaków.

Rozumiem, że istnieją trzy sposoby, aby długi ciąg obejmował wiele linii:

  • HEREDOC
  • % Q {}
  • Rzeczywista konkatenacja łańcucha.

Jednak wszystkie te przypadki wymagają więcej cykli obliczeniowych, co wydaje się głupie. Oczywiście łączenie łańcuchów, ale dla HEREDOCi %Qmuszę usunąć nowe linie za pomocą czegoś takiego .gsub(/\n$/, '').

Czy jest na to czysty sposób składni, który jest równoważny po prostu umieszczeniu całego łańcucha w jednym wierszu? Celem jest oczywiście, aby nie spędzać żadnych dodatkowych cykli tylko dlatego, że chcę, aby mój kod był nieco bardziej czytelny. (Tak, zdaję sobie sprawę z tego, że trzeba to zrobić dużo ... ale jeśli chodzi o długość struny, to po prostu wydaje się głupie.)

Aktualizacja: Odwrotne ukośniki nie są dokładnie tym, czego chcę, ponieważ tracisz wcięcia, co naprawdę wpływa na styl / czytelność.

Przykład:

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

Uważam, że powyższe jest trochę trudne do odczytania.

EDYCJA : poniżej dodałem odpowiedź; trzy lata później mamy teraz zawiłego heredoka.


Uwzględnienie tych ciągów może być warte poświęcenia czasu.
Cheezmeister


👎🏼 Nie jest jasne, czy chcesz zachować \nznaki nowej linii, czy nie. Najlepsza odpowiedź ich nie zachowuje, a jednak twoja odpowiedź tak. Pytanie brzmi „bez usuwania nowych linii” - ale opis mówi „[...] Muszę usunąć nowe linie”.
Bryan Dimas

Odpowiedzi:


432

Może tego właśnie szukasz?

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

p string # => "line #1line #2line #3"

4
hę tak, to całkiem idealne. czy to faktycznie robi konkatenat pod maską? (ukrywanie
znaku

13
Jestem całkiem pewien, że tak nie jest; Próbowałem zarówno undef'ing, jak i przedefiniować String # + i nie wydaje się, aby cokolwiek tam było wysyłane.
Jessehz

Również umieszczanie ciągów obok siebie w tej samej linii również działa, ale to nie jest bardzo przydatne.
Jessehz

3
Podoba mi się również rozwiązanie Emily. Ale z jakiegoś powodu czuję się bardziej komfortowo z tym, ponieważ wiodące białe znaki w kolejnych wierszach można wciąć bez zgadywania.
Amin Ariana,

5
Jeśli chodzi o konkatenację, sprawdź odpowiedź Amadana na to powiązane pytanie . Używa kodu bajtowego, aby udowodnić, że nie łączy łańcuchów, lecz traktuje je jako jeden długi.
Tom Hundt,

55

Możesz użyć, \aby wskazać, że dowolny wiersz Ruby kontynuuje w następnym wierszu. Działa to również z ciągami:

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

puts string.inspect

wyjdzie "this is a string that spans lines"


11
hę to jest dość proste. Cóż, prawdopodobnie jest to zbyt wiele, ale nie mogę wciąć następnego wiersza. byłoby idealnie, gdybym mógł dopasować to do znaku równości.
chug2k

5
Uwaga: po tym odwrotnym ukośniku nie możesz mieć żadnych białych znaków. To musi być ostatnia postać.
Julian Mann,

3
Zobacz odpowiedź @Jessehz. Sposób na ładnie sformatowany kod z odpowiednim wcięciem polega na umieszczeniu każdego wiersza w cudzysłowie.
2017 r. O

36

Trzy lata później jest teraz rozwiązanie w Ruby 2.3: Squiggly 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 do posta na blogu: https://infinum.co/the-capsized-eight/articles/multiline-strings-ruby-2-3-0-the-squiggly-heredoc

Wcięcie najmniej wciętego wiersza zostanie usunięte z każdego wiersza treści.


29
Dla każdego, kto zastanawia się: <<~HEREDOCzachowuje znaki nowego wiersza, usuwa tylko wcięcia. Np.line 1\nline 2\nline 3\n
Bryan Dimas

1
Usuwanie nowych linii nadal będzie wymagało dodatkowych obliczeń, co sugerowane przez OP nie było pożądane.
henrebotha

1
@henrebotha Tak, ale OP powiedział bardziej wyraźnie, że chcą „ekwiwalentu posiadania całego łańcucha w jednym wierszu”, co nie wymagałoby żadnych nowych znaków.
Nick

Więc wyraźnie powiedziałeś w swoim pytaniu, że nie chcesz używać heredoka i musisz usunąć nowe linie. Twoja odpowiedź tutaj wykorzystuje heredoc i wymaga tego „przetwarzania końcowego”, którego chciałeś uniknąć.
lamont

17

Miałem ten problem, kiedy próbowałem napisać bardzo długi adres URL, następujące prace.

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

Uwaga: podczas tworzenia ciągu adresu URL nie może być żadnych nowych linii, białych znaków. Jeśli chcesz nowego wiersza, skorzystaj z HEREDOC.

Tutaj masz wcięcie dla czytelności, łatwości modyfikacji, bez zbędnych cytatów i ukośników w każdej linii. Koszt połączenia ciągów powinien być znikomy.


10

Zmodyfikowałem odpowiedź Zacka, ponieważ chciałem spacji i interpolacji, ale nie nowych linii i użyłem:

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

gdzie name = 'fred'to produkujeIt's a nice day "fred" for a walk!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.