Статьи

Менее используемые Ruby API

Если вы когда-либо разрабатывали что-то с использованием Ruby, то вы знаете, что это просто классно. Он течет хорошо, хорошо читает и имеет много интересных способов сделать что-то. Помимо повседневных API-интерфейсов, к которым вы, возможно, привыкли, есть куча вкусностей, которые часто упускают из виду или никогда не видели до сих пор! В этой статье я расскажу о некоторых из этих драгоценных камней, без каламбура, которые могут доставить вас прямо к Ruby Zen.

ядро

Модуль Kernel предоставляет множество методов, которые доступны для всех объектов, которые наследуются от Object , поскольку Object смешивается в Kernel . Почему я делаю это различие? Что BasicObject Ruby 1.9, класс BasicObject был добавлен и теперь является родительским для всех классов. BasicObject не имеет методов, предоставляемых модулем Kernel .

__callee__

Эта странная функция возвращает имя текущего метода в качестве Symbol .

 def add(a, b) log("#{a} + #{b}", __callee__) a + b end def log(msg, caller) puts "##{caller}: #{msg}" end 

В приведенном выше примере метод log принимает два параметра: сообщение и вызывающий объект. Метод add использует функцию __callee__ для передачи имени своего метода в функцию log. Если вы запустите консоль irb, введите эти два метода, а затем add 3,5 вы получите:

 #add: 3 + 5 => 8 

Хорошо, так что это довольно просто, но немного изящно, верно? Конечно, вы можете просто передать :add в метод log вместо использования __callee__ , ведь вы знаете, что находитесь в методе add верно? Небольшое преимущество в приведенном выше случае использования состоит в том, что если бы вы переименовали метод add в my_super_add_method вам не пришлось бы обновлять свой вызов метода log . Не стесняйтесь придумать другие удобные способы использования и опубликовать их в разделе комментариев этой статьи.

at_exit

Если вам когда-нибудь нужно было запустить какой-то код непосредственно перед at_exit из вашей программы, вам следует проверить at_exit . Он регистрирует блок как обработчик, который вызывается при выходе из процесса Ruby. Фактически вы можете зарегистрировать несколько обработчиков, как показано в следующем примере, at_exit_example.rb.

 at_exit { puts "the program is exiting" } at_exit { puts "the program is really exiting" } puts "doing some stuff" raise "Uh oh, something bad happened!" 

Обработчики будут вызываться в порядке «последний пришел — первым вышел» (LIFO). Если вы поместите приведенный выше код в файл, возможно с именем at_exit_example.rb, и ruby at_exit_example.rb его ruby at_exit_example.rb , вы получите:

 doing some stuff the program is really exiting the program is exiting at_exit_example.rb:10:in `<main>': Uh oh, something bad happened! (RuntimeError) 

Как вы видели, обработчики at_exit будут вызываться, когда at_exit завершиться процесс Ruby, даже если это происходит из-за необработанного исключения. Это может быть полезно для очистки некоторых файлов, которые могли быть созданы вашей программой, закрытия соединений с серверами или регистрации некоторого контекста, который может помочь отладить проблему с программой (если это программа, которая обычно не должна выходить самостоятельно). ).

block_given?

Это может быть одна функция, с которой вы уже столкнулись, но если нет, то сейчас самое время узнать об этом. Если вы когда-нибудь передавали блок функции, то есть вероятность, что вызываемая функция использует block_given? , Ниже приведен пример того, как block_given? может быть использован.

 def sum(values) error = result = nil begin result = values.inject do |total, value| total += value end rescue Exception => ex error = ex end if block_given? yield result, error else return result unless error raise error end end sum((1..5)) do |result, error| puts "Error: #{error}" # => nil puts "Result: #{result}" # => 15 end 

Функция sum берет коллекцию значений, вычисляет их сумму и возвращает результат. Функция проверяет, был ли задан блок, следовательно, block_given? вызов, и если он имеет, то это приведет к результату и ошибке. Если во время выполнения суммы возникло исключение, оно будет перехвачено и возвращено в блок.

Однако, если блок не задан, функция sum вычислит результат и вернет его. Если в этом сценарии возникает исключение, то функция sum возбуждает его вместо возврата nil или какого-либо другого значения, чтобы указать на проблему. Если вы хотите разрешить передачу block_given? вашим функциям, попробуйте block_given? вихрь!

объект

Класс Object странным образом описывается так:

Объект является корнем иерархии классов Ruby. Его методы доступны всем классам, если они явно не переопределены.

Я говорю странно, потому что, как я упоминал ранее, BasicObject является новым корневым классом верхнего уровня в иерархии классов Ruby. Я предполагаю, что документация просто должна быть обновлена, что вы или я могли бы добровольно сделать;).

Класс Object получает большую часть своего поведения, смешивая его с модулем Kernel , но также имеет некоторые свои полезные свойства, такие как method описанный ниже.

метод

Вы никогда не задумывались, как вы можете получить ссылку на метод? Многие языки предоставляют эту возможность, но проверьте, насколько она лаконична с Ruby:

 m = Calculator.method(:sum) # => assume "sum" is a class method m.call 3, 4 # => 7 

Попробуйте сделать это в Java, и вы легко добавите больше кода, включая несколько предложений catch для обработки множества потенциальных исключений, которые могут быть выброшены.

пространства объектов

Модуль ObjectSpace описывается следующим образом:

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

Круто, да? Я так и думал, поэтому я покажу вам each_object и _id2ref .

each_object

Функция each_object предоставляет итератор для всех живых объектов (для этого процесса Ruby). Перечислитель может быть отфильтрован по типу, если вас интересуют только определенные типы объектов. Вы можете использовать each_object и модуль ObjectSpace в целом для помощи в отладке или профилировании.

 class Foo; end ObjectSpace.each_object(Foo) do |foo_obj| puts foo_obj end # => 0 ...there are no instances yet. # create a new instance and print the object_id puts Foo.new.object_id # => 2160309640 ObjectSpace.each_object(Foo) do |foo_obj| puts foo_obj.object_id # => 2160309640 end 

Конечно, вы можете перебирать объекты любого типа, а не только свои собственные. Давай, взгляни на все объекты String !

_id2ref

Если по какой-то причине вы знаете, object_id объекта, запущенного в вашем процессе Ruby, то вам повезло. Вы можете получить ссылку на этот объект, используя ObjectSpace._id2ref .

 f = Foo.new.object_id # => 2160309640 ObjectSpace._id2ref(2160309640) == f # => true 

Много больше

Надеюсь, вы прочитали что-то новое и классное после прочтения этого, но держу пари, что вы хотите большего, верно? Если это так, вы можете проверить некоторые из них:

Дело в том, что в Ruby есть много интересного кода, доступного для вашего исследования. У вас есть опыт работы с некоторыми менее распространенными классами, модулями или функциями Ruby? Если так, оставьте комментарий и поделитесь со всеми!