Ruby и красивый код #1

Благодаря некоторым особенностям Ruby, код на нем можно писать значительно более лаконичный...

Posted by Марк Мельник on October 19, 2010

Благодаря некоторым особенностям Ruby, код на нем можно писать значительно более лаконичный, чем вы можете себе это представить. Например, благодаря тому, что Ruby возвращает значение последнего выражения, можно сократить количество кода не только за счет отказа от использования return, там, где это возможно, но и за счет написания простых методов, которые в итоге своей работы возвращают только true или false не используя при этом логический конструкций типа if..else, и т.д.

Пример:

def young? (age)
  if age < 30
    return true
  else
    return false
  end
end

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

def a_bigger? (a, b)
  a > b
end

Мы сократили код в 2 раза! И не потеряли при этом его ясности.

Давайте представим, что у нас есть следующий код:

breakfast = nil
if breakfast == nil
  breakfast = "глазунья с беконом"
end

Как его можно улучшить? Давайте попробуем воспользоваться методом nil? вместо сравнения с объектом nil:

if breakfast.nil?
  breakfast = "глазунья с беконом"
end

Можно ли еще улучшить код? — Конечно!

if !breakfast
  breakfast = "глазунья с беконом"
end

Конструкция if !… — это то же самое, что и unless:

unless breakfast
  breakfast = "глазунья с беконом"
end

Можно ли сделать еще лучше? — Делаем!

breakfast = "глазунья с беконом" unless breakfast

Хотите еще лучше?! Получите!

breakfast || = "глазунья с беконом"

Уже устали? А ведь это только начало статьи об оптимизации кода!

Допустим у нас есть следующий код:

val =12
if val == 1 || val == 12 || val == 42
  puts "е-ху!"
end

Сразу видно, что мы повторяемся, а именно повторяме операцию сравнения. Терпеливый программист может позволить себе написать 10 и 20 и 100 проверок, но ленивый и умный программист сделает следующим образом:

if [1,12,42].include?(val)
  puts "е-ху!"
end

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

puts "е-ху!" if [1,12,42].include?(val)

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

fruits = ['apple', 'banana', 'apricot']

fruits << 'apple' unless fruits.include?('apple')

Оказывается можно сделать проще! пример:

fruits |= ['apple']

Метод | присоединяет к первому массиву второй удаляя при этом повторяющиеся элементы.

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

user_id = nil
if comments
  if comments.first
    if comments.first.user
      user_id = comments.first.user.id
    end
  end
end

Этот код можно легко уложить в одну строку и не повторять надоедливые блоки if…end:

user_id = comments && Comments.first && comments.first.user && comments.first.user.id

Логические операции производятся в порядке слева направо и возвращается значение последнего выражения — значит все отлично!

Вы можете вставлять код непосредственно в строку при этом сам код в итоге будет заменен на результат его выполнения, но для этого сам код необходимо поместить в «магические» скобки.

Пример без магических скобок:

puts "User name:" + name.capitalize + "\n user last name:" + lastname.capitalize + "\n user father name:" + ...

Делаем как лучше:

puts "User name: #{name.capitalize}\n user last name: #{lastname.capitalize}\n user father name: ..."

Нельзя сказать, что код вышел короче, зато нет путаницы с кавычками!

Представьте, что у нас есть массив:

a = ['ant', 'bee', 'cat', 'dog', 'elk']

Существует более короткий способ создания подобных массивов:

a = %w{ ant bee catdog elk}

Не стоит забывать об итераторах. Код:

for i in 0..9
  puts i
end

Используя итератор times мы можем записать тот же функционал более изящно:

10.times {|i| puts i}

Еще один пример того, как итераторы делают жизнь лучше:

for i in 0...people.size
  puts people[i].name
end

Используя итератор each мы добиваемся совершенства:

people.each {|p| puts p.name}

Благодарю Karmen Blake (karmenblake) за предоставление большинства примеров кода к этому посту.