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/
Добавить комментарий