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?
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.
La réponse courte est cela dépend .
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)
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}
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
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
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
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
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.
Malheureusement, les gens ont tendance à écrire de longues lignes et c'est mauvais:
git diff
de la console ayant de longues lignes est douloureuxJ'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.
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é .
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
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.