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

октября 19, 2010  |  Published in Ruby, Основы  |  14 Comments

ruby Благодаря некоторым особенностям 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) за предоставление большинства к этому посту.

Tags: ,

Responses

  1. says:

    октября 20, 2010 at 09:06 (#)

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

  2. says:

    октября 20, 2010 at 09:27 (#)

    В догонку: может посоветуете какую-то книжку, где вот эти все премудрости расписаны? Можно на английском…

  3. admin says:

    октября 20, 2010 at 13:47 (#)

    Практически все книги по Ruby хороши — это благодаря тому, что называется «высокий порог входа». Из тех что я читал и листал могу посоветовать:

    Addison Wesley: Design Patterns in Ruby (2007) — толковая книга, но не для новичков, как по-моему.

    Pragmatic Bookshelf: Best of Ruby Quiz (2006) — интересные задачи и решения

    The Ruby Way она же доступна на русском под названием: «Программирование на языке Ruby» автор: Хэл Фултон

    Хоть с выходом 1.9.х многое изменилось, большая часть информации в книгах остается актуальной.

    «Сразухватание» за rails не мешает паралельно с этим изучать сам язык, многие так и делают — начинают с Rails и далее двигаются к совершенствования навыков программирования на самом Ruby… По-моему это даже хорошая практика, т.к. позволяет работать с языком на реальных проектах, а не решать традиционные и совсем бесполезные задачи — это на много интересней, хотя полистать книгу по Ruby все-же необходимо для изучения азов.

  4. says:

    октября 20, 2010 at 15:49 (#)

    Спасибо, буду изучать (-:

  5. baka says:

    октября 21, 2010 at 14:54 (#)

    По поводу первого примера это не заслуга ruby, а дурость некоторых разработчиков.
    т.е. код

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

    можно переписать на С так…

    bool isYoung(int age) {
    return age < 30;
    }

    Извините за такой "вброс" но в данном примере крутость Ruby не кажется явной или актуальной.

  6. admin says:

    октября 21, 2010 at 19:14 (#)

    baka, не могу с вами не согласится, но статья не так об особенностях Ruby, как о возможностях писать более лаконичный и удобочитаемый код, т.е. идея состоит не в том, что «Смотрите какой Ruby класный!(в этом нет сомнений ;-) )», а в том, что «Следует досконало изучить синтаксис и стандартную библиотеку и вы сможете писать очень изящный код.»

  7. says:

    октября 22, 2010 at 13:22 (#)

    Скажите, а где прочитать вот про такие конструкции:

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

    fruits |= ['apple']

    Это какое-то такое хитрое присваивание?? понятно, что присваивание, но в книжках, которые я пока пролистал и почитал, именно такого не видел )))-:

  8. says:

    октября 22, 2010 at 13:46 (#)

    Уже не надо: нашёл ответ вот тут

  9. Alexey says:

    октября 23, 2010 at 16:07 (#)

    Удивительно, это ведь почти перл! :)

  10. Ruby и красивый код #2 | Разработка на Ruby и Rails c нуля says:

    ноября 20, 2010 at 10:56 (#)

    [...] Это 2я статья из серии “Ruby и красивый код”. Ruby и красивый код #1 [...]

  11. says:

    ноября 22, 2010 at 09:56 (#)

    Первый-то пример проще всего сделать так (young? — прекрасное название, зачем было менять, имхо, ясности не прибавило):

    def young? (age, upward = nil)
    age < (upward || 30)
    end

  12. says:

    ноября 22, 2010 at 10:00 (#)

    Блин, вот это круто, не знал, что так можно:

    fruits |= ['apple']
    
  13. says:

    января 11, 2011 at 07:45 (#)

    В предпоследнем примере:

    for i in 0..people.size

    следует добавить одну точку, а именно:

    for i in 0...people.size

    Иначе при выполнении интерпретатор выдаст ошибку доступа к методу #name объекта nil.

  14. admin says:

    января 11, 2011 at 16:55 (#)

    kaineer спасибо, исправил!

Leave a Response

Для подсветки кода используйте BB - коды: [language]...[/language], где language может быть: ruby, javascript, css, html.