Многие из вас слышали о замечательном методе inherited.
Если кто-то не понимает о чем сейчас идёт речь, то поясню, что этот метод вызывается, когда какой-нибудь класс унаследовал другой (базовый) класс. Сегодня вы узнаете, как этот метод может быть полез в хозяйстве ;)
Например:
class A def self.inherited(child) puts “Now I am parent of class #{child}!” end end class B < A end #=> “Now I am parent of class B”
Такие методы называются методами обратного вызова (callback).
Но для чего оно может пригодиться нам?
Например, вы разрабатываете свой фреймворк и вам необходимо узнать о классах, которые унаследовали базовый класс:
class MyController < MyFrameWork::Base
На этой недели я разрабатывал свою систему виджетов, и воспользовался этой техникой:
class MyCustomWidget < Widgets::Base
Скрипт читал каждый .rb файл в директории “widgets” и загружал его в память. Как только интерпретатор замечал, что какой-нибудь класс унаследовал Widgets::Base, он сразу заносил имя этого класса в хранилище.
Проблема в том, что при срабатывании метода inherited вам недоступны методы, объявленные в теле класса – потомка. Потому что интерпретатор еще не успел занести методы класса в память. Это может стать проблемой. Я обошел эту проблему простым путём: узнал о всех классах, унаследовавших базовый класс, позволил интерпретатору загрузить методы классов, а уже после этого создал объекты классов:
def initialize self.pool = EasyWidgets::Pool.new self.load_widgets self.pool.init_objects_pool end
Более подробно об объектном пуле
Хорошо это или плохо?
С одной стороны вам не нужно создавать и следовать naming-convention. Как, например в Rails:
[main_controller.rb]: MainController < базовый_класс
Вы сможете делать что-то вроде этого:
[любое_имя_файла.rb]: MySuperClass < базовый_класс
Меня огорчил тот факт, что метод inherited срабатывает ДО того, как руби занёс методы класса в память.
Но по сути это не является серьезной проблемой.
Я думаю это первое «ограничение», которое мне удалось встретить при работе с ruby :)
{ 2 comments… read them below or add one }
Скорей всего, это ограничение сделано специально с целью предотвращения утечки памяти или еще по какому-то мотиву, при этом разработчики Ruby позаботились о несложных обходных маневрах. Это повсеместная практика разработки на Ruby: зделать несколько сложнее написание потенциально опасного кода. Например, Ruby защищает методы и атрибуты private классов, однако, фактически можно получить доступ к чему угодно используя instance_eval() и send().
«Более подробно об объектном пуле»
ссылка не работает
«self.pool = EasyWidgets::Pool.new»
а почему не @pool = EasyWidgets::Pool.new
pool это же instance variable