В этом посте я хочу представить вам 21 интересную особенность Ruby. Многие из этих особенностей могут быть не очевидны новичку, в то время как более опытный разработчик использует их каждый день. Для выполнения примеров кода удобнее всего использовать «интерактивный» Ruby — irb. Если же у вас ещё нет своего Ruby, то воспользуйтесь онлайн интерактивным интерпретатором. Итак, приступим.
1. Быстрое получение совпадений из регулярного выражения
Чтобы получить данные из текста используя регулярные выражения, как правило применяют метод match. Сейчас я покажу как использовать его наиболее эффективно:
email = "Fred Bloggs" email.match(/<(.*?)>/)[1] # => "fred@bloggs.com" email[/<(.*?)>/, 1] # => "fred@bloggs.com" email.match(/(x)/)[1] # => NoMethodError [:(] email[/(x)/, 1] # => nil email[/([bcd]).*?([fgh])/, 2] # => "g"
В комментариях мне делают замечание, что тема регулярных выражений не раскрыта. Раскрываю:
name, mail = *email.match(/(.+)\s<(.*)>/)[1..2] puts name # "Fred Bloggs" puts mail # "fred@bloggs.com"
2. Синоним для Array#join
Многие знают, что если использовать метод Array#* для «умножения» массива на число, то массив будет увеличен в заданное количество раз путём дублирования его элементов. Но но всем известно, что если вместо числа, «умножить» массив на строку, то это сработает как метод Array#join:
%w{this is a test} * ", " # => "this, is, a, test" h = { :name => "Fred", :age => 77 } h.map { |i| i * "=" } * "\n" # => "age=77\nname=Fred"
3. Быстрое форматирование десятичных чисел.
Если вы хотите сделать форматированный вывод, например, для указания цен, скорее всего будете использовать метод sprintf, но не спешите, Ruby предлагает более интересную возможность:
money = 9.5 "%.2f" % money # => "9.50"
4. Окружаем текст тегами
Конечно предыдущий пример можно использовать не только для чисел, но и для строк:
"[%s]" % "same old drag" # => "[same old drag]"
И даже для массивов:
x = %w{p hello p} "<%s>%s" % x # => "hello "
5. Удаляем директорию со всем содержимым
Нет-нет, не спешите писать код на bash, в Руби есть библиотека fileutils:
require 'fileutils' FileUtils.rm_r 'somedir'
6. Разбиваем массивы и хэши
Можно использовать «*» чтобы «разбить» перечисляемые типы данных (массивы и хэши). Чтобы было понятно о чём идёт речь, вот несколько примеров:
a = %w{a b} b = %w{c d} [a + b] # => [["a", "b", "c", "d"]] [*a + b] # => ["a", "b", "c", "d"]
a = { :name => "Fred", :age => 93 } [a] # => [{:name => "Fred", :age =>93}] [*a] # => [[:name, "Fred"], [:age, 93]]
a = %w{a b c d e f g h} b = [0, 5, 6] a.values_at(*b).inspect # => ["a", "f", "g"]
Получаем из массива хэш:
fruit = ["apple","red","banana","yellow"] # ["apple", "red", "banana", "yellow"] Hash[*fruit] # {"apple"=>"red", "banana"=>"yellow"}
7. Убираем объявление переменных.
Вместо объявления переменных с каким-то, зачастую пустым, начальным значением, можно это сделать «на лету». Таким образом можно совместить объявление переменной и какие-то манипуляции над ней. Приём особенно полезен, когда не известно, была ли объявлена эта переменная раньше:
(z ||= []) << 'test'
8. Использование не строковых ключей хэша
Такое применение можно встретить не часто, но иногда это может оказаться действительно полезно:
does = is = { true => 'Yes', false => 'No' } does[10 == 50] # => "No" is[10 > 5] # => "Yes"
9. Логические and и or могут объединить операторы в одну строку
Многие разработчики используют это приём чтобы сократить код, убрав ненужное разбиение на строки:
queue = [] %w{hello x world}.each do |word| queue << word and puts "Added to queue" unless word.length < 2 end puts queue.inspect # Output: # Added to queue # Added to queue # ["hello", "world"]
10. Выполнение кода, только если если файл запущен непосредственно
Вы можете использовать один и тот же код как в качестве самостоятельного скрипта, так и библиотеки. Тогда у вас может возникнуть необходимость выполнять части кода только если они использованы как самостоятельный скрипт или наоборот, подключаются с помощью require:
if __FILE__ == $0 # Этот участок будет выполнен, только если файл выполнен как самостоятельная программа end
11. Быстрое массовое присвоение
Что может быть проще:
a, b, c, d = 1, 2, 3, 4
12. Диапазоны вместо нескольких сравнений
Больше никаких if x > 1000 && x < 2000, теперь можно писать так:
year = 1972 puts case year when 1970..1979: "Семидесятые" when 1980..1989: "Восьмидесятые" when 1990..1999: "Девяностые" end
13. Перечисляемые структуры вместо повторения кода
%w{rubygems daemons eventmachine}.each { |x| require x }
14. Тернарный оператор
О тернарном операторе обычно узнают на ранних этапах изучения Руби, но почему-то используют не часто. Тернарный оператор — не панацея, но иногда способен сделать многое проще:
puts x == 10 ? "x равно десяти" : "x не равно десяти" # Конечно, можно сделать и присвоение: LOG.sev_threshold = ENVIRONMENT == :development ? Logger::DEBUG : Logger::INFO
15. Несколько тернарных операторов
Безусловно, это может вызвать проблемы с читаемостью кода, но всё же:
qty = 1 qty == 0 ? 'none' : qty == 1 ? 'one' : 'many'
Да, немного запутанно… Так будет понятнее:
(qty == 0 ? 'none' : (qty == 1 ? 'one' : 'many'))
16. Избавляемся от избыточных логических выражений
Частенько можно увидеть что-нибудь вроде этого:
def odd?(x) if x % 2 == 0 return false else return true end end
Но это слишком длииино! Воспользуемся тернарным оператором:
def odd?(x) # Кстати, return можно опустить x % 2 == 0 ? false : true end
Уже неплохо, но это тоже длинно, зачем нам использовать тернарный оператор, если «==» и так возвращает true или false:
def odd?(x) x % 2 != 0 end
17. Полный backtrace исключения
def do_division_by_zero; 5 / 0; end begin do_division_by_zero rescue => exception puts exception.backtrace end
18. Перебираем в итераторе как одиночные объекты, так и перечисляемые
[*items].each do |item| # ... end
В этом примере, если items — одиночный объект, то он будет преобразован в массив, благодаря заключению в «[]», если же это массив, то с ним ничего не произойдёт, потому что «[]» и «*» скомпенсируют друг-друга.
19. Перед блоком rescue не обязательно писать begin
def x begin # ... rescue # ... end end
def x # ... rescue # ... end
20. Блоки комментариев
Для комментирования можно использовать не только «#», но и такую конструкцию:
puts "x" =begin this is a block comment You can put anything you like here! puts "y" =end puts "z"
21. Rescue для спасения
Можно использовать однострочную форму rescue когда важно во что бы то ни стало вернуть значение:
h = { :age => 10 } h[:name].downcase # ERROR h[:name].downcase rescue "No name" # => "No name"
Бонус 22. Параметр, заданный по-умолчанию
Как можно опознать, задан ли параметр метода вызывающей программой или было взято значение по-умолчанию.
Один из возможных вариантов:
def foo(a, b=(flag=true; 666)) puts "b равно #{b}, flag равно #{flag.inspect}" end foo 100 # b равно 666, flag равно true foo 100, 666 # b равно 666, flag равно nil foo 100, 400 # b равно 400, flag равно nil
Бонус 23. Переводим из 10 системы счисление в любую другую с базисом от 2 до 36
1234567890.to_s(2) # "1001001100101100000001011010010" 1234567890.to_s(8) # "11145401322" 1234567890.to_s(16) # "499602d2" 1234567890.to_s(24) # "6b1230i" 1234567890.to_s(36) # "kf12oi"
Комментариев нет:
Отправить комментарий