Программирование на языке Ruby
Программирование на языке Ruby читать книгу онлайн
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
11.3.13. Отслеживание изменений в определении класса или объекта
А зачем, собственно? Кому интересны изменения, которым подвергался класс?
Одна возможная причина — желание следить за состоянием выполняемой программы на Ruby. Быть может, мы реализуем графический отладчик, который должен обновлять список методов, добавляемых «на лету».
Другая причина: мы хотим вносить соответствующие изменения в другие классы. Например, мы разрабатываем модуль, который можно включить в определение любого класса. С момента включения будут трассироваться любые обращения к методам этого класса. Что-то в этом роде:
class MyClass include Tracing def one end def two(x, y) endendm = MyClass.newm.one # Вызван метод one. Параметры =m.two(1, 'cat') # Вызван метод two. Параметры = 1, catОн должен работать также для всех подклассов трассируемого класса:
class Fred < MyClass def meth(*a) endendFred.new.meth{2,3,4,5) # вызван метод meth. Параметры =2, 3, 4, 5Возможная реализация такого модуля показана в листинге 11.18.
module Tracing def Tracing.included(into) into.instance_methods(false).each { |m| Tracing.hook_method(into, m) } def into.method_added(meth) unless @adding @adding = true Tracing.hook_method(self, meth) @adding = false end end end def Tracing.hook_method(klass, meth) klass.class_eval do alias_method "old_#{meth}", "#{meth}" define_method(meth) do |*args| puts "Вызван метод #{meth}. Параметры = #{args.join(', ')}" self.send("old_#{meth}",*args) end end endendclass MyClass include Tracing def first_meth end def second_meth(x, y) endendm = MyClass.newm.first_meth # Вызван метод first_meth. Параметры =m.second_meth(1, 'cat') # Вызван метод second_meth. Параметры = 1, catВ этом коде два основных метода. Первый,
includedhook_methodmethod_addedhook_methodhook_methodold_nameОбратите внимание на использование конструкции
alias_methodalias# Еще два способа записать эту строку...# Символы с интерполяцией:alias_method :"old_#{meth}", :"#{meth}"# Преобразование строк с помощью to_sym:alias_method "old_#{meth}".to_sym, meth.to_symЧтобы обнаружить добавление нового метода класса в класс или модуль, можно определить метод класса
singleton_method_addedKernelclass MyClass def MyClass.singleton_method_added(sym) puts "Добавлен метод #{sym.to_s} в класс MyClass." end def MyClass.meth1 puts "Я meth1." endenddef MyClass.meth2 puts "А я meth2."endВ результате выводится следующая информация:
Добавлен метод singleton_method_added в класс MyClass.Добавлен метод meth1 в класс MyClass.Добавлен метод meth2 в класс MyClass.Отметим, что фактически добавлено три метода. Возможно, это противоречит вашим ожиданиям, но метод
singleton_method_added
