11 фокусов с Ruby, о которых вы не подозревали

от автора

1. Глубокое копирование

Когда вы копируете объект, который содержит другие объекты, например Array, в копии оказываются ссылки на оригинальные объекты.

Вот, смотрите:

food = %w( bread milk orange ) food.map(&:object_id)       # [35401044, 35401020, 35400996] food.clone.map(&:object_id) # [35401044, 35401020, 35400996]

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

def deep_copy(obj)   Marshal.load(Marshal.dump(obj)) end deep_copy(food).map(&:object_id) # [42975648, 42975624, 42975612]

2. Различные способы вызова лямбд

my_lambda = -> { puts 'Hello' }  my_lambda.call my_lambda[] my_lambda.() my_lambda.===

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

3. Создание предзаполненного массива

Фабрика класса Array может принимать аргумент и блок, что позволяет создавать массив с несколькими (n) элементами. По умолчанию эти элементы — экземпляры класса NilClass (их значение равно nil), но если вы передаете в вызов блок, значения заполняются оттуда.

Array.new(10) { rand 300 }

Этот код создаст массив из десяти элементов, каждый из которых — случайное число в диапазоне от 0 до 299.

4. true, false и nil — объекты

true.class  # TrueClass false.class # FalseClass nil.class   # NilClass

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

Это паттерн «singleton» в действии.

5. lambda строго относится к количеству аргументов, Proc — нет

my_lambda = ->(a, b)  { a + b } my_proc   = Proc.new  { |a, b| a + b }  my_lambda.call(2) #⇒ ArgumentError: wrong number of arguments (1 for 2)  my_proc.call(2) #⇒ TypeError: nil can't be coerced into Fixnum

6. Код можно выполнять напрямую, без irb, pry, или файла

Командная строка руби принимает некоторые интересные опции, которыми можно пользоваться.

Например, флаг -e можно напрямую передать кусок кода, который будет выполнен.

ruby -e '5.times { puts "Fun with Ruby" }'

Про остальные флаги можно узнать, запустив интерпретатор с ключом -h.

7. Собственный mini-irb одной строкой

Хотели когда-нибудь узнать, как работает irb? Ну, вот мегаупрощенная ее версия.

Помните, что означает аббревиатура «REPL»: Read-Eval-Print Loop (прочитать-выполнить-напечатать-повторить).

ruby -n -e 'p eval($_)'

У этой версии нет приглашения командной строки, но ничто не может остановить вас: давайте, попробуйте, наберите какой-нибудь код на руби.

"A" * 5 "AAAAA"

Это работает, потому что ключ «-n» делает вот что:

-n    assume 'while gets(); ... end' loop around your script

Ну а $_ — просто глобальная переменная, которая хранит:

The last input line of string by gets or readline.

8. Разморозить (unfreeze) объект (опасно!)

В самом руби нет метода, который позволит разморозить ранее замороженный (frozen) объект, но используя класс Fiddle из стандартной библиотеки, вы можете проникнуть во внутренний мир руби и сделать невозможное возможным.

require 'fiddle'  str = 'water'.freeze str.frozen? # true  memory_address = str.object_id * 2  Fiddle::Pointer.new(memory_address)[1] &= ~8  str.frozen? # false

Не пытайтесь повторить это дома или в школе!

9. Объекты с особенной индивидуальностью (identity)

У всех объектов в руби Ruby есть идентификатор id — целое число, которое вы можете посмотреть, вызвав метод object_id. У некоторых объектов этот идентификатор фиксирован: у чисел, наследников Fixnum, а также у true, false и nil.

false.object_id # 0 true.object_id  # 2 nil.object_id   # 4  1.object_id # 3 2.object_id # 5

Для Fixnumов верна следующая формула: (number * 2) + 1.

Бонус: Самое большое число, представимое Fixnum — это 1073741823, дальше уже идут объекты класса Bignum.

10. Предотвращение слишком длинного вывода в irb или pry

Если вы работаете в irb и хотите избежать вывода на экран какого-нибудь громадного куска данных (например, гигантского массива, или строки) — просто добавьте точку с запятой ; в конец вашего кода.

require 'rest-client' #                                ⇓  RestClient.get('blackbytes.info');

А теперь попробуйте еще разок без ; и найдите одно отличие

11. Метод caller для получения полного стека текущего вызова

Вот пример:

def foo   bar end  def bar   puts caller end  foo

Выведет:

-:3:in 'foo' -:10:in '<main>'

Для того, чтобы просто получить имя метода, воспользуйтесь __method__ или __callee__.

Прим. переводчика: разница между __method__ и __callee__ в том, что будет выведено для алиасов: __method__ всегда вернет имя настоящего метода, в то время, как __callee__ вернет имя алиаса:

main> def m; puts [__callee__, __method__].inspect; end main> alias :a, :m main> m #⇒ [:m, :m] main> a #⇒ [:a, :m]

Во всех минорных версиях Ruby2.3 эта функциональность сломана, оба метода возвращают [:m, :m]. Будьте осторожны!

Бонус! Конвертирование любого значения в boolean

!!(1)   # true !!(nil) # false

Это все.

— Оригинал: Jesus Castello

ссылка на оригинал статьи https://habrahabr.ru/post/326422/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *