SlideShare una empresa de Scribd logo
1 de 38
Динамический код:
модифицируем таблицу символов во время
выполнения
• Какие-то проблемы?
• Методы runtime-
кодогенерации
• Таблица символов:
матчасть
• От теории к практике
• Как не выстрелить себе
в ногу
• RTFM
2
• Конструкторы
• Методы-аксессоры
• Идентичная предварительная обработка
данных
• Похожие по функционалу функции с
небольшими отличиями
corp.mail.ru
Повторяющийся код
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->{field2} = $_[0] if @_;
return $self->{field2};
}
sub field3 {
my $self = shift;
$self->{field3} = $_[0] if @_;
return $self->{field3};
}
www.mail.ru 5
Аксессоры
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
Предварительная
обработка
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
Похожие функции
• Потеря времени на
перепечатывание/копирование
• Ошибки из-за невнимательности
• Трудоемкость сопровождения
corp.mail.ru
Проблемы повторяющегося кода
• Ошибки в реализации
• Отсутствие поддержки кириллицы
• Недостаточный функционал
corp.mail.ru
Сторонние модули
print Dumper {test => 'Тестовая строка'};
www.mail.ru 10
Data::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}"
};
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
• Необходимость доказательства
целесообразности
• Замусоривание системы
• Замусоривание блоков use в коде
• Снижение производительности
• Увеличение времени компиляции
• Расход памяти
• Уменьшение контроля над кодом («чужой
код»)
www.mail.ru 12
Проблемы использования
сторонних модулей
• Какие-то проблемы?
• Методы runtime-
кодогенерации
• Таблица символов:
матчасть
• От теории к практике
• Как не выстрелить себе
в ногу
• RTFM
13
• Переопределение подпрограмм
• eval
• Изменение таблицы символов
www.mail.ru 14
Модификация кода
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
Переопределение
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 16
eval
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 17
eval
• Какие-то проблемы?
• Методы runtime-
кодогенерации
• Таблица символов:
матчасть
• От теории к практике
• Как не выстрелить себе
в ногу
• RTFM
18
• Таблица символов – это хэш
www.mail.ru 19
Таблица символов
• Ключи – глобальные переменные и
подпрограммы
• Значения - тайпглобы
%PackageName::
%main::
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::data
my $fh = *FH;
*glob{PACKAGE} имя пакета
*glob{NAME} имя элемента (переменной или функции)
*glob{SCALAR} ссылка на значение-скаляр
*glob{ARRAY} ссылка на значение-массив
*glob{HASH} ссылка на значение-хэш
*glob{CODE} ссылка на подпрограмму
corp.mail.ru
Структура тайпглоба
Получение данных
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
Работа с тайпглобом
• Какие-то проблемы?
• Методы runtime-
кодогенерации
• Таблица символов:
матчасть
• От теории к практике
• Как не выстрелить себе
в ногу
• RTFM
23
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;
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__
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
• Генераторы классов: десериализация, ORM
• Реализация паттерна «прокси»
• Тестирование: mock, stub, fake object
• Хуки для подпрограмм: before, after, around
• Патчи во время выполнения
• Расширение функционала сторонних модулей
• Синонимы для устаревших функций при
рефакторинге
www.mail.ru 27
От теории к практике
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
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
Синонимы
test
Test1::old_func called at test12.pl
(40) is deprecated. Use
Test2::Test2::new_func
test
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 30
Stub
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
Хуки
wrapper
test
• Какие-то проблемы?
• Методы runtime-
кодогенерации
• Таблица символов:
матчасть
• От теории к практике
• Как не выстрелить себе
в ногу
• RTFM
32
• Прагмы strict и warnings
• __ANON__ в трассировке стэка
• Ссылки на переопределяемые функции
• Снижение читабельности кода и повышение
требований к профессиональному уровню
программистов
• Рост стэка при использовании хуков
• Пространство имен модуля
www.mail.ru 33
Проблемы
кодогенерации
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
Ссылки
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
Пространство имен
eval
• Компиляция во время
выполнения
• Ускоренная
загрузка, возможность
компиляции по запросу
• Создание символов в
пространстве имен нужного
модуля
• Неэффективная генерация
большого количества
похожих функций
Таблица символов
• Компиляция при загрузке
• Проверка синтаксиса
компилятором при запуске
• Высокая эффективность
повторного использования
генераторов
• Невозможность создания
символов в пространстве
имен нужного модуля, если
имя последнего не известно
во время компиляции
www.mail.ru 36
• perlmod: Symbol tables
• perlref
• perldata: Typeglobs and
Filehandlers
• Sriram Srinivasan.Advanced
Perl Programming
• Modern Perl
(http://modernperlbooks.com)
www.mail.ru 37
Что почитать
Шишкина Елена Владимировна
e.shishkina@corp.mail.ru

Más contenido relacionado

La actualidad más candente

Написание DSL в Perl
Написание DSL в PerlНаписание DSL в Perl
Написание DSL в Perlmayperl
 
PHP Advanced
PHP AdvancedPHP Advanced
PHP AdvancedNoveo
 
Что нового в Perl? 5.10 — 5.16
Что нового в Perl? 5.10 — 5.16Что нового в Perl? 5.10 — 5.16
Что нового в Perl? 5.10 — 5.16Anatoly Sharifulin
 
Функциональные тесты на Perl
Функциональные тесты на PerlФункциональные тесты на Perl
Функциональные тесты на PerlIlya Zelenchuk
 
Present saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasovPresent saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasovPavel Vlasov
 
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Vasya Petrov
 
Anton Shabouta "Implementing async binary clients in pure PHP"
Anton Shabouta "Implementing async binary clients in pure PHP" Anton Shabouta "Implementing async binary clients in pure PHP"
Anton Shabouta "Implementing async binary clients in pure PHP" Fwdays
 
Cобачники против кинофобов
Cобачники против кинофобовCобачники против кинофобов
Cобачники против кинофобовLidiya Myalkina
 
Groovy On Grails
Groovy On GrailsGroovy On Grails
Groovy On Grailsguest32215a
 
Web осень 2013 лекция 2
Web осень 2013 лекция 2Web осень 2013 лекция 2
Web осень 2013 лекция 2Technopark
 
Контрактное программирование
Контрактное программированиеКонтрактное программирование
Контрактное программированиеIlya Zelenchuk
 

La actualidad más candente (19)

Collider
ColliderCollider
Collider
 
Написание DSL в Perl
Написание DSL в PerlНаписание DSL в Perl
Написание DSL в Perl
 
Почему Mojolicious?
Почему Mojolicious?Почему Mojolicious?
Почему Mojolicious?
 
PHP Advanced
PHP AdvancedPHP Advanced
PHP Advanced
 
Что нового в Perl? 5.10 — 5.16
Что нового в Perl? 5.10 — 5.16Что нового в Perl? 5.10 — 5.16
Что нового в Perl? 5.10 — 5.16
 
Javascript
JavascriptJavascript
Javascript
 
Функциональные тесты на Perl
Функциональные тесты на PerlФункциональные тесты на Perl
Функциональные тесты на Perl
 
Приручаем linux-консоль
Приручаем linux-консольПриручаем linux-консоль
Приручаем linux-консоль
 
Present saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasovPresent saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasov
 
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1
 
Nginx.pm
Nginx.pmNginx.pm
Nginx.pm
 
Perl – жив?!
Perl – жив?!Perl – жив?!
Perl – жив?!
 
Anton Shabouta "Implementing async binary clients in pure PHP"
Anton Shabouta "Implementing async binary clients in pure PHP" Anton Shabouta "Implementing async binary clients in pure PHP"
Anton Shabouta "Implementing async binary clients in pure PHP"
 
Cобачники против кинофобов
Cобачники против кинофобовCобачники против кинофобов
Cобачники против кинофобов
 
Server optimization
Server optimizationServer optimization
Server optimization
 
Groovy On Grails
Groovy On GrailsGroovy On Grails
Groovy On Grails
 
Decorators' recipes
Decorators' recipesDecorators' recipes
Decorators' recipes
 
Web осень 2013 лекция 2
Web осень 2013 лекция 2Web осень 2013 лекция 2
Web осень 2013 лекция 2
 
Контрактное программирование
Контрактное программированиеКонтрактное программирование
Контрактное программирование
 

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

PHP Tricks
PHP TricksPHP Tricks
PHP TricksBlackFan
 
Страх и ненависть в исходном коде
Страх и ненависть в исходном кодеСтрах и ненависть в исходном коде
Страх и ненависть в исходном кодеKolya Korobochkin
 
Как очистить массив
Как очистить массивКак очистить массив
Как очистить массивAndrew Shitov
 
Импорт данных с фреймворком Migrate. Владислав Богатырев.
Импорт данных с фреймворком Migrate. Владислав Богатырев.Импорт данных с фреймворком Migrate. Владислав Богатырев.
Импорт данных с фреймворком Migrate. Владислав Богатырев.DrupalCampDN
 
Что нового в PHP-5.3
Что нового в PHP-5.3 Что нового в PHP-5.3
Что нового в PHP-5.3 phpclub
 
Дмитрий Щадей "Зачем и как мы используем jsLint"
Дмитрий Щадей "Зачем и как мы используем jsLint"Дмитрий Щадей "Зачем и как мы используем jsLint"
Дмитрий Щадей "Зачем и как мы используем jsLint"Yandex
 
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)ZFConf Conference
 
Толстая модель. История разработки ORM
Толстая модель. История разработки ORMТолстая модель. История разработки ORM
Толстая модель. История разработки ORMMikhail Shamin
 
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)Symfoniacs
 
Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2Ilyas Salikhov
 
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf Conference
 
Разработка на Perl под Raspberry PI
Разработка на Perl под Raspberry PIРазработка на Perl под Raspberry PI
Разработка на Perl под Raspberry PIIlya Chesnokov
 
Yii 2. Что нового?
Yii 2. Что нового?Yii 2. Что нового?
Yii 2. Что нового?yiiconf
 

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

DSLs в Perl
DSLs в PerlDSLs в Perl
DSLs в Perl
 
PHP Tricks
PHP TricksPHP Tricks
PHP Tricks
 
Страх и ненависть в исходном коде
Страх и ненависть в исходном кодеСтрах и ненависть в исходном коде
Страх и ненависть в исходном коде
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Как очистить массив
Как очистить массивКак очистить массив
Как очистить массив
 
Импорт данных с фреймворком Migrate. Владислав Богатырев.
Импорт данных с фреймворком Migrate. Владислав Богатырев.Импорт данных с фреймворком Migrate. Владислав Богатырев.
Импорт данных с фреймворком Migrate. Владислав Богатырев.
 
Perl in practice
Perl in practicePerl in practice
Perl in practice
 
Что нового в PHP-5.3
Что нового в PHP-5.3 Что нового в PHP-5.3
Что нового в PHP-5.3
 
Дмитрий Щадей "Зачем и как мы используем jsLint"
Дмитрий Щадей "Зачем и как мы используем jsLint"Дмитрий Щадей "Зачем и как мы используем jsLint"
Дмитрий Щадей "Зачем и как мы используем jsLint"
 
UWDC 2013, Yii2
UWDC 2013, Yii2UWDC 2013, Yii2
UWDC 2013, Yii2
 
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
ZFConf 2011: Толстая модель: История разработки собственного ORM (Михаил Шамин)
 
Толстая модель. История разработки ORM
Толстая модель. История разработки ORMТолстая модель. История разработки ORM
Толстая модель. История разработки ORM
 
Yserver
YserverYserver
Yserver
 
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)
Расширенное кеширование Doctrine2 (Ильяс Салихов, Intaro)
 
Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2Расширенное кеширование в Doctrine2
Расширенное кеширование в Doctrine2
 
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
 
бегун
бегунбегун
бегун
 
Rose::DB
Rose::DBRose::DB
Rose::DB
 
Разработка на Perl под Raspberry PI
Разработка на Perl под Raspberry PIРазработка на Perl под Raspberry PI
Разработка на Perl под Raspberry PI
 
Yii 2. Что нового?
Yii 2. Что нового?Yii 2. Что нового?
Yii 2. Что нового?
 

Más de Moscow.pm

О работе с документами .xls, .xlsx, .rtf
О работе с документами .xls, .xlsx, .rtfО работе с документами .xls, .xlsx, .rtf
О работе с документами .xls, .xlsx, .rtfMoscow.pm
 
Fast queue – как мы сделали свою очередь на perl и redis
Fast queue – как мы сделали свою очередь на perl и redisFast queue – как мы сделали свою очередь на perl и redis
Fast queue – как мы сделали свою очередь на perl и redisMoscow.pm
 
Perl для не программистов. Николай Мишин. Moscow.pm 4 июля 2013
Perl для не программистов. Николай Мишин. Moscow.pm 4 июля 2013Perl для не программистов. Николай Мишин. Moscow.pm 4 июля 2013
Perl для не программистов. Николай Мишин. Moscow.pm 4 июля 2013Moscow.pm
 
Язык Go для Perl-программистов v1.1. Александр Орловский. Moscow.pm 4 июля 2013
Язык Go для Perl-программистов v1.1. Александр Орловский. Moscow.pm 4 июля 2013Язык Go для Perl-программистов v1.1. Александр Орловский. Moscow.pm 4 июля 2013
Язык Go для Perl-программистов v1.1. Александр Орловский. Moscow.pm 4 июля 2013Moscow.pm
 
Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....
Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....
Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....Moscow.pm
 
Особенности создания XS-модулей на языке C++. Владимир Тимофеев. Moscow.pm 4 ...
Особенности создания XS-модулей на языке C++. Владимир Тимофеев. Moscow.pm 4 ...Особенности создания XS-модулей на языке C++. Владимир Тимофеев. Moscow.pm 4 ...
Особенности создания XS-модулей на языке C++. Владимир Тимофеев. Moscow.pm 4 ...Moscow.pm
 
Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...
Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...
Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...Moscow.pm
 
Преобразование Perl-структур в XML. Трефилова Екатерина. Moscow.pm 6 июля 2013
Преобразование Perl-структур в XML. Трефилова Екатерина. Moscow.pm 6 июля 2013Преобразование Perl-структур в XML. Трефилова Екатерина. Moscow.pm 6 июля 2013
Преобразование Perl-структур в XML. Трефилова Екатерина. Moscow.pm 6 июля 2013Moscow.pm
 
Play Perl — распределенная социальная игра для Perl-разработчиков. Вячеслав М...
Play Perl — распределенная социальная игра для Perl-разработчиков. Вячеслав М...Play Perl — распределенная социальная игра для Perl-разработчиков. Вячеслав М...
Play Perl — распределенная социальная игра для Perl-разработчиков. Вячеслав М...Moscow.pm
 

Más de Moscow.pm (9)

О работе с документами .xls, .xlsx, .rtf
О работе с документами .xls, .xlsx, .rtfО работе с документами .xls, .xlsx, .rtf
О работе с документами .xls, .xlsx, .rtf
 
Fast queue – как мы сделали свою очередь на perl и redis
Fast queue – как мы сделали свою очередь на perl и redisFast queue – как мы сделали свою очередь на perl и redis
Fast queue – как мы сделали свою очередь на perl и redis
 
Perl для не программистов. Николай Мишин. Moscow.pm 4 июля 2013
Perl для не программистов. Николай Мишин. Moscow.pm 4 июля 2013Perl для не программистов. Николай Мишин. Moscow.pm 4 июля 2013
Perl для не программистов. Николай Мишин. Moscow.pm 4 июля 2013
 
Язык Go для Perl-программистов v1.1. Александр Орловский. Moscow.pm 4 июля 2013
Язык Go для Perl-программистов v1.1. Александр Орловский. Moscow.pm 4 июля 2013Язык Go для Perl-программистов v1.1. Александр Орловский. Moscow.pm 4 июля 2013
Язык Go для Perl-программистов v1.1. Александр Орловский. Moscow.pm 4 июля 2013
 
Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....
Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....
Разработка документации для RESTful API: как убить трёх зайцев одним. Moscow....
 
Особенности создания XS-модулей на языке C++. Владимир Тимофеев. Moscow.pm 4 ...
Особенности создания XS-модулей на языке C++. Владимир Тимофеев. Moscow.pm 4 ...Особенности создания XS-модулей на языке C++. Владимир Тимофеев. Moscow.pm 4 ...
Особенности создания XS-модулей на языке C++. Владимир Тимофеев. Moscow.pm 4 ...
 
Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...
Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...
Ленивые итераторы для разбора разнородных данных. Михаил Озеров. Moscow.pm 6 ...
 
Преобразование Perl-структур в XML. Трефилова Екатерина. Moscow.pm 6 июля 2013
Преобразование Perl-структур в XML. Трефилова Екатерина. Moscow.pm 6 июля 2013Преобразование Perl-структур в XML. Трефилова Екатерина. Moscow.pm 6 июля 2013
Преобразование Perl-структур в XML. Трефилова Екатерина. Moscow.pm 6 июля 2013
 
Play Perl — распределенная социальная игра для Perl-разработчиков. Вячеслав М...
Play Perl — распределенная социальная игра для Perl-разработчиков. Вячеслав М...Play Perl — распределенная социальная игра для Perl-разработчиков. Вячеслав М...
Play Perl — распределенная социальная игра для Perl-разработчиков. Вячеслав М...
 

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

  • 1. Динамический код: модифицируем таблицу символов во время выполнения
  • 2. • Какие-то проблемы? • Методы runtime- кодогенерации • Таблица символов: матчасть • От теории к практике • Как не выстрелить себе в ногу • RTFM 2
  • 3. • Конструкторы • Методы-аксессоры • Идентичная предварительная обработка данных • Похожие по функционалу функции с небольшими отличиями corp.mail.ru Повторяющийся код
  • 4. package Foo; sub new { return bless {}, shift; } package Bar; sub new { return bless {}, shift; } www.mail.ru 4 Конструкторы
  • 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. 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. 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. • Потеря времени на перепечатывание/копирование • Ошибки из-за невнимательности • Трудоемкость сопровождения corp.mail.ru Проблемы повторяющегося кода
  • 9. • Ошибки в реализации • Отсутствие поддержки кириллицы • Недостаточный функционал corp.mail.ru Сторонние модули
  • 10. print Dumper {test => 'Тестовая строка'}; www.mail.ru 10 Data::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. 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. • Необходимость доказательства целесообразности • Замусоривание системы • Замусоривание блоков use в коде • Снижение производительности • Увеличение времени компиляции • Расход памяти • Уменьшение контроля над кодом («чужой код») www.mail.ru 12 Проблемы использования сторонних модулей
  • 13. • Какие-то проблемы? • Методы runtime- кодогенерации • Таблица символов: матчасть • От теории к практике • Как не выстрелить себе в ногу • RTFM 13
  • 14. • Переопределение подпрограмм • eval • Изменение таблицы символов www.mail.ru 14 Модификация кода
  • 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. 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 16 eval
  • 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 17 eval
  • 18. • Какие-то проблемы? • Методы runtime- кодогенерации • Таблица символов: матчасть • От теории к практике • Как не выстрелить себе в ногу • RTFM 18
  • 19. • Таблица символов – это хэш www.mail.ru 19 Таблица символов • Ключи – глобальные переменные и подпрограммы • Значения - тайпглобы %PackageName:: %main::
  • 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::data my $fh = *FH;
  • 21. *glob{PACKAGE} имя пакета *glob{NAME} имя элемента (переменной или функции) *glob{SCALAR} ссылка на значение-скаляр *glob{ARRAY} ссылка на значение-массив *glob{HASH} ссылка на значение-хэш *glob{CODE} ссылка на подпрограмму corp.mail.ru Структура тайпглоба
  • 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. • Какие-то проблемы? • Методы runtime- кодогенерации • Таблица символов: матчасть • От теории к практике • Как не выстрелить себе в ногу • RTFM 23
  • 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. 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. 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. • Генераторы классов: десериализация, ORM • Реализация паттерна «прокси» • Тестирование: mock, stub, fake object • Хуки для подпрограмм: before, after, around • Патчи во время выполнения • Расширение функционала сторонних модулей • Синонимы для устаревших функций при рефакторинге www.mail.ru 27 От теории к практике
  • 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. 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 Синонимы test Test1::old_func called at test12.pl (40) is deprecated. Use Test2::Test2::new_func test
  • 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 30 Stub
  • 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 Хуки wrapper test
  • 32. • Какие-то проблемы? • Методы runtime- кодогенерации • Таблица символов: матчасть • От теории к практике • Как не выстрелить себе в ногу • RTFM 32
  • 33. • Прагмы strict и warnings • __ANON__ в трассировке стэка • Ссылки на переопределяемые функции • Снижение читабельности кода и повышение требований к профессиональному уровню программистов • Рост стэка при использовании хуков • Пространство имен модуля www.mail.ru 33 Проблемы кодогенерации
  • 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. 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. eval • Компиляция во время выполнения • Ускоренная загрузка, возможность компиляции по запросу • Создание символов в пространстве имен нужного модуля • Неэффективная генерация большого количества похожих функций Таблица символов • Компиляция при загрузке • Проверка синтаксиса компилятором при запуске • Высокая эффективность повторного использования генераторов • Невозможность создания символов в пространстве имен нужного модуля, если имя последнего не известно во время компиляции www.mail.ru 36
  • 37. • perlmod: Symbol tables • perlref • perldata: Typeglobs and Filehandlers • Sriram Srinivasan.Advanced Perl Programming • Modern Perl (http://modernperlbooks.com) www.mail.ru 37 Что почитать