Программирование на языке Ruby
Программирование на языке Ruby читать книгу онлайн
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
class MyClass def self.new_method(name, &block) define_method(name, &block) endendMyClass.new_method(:mymeth) { puts "Это мой метод." }x = MyClass.newx.mymeth # Печатается "Это мой метод."То же самое можно сделать и на уровне экземпляра, а не класса:
class MyClass def new_method(name, &block) self.class.send(:define_method,name, &block) endendx = MyClass.newx.new_method(:mymeth) { puts "Это мой метод." }x.mymeth # Печатается "Это мой метод."Здесь метод экземпляра тоже определен динамически. Изменился только способ реализации метода
new_methodsenddefine_methodsendПо поводу метода
define_methodclass MyClass def self.new_method(name, &block) define_method(name, &block) endenda,b = 3,79MyClass.new_method(:compute) { a*b }x = MyClass.newputs x.compute # 237a,b = 23,24puts x.compute # 552Смысл здесь в том, что новый метод может обращаться к переменным в исходной области видимости блока, хотя сама эта область более не существует и никаким другим способом не доступна. Иногда это бывает полезно, особенно в случае метапрограммирования или при разработке графических интерфейсов, когда нужно определить методы обратного вызова, реагирующие на события.
Отметим, что замыкание оказывается таковым только тогда, когда имя переменной то же самое. Изредка из-за этого могут возникать сложности. Ниже мы воспользовались методом
define_methodclass SomeClass @@var = 999 define_method(:peek) { @@var }endx = SomeClass.new px.peek # 999А теперь попробуем проделать с переменной экземпляра класса такой трюк:
class SomeClass @var = 999 define_method(:peek) { @var }endx = SomeClass.newp x.peek # Печатается nilМы ожидали, что будет напечатано 999, а получили
nilС другой стороны, такой код работает правильно:
class SomeClass @var = 999 x = @var define_method(:peek) { x }endx = SomeClass.new px.peek # 999Так что же происходит? Да, замыкание действительно запоминает переменные в текущем контексте. Но ведь контекст нового метода - это контекст экземпляра объекта, а не самого класса.
Поскольку имя
@varВ предыдущих версиях Ruby мы часто определяли методы во время выполнения с помощью
evaldefine_method11.3.6. Метод const_missing
Метод
const_missingmethod_missingЧтобы перехватывать обращения к отсутствующим константам глобально, определите следующий метод в самом классе
ModuleClassclass Module def const_missing(x) "Из Module" endendclass Xendp X::BAR # "Из Module"p BAR # "Из Module"p Array::BAR # "Из Module"Можно выполнить в нем любые действия: вернуть фиктивное значение константы, вычислить его и т.д. Помните класс
Romanclass Module
