Ruby и красивый код #1
октября 19, 2010 | Published in Ruby, Основы | 14 Comments
Благодаря некоторым особенностям 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) за предоставление большинства к этому посту.
октября 20, 2010 at 09:06 (#)
У меня шок, мягко говоря… я, конечно, подразумевал про удобство руби, но чтоб такое можно было вытворять… чувствую, стоит обзавестись какой-то хорошей книгой именно по руби, а не сразу хвататься за рельсы…
октября 20, 2010 at 09:27 (#)
В догонку: может посоветуете какую-то книжку, где вот эти все премудрости расписаны? Можно на английском…
октября 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 все-же необходимо для изучения азов.
октября 20, 2010 at 15:49 (#)
Спасибо, буду изучать (-:
октября 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 не кажется явной или актуальной.
октября 21, 2010 at 19:14 (#)
baka, не могу с вами не согласится, но статья не так об особенностях Ruby, как о возможностях писать более лаконичный и удобочитаемый код, т.е. идея состоит не в том, что «Смотрите какой Ruby класный!(в этом нет сомнений ;-) )», а в том, что «Следует досконало изучить синтаксис и стандартную библиотеку и вы сможете писать очень изящный код.»
октября 22, 2010 at 13:22 (#)
Скажите, а где прочитать вот про такие конструкции:
breakfast || = «глазунья с беконом»
fruits |= ['apple']
Это какое-то такое хитрое присваивание?? понятно, что присваивание, но в книжках, которые я пока пролистал и почитал, именно такого не видел )))-:
октября 22, 2010 at 13:46 (#)
Уже не надо: нашёл ответ вот тут
октября 23, 2010 at 16:07 (#)
Удивительно, это ведь почти перл! :)
ноября 20, 2010 at 10:56 (#)
[...] Это 2я статья из серии “Ruby и красивый код”. Ruby и красивый код #1 [...]
ноября 22, 2010 at 09:56 (#)
Первый-то пример проще всего сделать так (young? — прекрасное название, зачем было менять, имхо, ясности не прибавило):
def young? (age, upward = nil)
age < (upward || 30)
end
ноября 22, 2010 at 10:00 (#)
Блин, вот это круто, не знал, что так можно:
января 11, 2011 at 07:45 (#)
В предпоследнем примере:
следует добавить одну точку, а именно:
Иначе при выполнении интерпретатор выдаст ошибку доступа к методу #name объекта nil.
января 11, 2011 at 16:55 (#)
kaineer спасибо, исправил!