Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Динамический код:модифицируем таблицу символов во времявыполнения
• Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себ...
• Конструкторы• Методы-аксессоры• Идентичная предварительная обработкаданных• Похожие по функционалу функции снебольшими о...
package Foo;sub new {return bless {}, shift;}package Bar;sub new {return bless {}, shift;}www.mail.ru 4Конструкторы
sub field1 {my $self = shift;$self->{field1} = $_[0] if @_;return $self->{field1};}sub field2 {my $self = shift;$self->{fi...
sub do_something {my $self = shift;$self->check_cookies;return $self->redirect(/login) unless $self->check_auth;my $form =...
sub error {my $message = shift;my ($package, $line, $sub) = (caller(0))[0, 2, 3];print $log scalar localtime, "ERROR: ${pa...
• Потеря времени наперепечатывание/копирование• Ошибки из-за невнимательности• Трудоемкость сопровожденияcorp.mail.ruПробл...
• Ошибки в реализации• Отсутствие поддержки кириллицы• Недостаточный функционалcorp.mail.ruСторонние модули
print Dumper {test => Тестовая строка};www.mail.ru 10Data::Dumper икириллица в utf8$VAR1 = {"test" =>"x{422}x{435}x{441}x{...
package Foo;use Moose;has field1 => (is => rw);has field2 => (is => rw);has field3 => (is => rw);around [qw(do_something d...
• Необходимость доказательствацелесообразности• Замусоривание системы• Замусоривание блоков use в коде• Снижение производи...
• Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себ...
• Переопределение подпрограмм• eval• Изменение таблицы символовwww.mail.ru 14Модификация кода
use Data::Dumper;$Data::Dumper::Useqq = 1;{no warnings redefine;package Data::Dumper;sub Data::Dumper::qquote {my $s = shi...
package Wrapper;sub make_accessors {my $package = caller(0);for (@_) {eval qq{package $package;sub $_ {my $self = shift;$s...
package Test;use Wrapper;sub new { return bless {}, shift; }Wrapper::make_accessors( qw(name age) );package main;use Test;...
• Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себ...
• Таблица символов – это хэшwww.mail.ru 19Таблица символов• Ключи – глобальные переменные иподпрограммы• Значения - тайпгл...
www.mail.ru 20Таблица символовpackage Test;our $data = test;our @data = qw(1 2 3);our %data = (key1 => value1, key2 =>valu...
*glob{PACKAGE} имя пакета*glob{NAME} имя элемента (переменной или функции)*glob{SCALAR} ссылка на значение-скаляр*glob{ARR...
Получение данныхmy $scalar = ${ *Test::data };my %hash = %{ *Test::data };my @array = @{ *Test::data };&{ *Test::data }();...
• Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себ...
package MakeAccessor;sub import {my $package = caller(0);no strict refs;*{"$package::has"} = &has;}sub has ($) {my $name =...
package MakeAccessor;sub import {my $package = caller(0);no strict refs;*{"$package::has"} = &has;}sub has ($) {my $name =...
www.mail.ru 26Боремся с __ANON__package MakeAccessor;sub import {my $package = caller(0);no strict refs;*{"$package::has"}...
• Генераторы классов: десериализация, ORM• Реализация паттерна «прокси»• Тестирование: mock, stub, fake object• Хуки для п...
package Response;use CGI;sub new {return bless { cgi => CGI->new }, shift;}our $AUTOLOAD;sub AUTOLOAD {my ($method) = $AUT...
package Wrapper;sub make_deprecated {my $deprecated = shift;{no strict refs;return if *{$deprecated}{CODE};};my $package =...
use Test::More;my $user_data = { ... };{no strict refs;*{Cache::Memcached::set} = sub {return 1;};*{Cache::Memcached::get}...
package Wrapper;sub before(@&) {my ($methods, $wrapper) = @_;my $package = caller(0);for my $method (@$methods) {my $orig ...
• Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себ...
• Прагмы strict и warnings• __ANON__ в трассировке стэка• Ссылки на переопределяемые функции• Снижение читабельности кода ...
use Data::Dumper;*{Data::Dumper::Dumper} = sub {return Hacked!;};say Dumper({key1 => 1, key2 => 2});say Data::Dumper::Dump...
package Wrapper;our $name = Ann;*{Test::test} = sub {say $name;say $Test::name;};package Test;our $name = Bob;package main...
eval• Компиляция во времявыполнения• Ускореннаязагрузка, возможностькомпиляции по запросу• Создание символов впространстве...
• perlmod: Symbol tables• perlref• perldata: Typeglobs andFilehandlers• Sriram Srinivasan.AdvancedPerl Programming• Modern...
Шишкина Елена Владимировнаe.shishkina@corp.mail.ru
Upcoming SlideShare
Loading in …5
×

Динамический код: модифицируем таблицу символов во время выполнения. Елена Шишкина. Moscow.pm 4 апреля

6,776 views

Published on

Видео: http://video.mail.ru/corp/p.scherbinin/6/7.html

Tаблица символов — это только небольшой шаг в мир внутреннего устройства Perl, но и он открывает программисту огромные возможности:

— Runtime-кодогенерация.

— Генерация по запросу.

— Изменение кода сторонних модулей на лету и многое другое.

Published in: Technology
  • читаю, читаю и некоторых вещей не могу вкурить и зачем нужна эта кодогенерация? у меня и без нее перловые объекты нормально работают, а их геттеры и сеттеры я могу увидеть в тексте программы, в общем технологиями, описанными в этой презентации нужно пользоваться с большой осторожностью!
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Динамический код: модифицируем таблицу символов во время выполнения. Елена Шишкина. Moscow.pm 4 апреля

  1. 1. Динамический код:модифицируем таблицу символов во времявыполнения
  2. 2. • Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себев ногу• RTFM2
  3. 3. • Конструкторы• Методы-аксессоры• Идентичная предварительная обработкаданных• Похожие по функционалу функции снебольшими отличиямиcorp.mail.ruПовторяющийся код
  4. 4. package Foo;sub new {return bless {}, shift;}package Bar;sub new {return bless {}, shift;}www.mail.ru 4Конструкторы
  5. 5. sub field1 {my $self = shift;$self->{field1} = $_[0] if @_;return $self->{field1};}sub field2 {my $self = shift;$self->{field2} = $_[0] if @_;return $self->{field2};}sub field3 {my $self = shift;$self->{field3} = $_[0] if @_;return $self->{field3};}www.mail.ru 5Аксессоры
  6. 6. sub do_something {my $self = shift;$self->check_cookies;return $self->redirect(/login) unless $self->check_auth;my $form = $self->load_form(do_something);$form->fetch;return $self->render_error() unless $form->validate;my $some_user_data = $self->load_user_data;...}sub do_another_thing {my $self = shift;$self->check_cookies;...}www.mail.ru 6Предварительнаяобработка
  7. 7. sub error {my $message = shift;my ($package, $line, $sub) = (caller(0))[0, 2, 3];print $log scalar localtime, "ERROR: ${package}::$sub ($line): $messagen";print $log Carp::longmess if $Trace_Errors;}sub debug {my $message = shift;my ($package, $line, $sub) = (caller(0))[0, 2, 3];print $log scalar localtime, "DEBUG: ${package}::$sub ($line): $messagen";}sub info { ... }sub warning { ... }www.mail.ru 7Похожие функции
  8. 8. • Потеря времени наперепечатывание/копирование• Ошибки из-за невнимательности• Трудоемкость сопровожденияcorp.mail.ruПроблемы повторяющегося кода
  9. 9. • Ошибки в реализации• Отсутствие поддержки кириллицы• Недостаточный функционалcorp.mail.ruСторонние модули
  10. 10. print Dumper {test => Тестовая строка};www.mail.ru 10Data::Dumper икириллица в utf8$VAR1 = {"test" =>"x{422}x{435}x{441}x{442}x{43e}x{432}x{430}x{44f} x{441}x{442}x{440}x{43e}x{43a}x{430}"};
  11. 11. package Foo;use Moose;has field1 => (is => rw);has field2 => (is => rw);has field3 => (is => rw);around [qw(do_something do_another_thing)] => sub {my ($orig, $self) = @_;...$self->$orig(form => $form, user_data => $some_user_data);};www.mail.ru 11Решение: CPAN
  12. 12. • Необходимость доказательствацелесообразности• Замусоривание системы• Замусоривание блоков use в коде• Снижение производительности• Увеличение времени компиляции• Расход памяти• Уменьшение контроля над кодом («чужойкод»)www.mail.ru 12Проблемы использованиясторонних модулей
  13. 13. • Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себев ногу• RTFM13
  14. 14. • Переопределение подпрограмм• eval• Изменение таблицы символовwww.mail.ru 14Модификация кода
  15. 15. use Data::Dumper;$Data::Dumper::Useqq = 1;{no warnings redefine;package Data::Dumper;sub Data::Dumper::qquote {my $s = shift;return "$s";}}www.mail.ru 15Переопределение
  16. 16. package Wrapper;sub make_accessors {my $package = caller(0);for (@_) {eval qq{package $package;sub $_ {my $self = shift;$self->{$_} = $_[0] if @_;return $self->{$_};}};}}www.mail.ru 16eval
  17. 17. package Test;use Wrapper;sub new { return bless {}, shift; }Wrapper::make_accessors( qw(name age) );package main;use Test;my $obj = Test->new;$obj->name(Ann);say $obj->name;www.mail.ru 17eval
  18. 18. • Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себев ногу• RTFM18
  19. 19. • Таблица символов – это хэшwww.mail.ru 19Таблица символов• Ключи – глобальные переменные иподпрограммы• Значения - тайпглобы%PackageName::%main::
  20. 20. www.mail.ru 20Таблица символовpackage Test;our $data = test;our @data = qw(1 2 3);our %data = (key1 => value1, key2 =>value2);sub data { return 0; }package main;say $Test::{$_} for keys %Test::;*Test::datamy $fh = *FH;
  21. 21. *glob{PACKAGE} имя пакета*glob{NAME} имя элемента (переменной или функции)*glob{SCALAR} ссылка на значение-скаляр*glob{ARRAY} ссылка на значение-массив*glob{HASH} ссылка на значение-хэш*glob{CODE} ссылка на подпрограммуcorp.mail.ruСтруктура тайпглоба
  22. 22. Получение данныхmy $scalar = ${ *Test::data };my %hash = %{ *Test::data };my @array = @{ *Test::data };&{ *Test::data }();Запись данных*Test::data = new value;*Test::data = [4, 5, 6];*Test::data = {key3 => value3,key4 => value4‘};*Test::data = sub { return 1; };www.mail.ru 22Работа с тайпглобом
  23. 23. • Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себев ногу• RTFM23
  24. 24. package MakeAccessor;sub import {my $package = caller(0);no strict refs;*{"$package::has"} = &has;}sub has ($) {my $name = shift;my $package = caller(0);no strict refs;*{"$package::$name"} = sub {my $self = shift;$self->{$name} = $_[0] if @_;return $self->{$name};};}www.mail.ru 24Генерация аксессоровpackage Test;use MakeAccessor;has name;has age;sub new { return bless{}, shift; }package main;my $o = Test->new;$o->name(Ann);say $o->name;
  25. 25. package MakeAccessor;sub import {my $package = caller(0);no strict refs;*{"$package::has"} = &has;}sub has ($) {my $name = shift;my $package = caller(0);no strict refs;*{"$package::$name"} = sub {my $self = shift;say ((caller(0))[3]);$self->{$name} = $_[0] if @_;return $self->{$name};};}www.mail.ru 25Боремся с __ANON__MakeAccessor::__ANON__
  26. 26. www.mail.ru 26Боремся с __ANON__package MakeAccessor;sub import {my $package = caller(0);no strict refs;*{"$package::has"} = &has;}sub has ($) {my $name = shift;my $package = caller(0);my $method = sub {local *__ANON__ = "$package::$name";my $self = shift;$self->{$name} = $_[0] if @_;return $self->{$name};};no strict refs;*{"$package::$name"} = $method;}Test::name
  27. 27. • Генераторы классов: десериализация, ORM• Реализация паттерна «прокси»• Тестирование: mock, stub, fake object• Хуки для подпрограмм: before, after, around• Патчи во время выполнения• Расширение функционала сторонних модулей• Синонимы для устаревших функций прирефакторингеwww.mail.ru 27От теории к практике
  28. 28. package Response;use CGI;sub new {return bless { cgi => CGI->new }, shift;}our $AUTOLOAD;sub AUTOLOAD {my ($method) = $AUTOLOAD =~ /([^:]+)$/;return if $method eq DESTROY;return unless CGI->can($method);my $sub = sub {local *__ANON__ = $AUTOLOAD;my $self = shift;return $self->{cgi}->$method(@_);};{ no strict refs;*{$AUTOLOAD} = $sub;};return $sub->(@_);}www.mail.ru 28Проксиpackage main;my $obj = Response->new;print $obj->header(text/html);Content-Type:text/html;charset=ISO-8859-1
  29. 29. package Wrapper;sub make_deprecated {my $deprecated = shift;{no strict refs;return if *{$deprecated}{CODE};};my $package = scalar caller(0);my $method = (caller(1))[3];my $func = sub {local *__ANON__ = $deprecated;warn "$deprecated called at " . sprintf("%s(%s)", (caller)[1, 2]) . " is deprecated. Use$package::$methodn";eval "use $package;" unless $package->can(can);my $sub = $package->can($method);$sub->(@_);};no strict refs;*{$deprecated} = $func;}package Test1;package Test2;sub new_func {Wrapper::make_deprecated(Test1::old_func);return test;}package main;say Test2::new_func();say Test1::old_func();www.mail.ru 29СинонимыtestTest1::old_func called at test12.pl(40) is deprecated. UseTest2::Test2::new_functest
  30. 30. use Test::More;my $user_data = { ... };{no strict refs;*{Cache::Memcached::set} = sub {return 1;};*{Cache::Memcached::get} = sub {return to_json($user_data);};};is_deeply($user->get_info($session_id), $user_data, Some test...);www.mail.ru 30Stub
  31. 31. package Wrapper;sub before(@&) {my ($methods, $wrapper) = @_;my $package = caller(0);for my $method (@$methods) {my $orig = $package->can($method);my $sub = sub {local *__ANON__ ="$package::$method";$wrapper->(@_);$orig->(@_);};no strict refs;*{"$package::$method"} = $sub;}}package Test;sub test { say test; }Wrapper::before [ test ], sub { say wrapper;};package main;Test::test();www.mail.ru 31Хукиwrappertest
  32. 32. • Какие-то проблемы?• Методы runtime-кодогенерации• Таблица символов:матчасть• От теории к практике• Как не выстрелить себев ногу• RTFM32
  33. 33. • Прагмы strict и warnings• __ANON__ в трассировке стэка• Ссылки на переопределяемые функции• Снижение читабельности кода и повышениетребований к профессиональному уровнюпрограммистов• Рост стэка при использовании хуков• Пространство имен модуляwww.mail.ru 33Проблемыкодогенерации
  34. 34. use Data::Dumper;*{Data::Dumper::Dumper} = sub {return Hacked!;};say Dumper({key1 => 1, key2 => 2});say Data::Dumper::Dumper({key1 => 1, key2 => 2});www.mail.ru 34Ссылки
  35. 35. package Wrapper;our $name = Ann;*{Test::test} = sub {say $name;say $Test::name;};package Test;our $name = Bob;package main;Test::test();www.mail.ru 35Пространство имен
  36. 36. eval• Компиляция во времявыполнения• Ускореннаязагрузка, возможностькомпиляции по запросу• Создание символов впространстве имен нужногомодуля• Неэффективная генерациябольшого количествапохожих функцийТаблица символов• Компиляция при загрузке• Проверка синтаксисакомпилятором при запуске• Высокая эффективностьповторного использованиягенераторов• Невозможность созданиясимволов в пространствеимен нужного модуля, еслиимя последнего не известново время компиляцииwww.mail.ru 36
  37. 37. • perlmod: Symbol tables• perlref• perldata: Typeglobs andFilehandlers• Sriram Srinivasan.AdvancedPerl Programming• Modern Perl(http://modernperlbooks.com)www.mail.ru 37Что почитать
  38. 38. Шишкина Елена Владимировнаe.shishkina@corp.mail.ru

×