Разбиение длинных строк по нескольким строкам в Ruby без разрыва строки

221

Мы недавно решили на моей работе гид по рубиновому стилю. Одним из указов является то, что ни одна строка не должна быть шире, чем 80 символов. Поскольку это проект Rails, у нас часто бывают строки, которые немного длиннее - то есть « Пользователь X хотел отправить вам сообщение о Thing Y », которое не всегда укладывается в ограничение в 80 символов.

Я понимаю, что есть три способа иметь длинную строку, охватывающую несколько строк:

  • Heredoc
  • % Q {}
  • Фактическая конкатенация строк.

Тем не менее, все эти случаи в конечном итоге занимают больше вычислительных циклов, что кажется глупым. Конкатенация строк, очевидно, но для HEREDOCи %Qя должен вырезать новые строки, через что-то вроде .gsub(/\n$/, '').

Есть ли чистый синтаксический способ сделать это, что эквивалентно наличию всей строки в одной строке? Цель, очевидно, состоит в том, чтобы не тратить лишних циклов только потому, что я хочу, чтобы мой код был немного более читабельным. (Да, я понимаю, что вы должны сделать этот компромисс много ... но для длины строки это просто кажется глупым.)

Обновление: обратная косая черта не совсем то, что я хочу, потому что вы теряете отступы, что действительно влияет на стиль / читабельность.

Пример:

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

Я нахожу вышеупомянутое немного трудным для чтения.

РЕДАКТИРОВАТЬ : я добавил ответ ниже; три года спустя у нас теперь волнистый наследственный синдром.

chug2k
источник
Это может стоить вашего времени, чтобы выделить эти строки.
Cheezmeister
👎🏼 Неясно, хотите ли вы сохранить \nсимволы новой строки или нет. Верхний ответ не сохраняет их, а ваш ответ сохраняет. Вопрос гласит: «Без удаления новых строк», но в описании говорится: «[...] Я должен удалить новые строки».
Брайан Димас

Ответы:

432

Может быть, это то, что вы ищете?

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

p string # => "line #1line #2line #3"
Jessehz
источник
4
да. да, это довольно прекрасно это на самом деле делает сцепление под капотом? (скрывая +?)
chug2k
13
Я вполне уверен, что это не так; Я пробовал как undef'ing, так и переопределить String # +, и не похоже, что туда что-то отправляют.
Джессехз
Кроме того, расположение строк рядом друг с другом также работает, но это не очень полезно.
Джессехз
3
Мне также нравится решение Эмили. Но по какой-то причине мне удобнее с этим, потому что начальные пробелы в следующих строках могут быть смещены без повторного угадывания.
Амин Ариана
5
Повторное объединение, проверьте ответ Амадана на этот связанный вопрос . Он использует байт-код, чтобы доказать, что он не объединяет строки, а рассматривает их как одну длинную.
Том
55

Вы можете использовать, \чтобы указать, что любая строка Ruby продолжается на следующей строке. Это работает и со строками:

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

puts string.inspect

будет выводить "this is a string that spans lines"

Эмили
источник
11
да. это довольно просто. ну, это, наверное, слишком много, чтобы спросить, но я не могу отступить от следующей строки. было бы идеально, если бы я мог сопоставить его со знаком равенства.
chug2k
5
Примечание: после этой обратной косой черты не должно быть пробелов. Это должен быть последний символ.
Джулиан Манн
3
Смотрите ответ @Jessehz. Чтобы получить правильно отформатированный код с соответствующим отступом, поместите каждую строку в кавычки.
orrd
36

Три года спустя, в Ruby 2.3 теперь есть решение: волнистый наследник.

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

Ссылка на запись в блоге: https://infinum.co/the-capsized-eight/articles/multiline-strings-ruby-2-3-0-the-squiggly-heroc

Отступы строки с наименьшим отступом будут удалены из каждой строки содержимого.

chug2k
источник
29
Для всех, кто интересуется: <<~HEREDOCсохраняет символы новой строки, это только лишние отступы. Напримерline 1\nline 2\nline 3\n
Брайан Димас
1
Удаление новых строк по-прежнему требует дополнительных вычислений, что, как подразумевает OP, нежелательно.
henrebotha
1
@henrebotha Да, но OP сказал более явно, что они хотят «эквивалентно наличию всей строки на одной строке», что не требует никаких новых строк.
Ник
Таким образом, вы прямо заявили в своем вопросе, что вы не хотите использовать heredoc и должны удалить символы новой строки. Ваш ответ здесь использует heredoc и требует той «постобработки», которую вы хотели избежать.
Ламонт
17

У меня была эта проблема, когда я пытаюсь написать очень длинный URL, работает следующее.

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

Обратите внимание, что при формировании строки URL не должно быть никаких новых строк, пробелов. Если вы хотите переводы строк, используйте HEREDOC.

Здесь у вас есть отступ для удобства чтения, простоты модификации, без лишних кавычек и обратной косой черты в каждой строке. Стоимость соединения строк должна быть незначительной.

Зак Сюй
источник
10

Я изменил ответ Зака, так как хотел пробелы и интерполяцию, но не переводы строк, и использовал:

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

где name = 'fred'это производитIt's a nice day "fred" for a walk!

iheggie
источник