web-dev-qa-db-fra.com

Comment briser les longues lignes de Ruby

Je reçois toujours de grandes lignes de code en haut de mon Rails models. Je recherche des suggestions pour la meilleure façon de les casser avec la norme Ruby style. Par exemple, une ligne que je regarde maintenant est la suivante:

delegate :occupation, :location, :picture_url, :homepage_url, :headline, :full_name, :to => :profile, :prefix => true, :allow_nil => true

Quel est le style conventionnel pour rompre ces longues lignes d'appel de méthode?

37
Matthew

Quelque chose dans le sens de:

delegate :occupation, :location, :picture_url, 
         :homepage_url, :headline, :full_name, 
         :to => :profile, :prefix => true, :allow_nil => true

Ou si vous souhaitez mettre en surbrillance l'option de hachage (une chose raisonnable):

delegate :occupation, :location, :picture_url, 
         :homepage_url, :headline, :full_name, 
     :to => :profile, :prefix => true, :allow_nil => true

L'idée de laisser tout cela sur une seule ligne me semble être une idée craptique, cela signifie que vous devez faire défiler un montant arbitraire afin de voir ce qui est délégué. Ew.

J'alignerais probablement un peu les choses aussi, peut-être par ordre alphabétique.

delegate :full_name, :headline,   :homepage_url,
         :location,  :occupation, :picture_url,
     :to => :profile, :prefix => true, :allow_nil => true

Si le fichier n'avait pas beaucoup/aucun autre contenu substantiel, je pourrais mettre chaque symbole de méthode sur sa propre ligne, juste pour faciliter l'édition. Dans un fichier plus grand, je ne voudrais pas prendre de la place pour ça.

Non pas que je pense à ce genre de choses.

Edit Je suppose que je fais: /

Ces jours-ci, je pourrais regrouper les méthodes déléguées par "similitude", à peu près:

delegate :full_name, :headline,
         :location,  :occupation,
         :homepage_url, picture_url,
     to: :profile, prefix: true, allow_nil: true

Mon jury s'est accroché à la syntaxe de hachage 1.9 lorsque la valeur est également un symbole; Je pense que ça a l'air drôle. Je ne sais pas non plus où je le mettrais en retrait - je pourrais le perdre de toute façon lors d'un reformatage IDE, mais j'aime un peu comment il se présente ci-dessus si j'utilise la nouvelle syntaxe.

18
Dave Newton

La réponse courte est cela dépend .

Les bases

Pour commencer, vous pouvez enregistrer quelques caractères en utilisant la "nouvelle" Ruby syntaxe de hachage:

result = very_long_method_name(something: 1, user: user, flange_factor: 1.34)

vs.

result = very_long_method_name(:something => 1, :user => user, :flange_factor => 1.34)

Hash/Arrays

Parfois, vous devez initialiser un tableau ou un hachage, en particulier pour les hachages, il est agréable de les écrire de cette façon:

args = {
  first_name: "Aldo",
  email: "[email protected]",
  age: Float::INFINITY
}

Le même hachage sur la même ligne serait (pas comme Nice):

args = {first_name: "Aldo", email: "[email protected]", age: Float::INFINITY}

Divers appels de méthode

Certaines méthodes nécessitent de nombreux paramètres ou ces paramètres ont des noms longs:

%table
  %thead
    %th
      %td= t("first_name", scope: "activemodel.lazy_model.not_so_active_model", some_interpolation_argument: "Mr.", suffix: "(Jr.)")

Dans ce cas, je l'écrirais probablement de cette façon:

%table
  %thead
    %th
      %td= t("first_name",
             scope: "activemodel.lazy_model.not_so_active_model",
             some_interpolation_argument: "Mr.",
             suffix: "(Jr.)")

Ce n'est toujours pas très beau mais je suppose que c'est moins moche.

class person < ActiveRecord::Base
  validates :n_cars, numericality: {
                       only_integer: true,
                       greater_than: 2,
                       odd: true,
                       message: t("greater_than_2_and_odd",
                                  scope: "activerecord.errors.messages")
                     }
end

Encore une fois, ce n'est pas le plus beau code du monde mais il a une sorte de structure.

De plus, vous pouvez parfois utiliser des variables pour séparer les lignes. Ce n'est qu'un exemple, mais en gros, vous nommez des blocs de choses (et parfois après cela, vous vous rendez compte que vous pouvez réellement déplacer ce bloc dans une méthode)

class person < ActiveRecord::Base
  NUMERICALITY_OPTS = {
    only_integer: true,
    greater_than: 2,
    odd: true,
    message: t("greater_than_2_and_odd", scope: "activerecord.errors.messages")
  }
  validates :n_cars, numericality: NUMERICALITY_OPTS
end

Blocs

En parlant de blocs (fermetures):

User.all.map { |user| user.method_name }

peut être écrit comme ceci:

User.all.map(&:method_name)

Si vous avez des blocs appropriés, essayez d'utiliser do-end au lieu d'accolades:

nicotine_level = User.all.map do |user|
  user.smoker? ? (user.age * 12.34) : 0.1234
end

Conditionnel

N'utilisez pas l'opérateur ternaire if pour des choses complexes:

nicotine_level = user.smoker? ? (user.age * 1.234 + user.other_method) : ((user.age - 123 + user.flange_factor) * 0)

if user.smoker?
  nicotine_level = user.age * 1.234 + user.other_method
else
  nicotine_level = (user.age - 123 + user.flange_factor) * 0
end

Si vous avez des instructions if complexes comme celle-ci:

if user.vegetarian? && !user.smoker? && (user.age < 25) && (user.n_girlfriends == 0) && (user.first_name =~ /(A|Z)[0-1]+/)
end

Il vaut probablement mieux déplacer les choses dans les méthodes et rendre les choses non seulement plus courtes mais aussi lisibles:

if user.healthy? && user.has_a_weird_name?
  # Do something
end

# in User
def healthy?
  vegetarian? && !smoker? && (age < 25) && (n_girlfriends == 0)
end

def user.has_a_weird_name?
  user.first_name =~ /(A|Z)[0-1]+/
end

Cordes longues

Heredoc est votre ami ... J'ai toujours besoin de google pour obtenir la bonne syntaxe, mais une fois que vous avez bien fait, cela rend certaines choses plus agréables à lire:

execute <<-SQL
  UPDATE people
  SET smoker = 0
  OK, this is a very bad example.
SQL

Requêtes

J'ai tendance à faire de cette façon pour les cas simples:

# Totally random example, it's just to give you an idea
def cars_older_than_n_days(days)
  Car.select("cars.*, DATEDIFF(NOW(), release_date) AS age")
     .joins(:brand)
     .where(brand: {country: "German"})
     .having("age > ?", days)
end

Parfois, les requêtes sont encore pires. Si j'utilise squeel et que la requête est très grande, j'ai tendance à utiliser des parenthèses comme ceci:

# Again, non-sense query
Person.where {
  first_name = "Aldo" |
  last_name = "McFlange" |
  (
    age = "18" &
    first_name = "Mike" &
    email =~ "%@hotmail.co.uk"
  ) |
  (
    person.n_girlfriends > 1 &
    (
      country = "Italy" |
      salary > 1_234_567 |
      very_beautiful = true |
      (
        whatever > 123 &
        you_get_the_idea = true 
      )
    )
  )
}

Je dirais, si possible, essayez d'éviter les requêtes complexes et de les diviser en portées plus petites ou autre:

scope :healthy_users, lambda {
  younger_than(25).
  without_car.
  non_smoking.
  no_girlfriend
}

scope :younger_than, lambda { |age|
  where("users.age < ?", age)
}

scope :without_car, lambda {
  where(car_id: nil)
}

scope :non_smoking, lambda {
  where(smoker: false)
}

scope :no_girlfriend, lambda {
  where(n_girlfriends: 0)
}

Ce serait probablement le meilleur moyen.

La réalité

Malheureusement, les gens ont tendance à écrire de longues lignes et c'est mauvais:

  • Les longues lignes sont difficiles à lire (il y a une raison si les livres imprimés n'ont pas de très grandes pages)
  • Il est vrai que nous utilisons principalement 2 écrans, mais lorsque nous utilisons des choses comme git diff de la console ayant de longues lignes est douloureux
  • Parfois, vous travaillez sur votre ordinateur portable 13 "avec moins d'écran
  • Même si j'aime travailler avec 2 écrans, j'aime diviser mon éditeur pour éditer 2 fichiers en même temps - les longues lignes m'obligent à utiliser la barre de défilement horizontale (la chose la plus détestée au monde)
  • Oui, vous pouvez activer l'habillage Word dans votre éditeur, mais ce n'est toujours pas aussi agréable (à mon humble avis)

J'ai une règle dans mon éditeur pour que je sache quand je suis sur le point de franchir le 80e caractère sur la ligne. Mais rarement franchir la ligne par quelques caractères, c'est en fait plus agréable que de le diviser.

Conclusion

Il existe plusieurs façons de garder les lignes sous les années 80 et cela dépend souvent de la situation. Le problème des longues lignes n'est pas seulement un mauvais style, les longues lignes sont souvent un symptôme de trop de complexité .

69

Bien que la question ait déjà deux bonnes réponses, je voudrais renvoyer les futurs lecteurs au Ruby Style Guide pour de telles questions.

Actuellement, la section Disposition du code source contient de nombreuses informations sur la façon de couper les lignes dans diverses situations:

# starting point (line is too long)
def send_mail(source)
  Mailer.deliver(to: '[email protected]', from: '[email protected]', subject: 'Important message', body: source.text)
end

# bad (double indent)
def send_mail(source)
  Mailer.deliver(
      to: '[email protected]',
      from: '[email protected]',
      subject: 'Important message',
      body: source.text)
end

# good
def send_mail(source)
  Mailer.deliver(to: '[email protected]',
                 from: '[email protected]',
                 subject: 'Important message',
                 body: source.text)
end

# good (normal indent)
def send_mail(source)
  Mailer.deliver(
    to: '[email protected]',
    from: '[email protected]',
    subject: 'Important message',
    body: source.text
  )
end

# bad - need to consult first line to understand second line
one.two.three.
  four

# good - it's immediately clear what's going on the second line
one.two.three
  .four

Et cela s'avère souvent être une "solution" pour un code trop complexe comme @Aldo l'a déjà mentionné:

# bad
some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else

# good
if some_condition
  nested_condition ? nested_something : nested_something_else
else
  something_else
end
7
jibiel

D'après mon expérience, il semble que la convention ne vise pas à briser les lignes. La plupart des projets que j'ai vus, y compris la base de code de Rails lui-même, ne semblent avoir aucun problème à avoir de très longues lignes ininterrompues.

Je dirais donc que si vous voulez suivre la convention, ne rompez pas les lignes. Si vous êtes déterminé à briser les lignes, il n'y a pas de convention largement suivie pour savoir comment le faire. Vous pouvez utiliser le style de codage que vous préférez.

1
alexsanford1