Briser de longues chaînes sur plusieurs lignes en Ruby sans supprimer les nouvelles lignes

221

Nous avons récemment décidé à mon travail d'un guide de style rubis. L'un des édits est qu'aucune ligne ne doit dépasser 80 caractères. Comme il s'agit d'un projet Rails, nous avons souvent des chaînes un peu plus longues - c'est-à-dire que «l' utilisateur X voulait vous envoyer un message sur la chose Y » qui ne correspond pas toujours à la limite de 80 caractères.

Je comprends qu'il y a trois façons d'avoir une longue chaîne de caractères sur plusieurs lignes:

  • HEREDOC
  • % Q {}
  • Concaténation de chaîne réelle.

Cependant, tous ces cas finissent par prendre plus de cycles de calcul, ce qui semble idiot. Concaténation de chaîne évidemment, mais pour HEREDOCet %Qje dois supprimer les nouvelles lignes, via quelque chose comme .gsub(/\n$/, '').

Existe-t-il une méthode de syntaxe pure pour ce faire, qui équivaut à avoir simplement la chaîne entière sur une seule ligne? Le but étant évidemment de ne pas passer de cycles supplémentaires juste parce que je veux que mon code soit légèrement plus lisible. (Oui, je me rends compte que vous devez souvent faire ce compromis ... mais pour la longueur des cordes, cela semble tout simplement idiot.)

Mise à jour: les barres obliques inverses ne sont pas exactement ce que je veux, car vous perdez l'indentation, ce qui affecte vraiment le style / la lisibilité.

Exemple:

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

Je trouve ce qui précède un peu difficile à lire.

EDIT : J'ai ajouté une réponse ci-dessous; trois ans plus tard, nous avons maintenant l'hérédoc squiggly.

chug2k
la source
Il peut être utile de prendre en compte ces chaînes.
Cheezmeister
👎🏼 Il est difficile de savoir si vous souhaitez conserver les \ncaractères de nouvelle ligne ou non. La première réponse ne les garde pas, mais votre réponse le fait. La question dit "sans supprimer les retours à la ligne" - mais la description dit "[...] je dois supprimer les retours à la ligne".
Bryan Dimas

Réponses:

432

C'est peut-être ce que vous cherchez?

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

p string # => "line #1line #2line #3"
Jessehz
la source
4
hein. oui, c'est assez parfait. est-ce que ça fait un enchaînement sous le capot? (cacher un +?)
chug2k
13
Je suis assez sûr que ce n'est pas le cas; J'ai essayé à la fois d'annuler et de redéfinir String # + et il ne semble pas que quelque chose soit envoyé là-bas.
Jessehz
En outre, mettre les chaînes les unes à côté des autres sur la même ligne fonctionne également, mais ce n'est pas très utile.
Jessehz
3
J'aime aussi la solution d'Emily. Mais pour une raison quelconque, je suis plus à l'aise avec celui-ci, car les espaces blancs de premier plan sur les lignes suivantes peuvent être indentés sans se remettre en question.
Amin Ariana
5
Re concaténation, consultez la réponse d'Amadan à cette question connexe . Il utilise le bytecode pour prouver qu'il ne s'agit pas de concaténer des chaînes mais de les traiter comme une longue.
Tom Hundt
55

Vous pouvez utiliser \pour indiquer que n'importe quelle ligne de Ruby continue sur la ligne suivante. Cela fonctionne également avec les chaînes:

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

puts string.inspect

affichera "this is a string that spans lines"

Emilie
la source
11
hein. c'est assez simple. eh bien, c'est probablement trop demander, mais je ne peux pas mettre en retrait la ligne suivante. ce serait idéal si je pouvais le faire correspondre avec le signe égal.
chug2k
5
Remarque: vous ne pouvez pas avoir d'espace blanc après cette barre oblique inverse. Ce doit être le dernier caractère.
Julian Mann
3
Voir la réponse de @Jessehz. La façon d'avoir du code bien formaté avec un retrait correct est de mettre chaque ligne entre guillemets.
2017
36

Trois ans plus tard, il existe maintenant une solution dans Ruby 2.3: l'hérédoc squiggly.

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

Lien de l'article de blog: https://infinum.co/the-capsized-eight/articles/multiline-strings-ruby-2-3-0-the-squiggly-heredoc

L'indentation de la ligne la moins indentée sera supprimée de chaque ligne du contenu.

chug2k
la source
29
Pour tous ceux qui se demandent: <<~HEREDOCconserve les caractères de nouvelle ligne, il supprime uniquement l'indentation. Par exempleline 1\nline 2\nline 3\n
Bryan Dimas
1
Cependant, la suppression des nouvelles lignes nécessitera toujours des calculs supplémentaires, ce que le type OP implicite n'était pas souhaitable.
henrebotha
1
@henrebotha Oui, mais OP a déclaré plus explicitement qu'ils voulaient "l'équivalent d'avoir simplement la chaîne entière sur une seule ligne", ce qui ne nécessiterait aucune nouvelle ligne.
Nick
Vous avez donc explicitement déclaré dans votre question que vous ne vouliez pas utiliser un hérédoc et que vous deviez supprimer les nouvelles lignes. Votre réponse ici utilise un hérédoc et requiert le "post-traitement" que vous vouliez éviter.
lamont
17

J'ai eu ce problème lorsque j'essaie d'écrire une URL très longue, les travaux suivants.

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

Notez qu'il ne doit pas y avoir de sauts de ligne ni d'espaces blancs lorsque la chaîne d'URL est formée. Si vous souhaitez des retours à la ligne, utilisez HEREDOC.

Ici, vous avez une indentation pour la lisibilité, la facilité de modification, sans les guillemets et les barres obliques inverses sur chaque ligne. Le coût de la jonction des cordes doit être négligeable.

Zack Xu
la source
10

J'ai modifié la réponse de Zack car je voulais des espaces et de l'interpolation mais pas des retours à la ligne et j'ai utilisé:

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

name = 'fred'cela produitIt's a nice day "fred" for a walk!

iheggie
la source