производительности, поскольку иногда условие вычисляется много раз. Но рассмотрим следующий пример, который делает практически то же самое, однако весь платформенно-зависимый код помещен в один метод, имя которого от платформы не зависит:
if platform == Windows
def my_action
action1
end
elsif platform == Linux
def my_action
action2
end
else
def my_action
default_action
end
end
Таким способом мы достигаем желаемого результата, но условие вычисляется только один раз. Когда программа вызовет метод my_action
, он уже будет правильно определен.
1.4.2. Отражение
В языках Smalltalk, LISP и Java реализована (с разной степенью полноты) идея рефлексивного программирования — активная среда может опрашивать структуру объектов и расширять либо модифицировать их во время выполнения.
В языке Ruby имеется развитая поддержка отражения, но все же он не заходит так далеко, как Smalltalk, где даже управляющие конструкции являются объектами. В Ruby управляющие конструкции и блоки не представляют собой объекты. (Объект Proc
можно использовать для того, чтобы представить блок в виде объекта, но управляющие конструкции объектами не бывают никогда.)
Для определения того, используется ли идентификатор с данным именем, служит ключевое слово defined?
(обратите внимание на вопросительный знак в конце слова):
if defined? some_var
puts 'some_var = #{some_var}'
else
puts 'Переменная some_var неизвестна.'
end
Аналогично метод respond_to?
выясняет, может ли объект отвечать на вызов указанного метода (то есть определен ли данный метод для данного объекта). Метод respond_to?
определен в классе Object
.
В Ruby запрос информации о типе во время выполнения поддерживается очень полно. Тип или класс объекта можно определить, воспользовавшись методом type
(из класса Object
). Метод is_a?
сообщает, принадлежит ли объект некоторому классу (включая и его суперклассы); синонимом служит имя kind_of?
. Например:
puts 'abc'.class '' # Печатается String
puts 345.class # Печатается Fixnum
rover = Dog.new
print rover.class # Печатается Dog
if rover.is_a? Dog
puts 'Конечно, является.'
end
if rover.kind_of? Dog
puts 'Да, все еще собака.'
end
if rover.is_a? Animal
puts 'Да, он к тому же и животное.'
end
Можно получить полный список всех методов, которые можно вызвать для данного объекта. Для этого предназначен метод methods
из класса Object
. Имеются также его варианты private_instance_methods
, public_instance_methods
и т.д.
Аналогично можно узнать, какие переменные класса или экземпляра ассоциированы с данным объектом. По самой природе ООП в перечни методов и переменных включаются те, что определены как в классе самого объекта, так и во всех его суперклассах. В классе Module
имеется метод constants
, позволяющий получить список всех констант, определенных в модуле.
В классе Module
есть метод ancestors
, возвращающий список модулей, включенных в данный модуль. В этот список входит и сам данный модуль, то есть список, возвращаемый вызовом Mod.ancestors
, содержит по крайней мере элемент Mod
. В этот список входят не только родительские классы (отобранные в силу наследования), но и «родительские» модули (отобранные в силу включения).
В классе Object
есть метод superclass
, который возвращает суперкласс объекта или nil
. Не имеет суперкласса лишь класс Object
, и, значит, только для него может быть возвращен nil
.
Модуль ObjectSpace
применяется для получения доступа к любому «живому» объекту. Метод _idtoref
преобразует идентификатор объекта в ссылку на него; можно считать, что это операция, обратная той, что выполняет двоеточие в начале имени. В модуле ObjectSpace
есть также итератор each_object
, который перебирает все существующие в данный момент объекты, включая и те, о которых иным образом узнать невозможно. (Напомним, что некоторые неизменяемые объекты небольшого размера, например принадлежащие классам Fixnum
, NilClass
, TrueClass
и FalseClass
, не хранятся в куче из соображений оптимизации.)
1.4.3. Отсутствующие методы
При вызове метода (myobject.mymethod
) Ruby ищет поименованный метод в следующем порядке:
1. Синглетные методы, определенные для объекта myobject
.
2. Методы, определенные в классе объекта myobject
.
3. Методы, определенные в предках класса объекта myobject
.
Если найти метод mymethod
не удается, Ruby ищет метод с именем method_missing
. Если он определен, то ему передается имя отсутствующего метода (в виде символа) и все переданные ему параметры. Этот механизм можно применять для динамической обработки неизвестных сообщений, посланных во время выполнения.