def MyMod.extend_object(obj)
puts "Расширяется объект id #{obj.object_id}, класс #{obj.class}"
super
end
# ...
end
x = [1, 2, 3]
x.extend(MyMod)
# Выводится:
# Расширяется объект id 36491192, класс Array
Обращение к super
необходимо для того, чтобы мог отработать исходный метод extend_object
. Это напоминает поведение метода append_features
(см. раздел 11.1.12); данный метод годится также для отслеживания использования модулей.
11.3.14. Определение чистильщиков для объектов
У классов в Ruby есть конструкторы (методы new
и initialize
), но нет деструкторов (методов, которые уничтожают объекты). Объясняется это тем, что в Ruby применяется алгоритм пометки и удаления объектов, на которые не осталось ссылок (сборка мусора); вот почему деструктор просто не имеет смысла.
Однако тем, кто переходит на Ruby с таких языков, как C++, этот механизм представляется необходимым — часто задается вопрос, как написать код очистки уничтожаемых объектов. Простой ответ звучит так: невозможно сделать это надежно. Но можно написать код, который будет вызываться, когда сборщик мусора уничтожает объект.
а = "hello"
puts "Для строки 'hello' ИД объекта равен #{a.id}."
ObjectSpace.define_finalizer(а) { |id| puts "Уничтожается #{id}." }
puts "Нечего убирать."
GC.start
a = nil
puts "Исходная строка - кандидат на роль мусора."
GC.start
Этот код выводит следующее:
Для строки 'hello' ИД объекта равен 537684890.
Нечего убирать.
Исходная строка - кандидат на роль мусора.
Уничтожается 537684890.
Подчеркнем, что к моменту вызова чистильщика объект уже фактически уничтожен. Попытка преобразовать идентификатор в ссылку на объект с помощью метода ObjectSpace._id2ref
приведет к исключению RangeError
с сообщением о том, что вы пытаетесь воспользоваться уничтоженным объектом.
Имейте в виду, что в Ruby применяется консервативный вариант сборки мусора по алгоритму пометки и удаления. Нет гарантии, что любой объект будет убран до завершения программы.
Однако все это может оказаться и ненужным. В Ruby существует стиль программирования, в котором для инкапсуляции работы с ресурсами служат блоки. В конце блока ресурс освобождается, и жизнь продолжается без помощи чистильщиков. Рассмотрим, например, блочную форму метода File.open
:
File.open("myfile.txt") do |file|
line1 = file.read
# ...
end
Здесь в блок передается объект File
, а по выходе из блока файл закрывается, причем все это делается под контролем метода open
. Функциональное подмножество метода File.open
на чистом Ruby (сейчас этот метод ради эффективности написан на С) могло бы выглядеть так:
def File.open(name, mode = "r")
f = os_file_open(name, mode)
if block_given?
begin
yield f
ensure
f.close
end
return nil
else
return f
end
end
Мы проверяем наличие блока. Если блок был передан, то мы вызываем его, передавая открытый файл. Делается это в контексте блока begin-end
, который гарантирует, что файл будет закрыт по выходе из блока, даже если произойдет исключение.
В этой главе были приведены примеры использования более сложных и даже экзотических механизмов ООП, а также решения некоторых рутинных задач. Мы видели, как реализуются некоторые паттерны проектирования. Познакомились мы и с API отражения в Ruby, продемонстрировали ряд интересных следствий динамической природы Ruby и некоторые трюки, возможные в динамическом языке.
Пришло время вернуться в реальный мир. Ведь ООП — не самоцель, а всего лишь средство достижения цели. Последняя же заключается в написании эффективных, безошибочных и удобных для сопровождения приложений.
В современном окружении таким приложениям часто необходим графический интерфейс. В главе 12 мы рассмотрим создание графических интерфейсов на языке Ruby.
Глава 12. Графические интерфейсы для Ruby
Нет ничего хуже четкого образа нечеткой идеи.
Апсель Адамс
Нет смысла отрицать, что мы живем в век графических интерфейсов (ГИ). В обозримом будущем тот или иной вид графического интерфейса станет основным способом взаимодействия с компьютерами.
Я не думаю, что командная строка не переживет следующее десятилетие — у нее есть свое место в мире. Но даже закоренелые хакеры прежних лет (предпочитающие команду cp -R
перетаскиванию файлов мышкой) все-таки не прочь воспользоваться ГИ, когда это оправданно.
Читать дальше
Конец ознакомительного отрывка
Купить книгу