Чтение онлайн

на главную

Жанры

Программирование на языке Ruby
Шрифт:

# Работает (Object - это контекст верхнего уровня).

if today =~ /Saturday | Sunday/

 Object.class_eval { define_method(:activity) { puts "Отдыхаем!" } }

else

 Object.class_eval { define_method(:activity) { puts "Работаем!" } }

end

activity

Можно было бы поступить так же внутри определения класса (в применении к классу

Object
или любому другому). Такое редко бывает оправданно, но если вы можете сделать это внутри определения класса, вопрос о закрытости не встает.

class MyClass

 define_method(:mymeth) { puts "Это мой метод." }

end

Есть еще один трюк: включить в класс метод, который сам вызывает

define_method
, избавляя от этого программиста:

class MyClass

 def self.new_method(name, &block)

define_method(name, &block)

 end

end

MyClass.new_method(:mymeth) { puts "Это мой метод." }

x = MyClass.new

x.mymeth # Печатается "Это мой метод."

То же самое можно сделать и на уровне экземпляра, а не класса:

class MyClass

 def new_method(name, &block)

self.class.send(:define_method,name, &block)

 end

end

x = MyClass.new

x.new_method(:mymeth) { puts "Это мой метод." }

x.mymeth # Печатается "Это мой метод."

Здесь метод экземпляра тоже определен динамически. Изменился только способ реализации метода

new_method
. Обратите внимание на трюк с
send
, позволивший нам обойти закрытость метода
define_method
. Он работает, потому что в текущей версии Ruby метод
send
позволяет вызывать закрытые методы. (Некоторые сочтут это «дыркой»; как бы то ни было, пользоваться этим механизмом следует с осторожностью.)

По поводу метода

define_method
нужно сделать еще одно замечание. Он принимает блок, а в Ruby блок — замыкание. Это означает, что в отличие от обычного определения метода, мы запоминаем контекст, в котором метод был определен. Следующий пример практически бесполезен, но этот момент иллюстрирует:

class MyClass

 def self.new_method(name, &block)

define_method(name, &block)

 end

end

a,b = 3,79

MyClass.new_method(:compute) { a*b }

x = MyClass.new

puts x.compute # 237

a,b = 23,24

puts x.compute # 552

Смысл здесь в том, что новый метод может обращаться к переменным в исходной области видимости блока, хотя сама эта область более не существует и никаким другим способом не доступна. Иногда это бывает полезно, особенно в случае метапрограммирования или при разработке графических интерфейсов, когда нужно определить методы обратного вызова, реагирующие на события.

Отметим, что замыкание оказывается таковым только тогда, когда имя переменной то же самое. Изредка из-за этого могут возникать сложности. Ниже мы воспользовались методом

define_method
, чтобы предоставить доступ к переменной класса (вообще-то это следует делать не так, но для иллюстрации подойдет):

class SomeClass

 @@var = 999

 define_method(:peek) { @@var }

end

x = SomeClass.new p

x.peek # 999

А теперь попробуем проделать с переменной экземпляра класса такой трюк:

class SomeClass

 @var = 999

 define_method(:peek) { @var }

end

x = SomeClass.new

p x.peek # Печатается nil

Мы ожидали, что будет напечатано 999, а получили

nil
. Почему? Объясню чуть позже.

С другой стороны, такой код работает правильно:

class SomeClass

 @var = 999

 x = @var

 define_method(:peek) { x }

end

x = SomeClass.new p

x.peek # 999

Так что же происходит? Да, замыкание действительно запоминает переменные в текущем контексте. Но ведь контекст нового метода - это контекст экземпляра объекта, а не самого класса.

Поскольку имя

@var
в этом контексте относится к переменной экземпляра объекта, а не класса, то переменная экземпляра класса оказывается скрыта переменной экземпляра объекта, хотя последняя никогда не использовалась и технически не существует.

В предыдущих версиях Ruby мы часто определяли методы во время выполнения с помощью

eval
. В принципе во всех таких случаях может и должен использоваться метод
define_method
. Некоторые тонкости вроде рассмотренной выше не должны вас останавливать.

11.3.6. Метод const_missing

Метод

const_missing
аналогичен методу
method_missing
. При попытке обратиться к неизвестной константе вызывается этот метод — если он, конечно, определен. В качестве параметра ему передается символ, ссылающийся на константу.

Поделиться:
Популярные книги

Лекарь Империи 7

Карелин Сергей Витальевич
7. Лекарь Империи
Фантастика:
городское фэнтези
аниме
боевая фантастика
попаданцы
5.00
рейтинг книги
Лекарь Империи 7

Глэрд VIII: Базис 2

Владимиров Денис
8. Глэрд
Фантастика:
фэнтези
боевая фантастика
попаданцы
5.00
рейтинг книги
Глэрд VIII: Базис 2

Наследие Маозари 5

Панежин Евгений
5. Наследие Маозари
Фантастика:
фэнтези
юмористическое фэнтези
5.00
рейтинг книги
Наследие Маозари 5

Звездная Кровь. Экзарх II

Рокотов Алексей
2. Экзарх
Старинная литература:
прочая старинная литература
5.00
рейтинг книги
Звездная Кровь. Экзарх II

Академия

Сай Ярослав
2. Медорфенов
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Академия

Я уже граф. Книга VII

Дрейк Сириус
7. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я уже граф. Книга VII

Барон отрицает правила

Ренгач Евгений
13. Закон сильного
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Барон отрицает правила

Я еще не барон

Дрейк Сириус
1. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я еще не барон

Неудержимый. Книга XXX

Боярский Андрей
30. Неудержимый
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Неудержимый. Книга XXX

Московское золото и нежная попа комсомолки. Часть Пятая

Хренов Алексей
5. Летчик Леха
Фантастика:
попаданцы
5.00
рейтинг книги
Московское золото и нежная попа комсомолки. Часть Пятая

Законы Рода. Том 11

Андрей Мельник
11. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Законы Рода. Том 11

Зодчий. Книга II

Погуляй Юрий Александрович
2. Зодчий Империи
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Зодчий. Книга II

Кодекс Охотника. Книга X

Винокуров Юрий
10. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
6.25
рейтинг книги
Кодекс Охотника. Книга X

Санек 3

Седой Василий
3. Санек
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Санек 3