В некоторых языках программирования существует интерфейс для создания класса не через его определение, а через выполнение некоего кода. Этот API называется Meta-Object Protocol или MOP.
В Perl 6 есть MOP, позволяющий создавать классы, роли и грамматики, добавлять методы и атрибуты и делать интроспекцию классов. К примеру, вот как в Rakudo можно использовать вызовы MOP, чтобы узнать, как реализован тип Rat (рациональные числа). Вызовы методов MOP обычно начинаются не с точки, а с .^
$ perl6 > say join ', ', Rat.^attributes $!numerator, $!denominator > # список всех методов слишком длинный, > # поэтому мы сделаем случайную их выборку > say join ', ', Rat.^methods(:local).pick(5) unpolar, ceiling, reals, Str, round > say Rat.^methods(:local).grep('log').[0].signature.perl :(Numeric $x: Numeric $base = { ... };; *%_)
Большинство строк должны быть понятны: у объектов класса Rat есть два атрибута, $!numerator и $!denominator, и много методов. Метод log принимает значение Numeric как вызывающий метод (это отмечено двоеточием после имени параметра) и необязательный второй параметр $base, у которого есть значение по умолчанию (число Эйлера e).
Хороший пример использования можно взять из интерфейса баз данных Perl 6. У него есть возможность записывать вызовы объекта в log, ограничив при этом запись методов одной конкретной ролью (к примеру, только роли, которая занимается вопросами соединения с базой, или же вопросами извлечения данных). Вот пример:
sub log-calls($obj, Role $r) { my $wrapper = RoleHOW.new; for $r.^methods -> $m { $wrapper.^add_method($m.name, method (|$c) { # вывести протокол выполнения # note() пишет в standard error note ">> $m"; # вызвать следующий метод с тем же именем и # теми же аргументами nextsame; }); } $wrapper.^compose(); # оператор 'does' работает так же, как 'but', но # изменяет только копию объекта $obj does $wrapper; } role Greet { method greet($x) { say "hello, $x"; } } class SomeGreeter does Greet { method LOLGREET($x) { say "OH HAI "~ uc $x; } } my $o = log-calls(SomeGreeter.new, Greet); # записали в log, поскольку это отработала роль Greet $o.greet('you'); # не записали в log, поскольку это не та роль $o.LOLGREET('u');
Выводит:
>> greet hello, you OH HAI U
С использованием Meta-Object Protocol классы, роли и грамматики становятся доступны вам не только через специальный синтаксис, но и через обычный API. Это добавляет гибкости в ООП-код и позволяет проводить интроспекцию и изменения объектов.
ссылка на оригинал статьи http://habrahabr.ru/post/265199/
Добавить комментарий