Подтвердить что ты не робот

Как разбить длинные строки Ruby

Я всегда получаю большие строки кода в верхней части моего Rails models. Я ищу предложения для лучшего способа разбить их со стандартным рубиновым стилем. Например, одна строка, на которую я сейчас смотрю, такова:

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

Каков обычный стиль для разбивки этих длинных линий вызова метода?

4b9b3361

Ответ 1

Что-то по строкам:

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

Или, если вам нравится выделить хэш хэша (разумная вещь):

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

Идея оставить это все на одной линии поражает меня как безумную идею, это означает, что вам нужно прокрутить произвольную сумму, чтобы увидеть, что было делегировано. Ео.

Я бы, наверное, тоже немного подстроил, возможно, алфавит.

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

Если у файла не было много/какого-либо другого существенного контента, я мог бы поместить каждый символ метода в его собственную строку, просто чтобы упростить редактирование. В более крупном файле я бы не хотел занимать место для этого.

Не то, чтобы я когда-либо думал об этом.

Изменить Я думаю, что:/

В эти дни я мог бы сгруппировать делегированные методы с помощью "подобия", примерно:

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

Мое жюри висело на синтаксисе хэша 1.9, когда значение также является символом; Я думаю, это выглядит забавно. Я также не уверен, где бы я отступил от него, но мог бы потерять его во время переформатирования IDE, но мне нравится, как он выглядит выше, если я использую новый синтаксис.

Ответ 2

Короткий ответ зависит от.

Основы

Для начала вы можете сохранить несколько символов, используя "новый" синтаксис хэша Ruby:

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

против.

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

Hash/Массивы

Иногда вам нужно инициализировать массив или хэш, особенно для хэшей, которые приятно писать их следующим образом:

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

Тот же хеш в той же строке будет (не так хорошо):

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

Различные вызовы методов

Некоторые методы требуют много параметров или эти параметры имеют длинные имена:

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

В этом случае я, вероятно, напишу так:

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

Это все еще не очень красиво, но я думаю, что это менее уродливо.

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

Опять же, не самый красивый код на земле, но у него есть какая-то структура.

Кроме того, иногда вы можете использовать переменные для разделения строк. Это всего лишь пример, но в основном вы называете блоки вещей (а иногда и после этого вы понимаете, что можете фактически переместить этот блок в методе)

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

Блоки

Говоря о блоках (замыканиях):

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

можно записать следующим образом:

User.all.map(&:method_name)

Если у вас есть правильные блоки, попробуйте использовать do-end вместо фигурных скобок:

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

Условный

Не используйте тернарный оператор if для сложных вещей:

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

Если у вас есть сложные операторы if:

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

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

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 - ваш друг... Мне всегда нужно google, чтобы получить синтаксис правильно, но как только вы это исправите, читатели читают следующее:

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

Запросы

Я делаю это для простых случаев:

# Totally random example, it 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

Иногда запросы даже хуже. Если я использую squeel, и запрос очень большой, я обычно использую круглые скобки следующим образом:

# 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 
      )
    )
  )
}

Я бы сказал, если возможно, попытайтесь избежать сложных запросов и разделите их на меньшие области или что-то еще:

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)
}

Это, вероятно, лучший способ.

Реальность

К сожалению, люди склонны писать длинные строки, и это плохо:

  • Длинные строки трудно читать (есть причина, если печатные книги не имеют сверхбольших страниц)
  • Это правда, что мы в основном используем 2 экрана, но при использовании таких вещей, как git diff из консоли, имеющей длинные строки, больно.
  • Иногда вы работаете на своем 13-дюймовом ноутбуке с меньшим имуществом экрана.
  • Даже если мне нравится работать с 2 экранами, мне нравится разделять мой редактор, чтобы редактировать 2 файла одновременно - длинные строки заставляют меня использовать горизонтальную полосу прокрутки (самая ненавистная вещь на земле).
  • Да, вы можете включить перенос слов в свой редактор, но он все же не так хорош (IMHO)

У меня есть линейка в моем редакторе, поэтому я знаю, когда я собираюсь пересечь 80-й char на линии. Но редко пересекайте линию несколькими символами, это действительно лучше, чем расколоть ее.

Заключение

Существует несколько способов удержать линии под 80-ыми и часто зависит от ситуации. Проблема с длинными строками - это не просто плохой стиль, длинные строки часто являются симптомом слишком большой сложности.

Ответ 3

Хотя у вопроса уже есть два отличных ответа, я хотел бы направить будущих читателей в Руководство по стилю Ruby для таких вопросов.

В настоящее время в разделе Source Code Layout содержится много информации о том, как разбить строки в различных ситуациях:

# 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 immediately clear what going on the second line
one.two.three
  .four

И это часто оказывается "решением" для слишком сложного кода, поскольку @Aldo уже упомянул:

# 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

Ответ 4

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

Итак, я бы сказал, если вы хотите следовать соглашению, не разрывайте линии. Если вы решите разбить строки, то для этого не существует широко принятого соглашения. Вы можете использовать любой стиль кодирования, который вы предпочитаете.