SlideShare una empresa de Scribd logo
1 de 38
Descargar para leer sin conexión
Динамический код:
модифицируем таблицу символов во время
             выполнения
• Какие-то проблемы?
• Методы 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
Data::Dumper и
                   кириллица в utf8
print Dumper {test => 'Тестовая строка'};


  $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}"
          };




                     www.mail.ru                         10
Решение: CPAN

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
Проблемы использования
                сторонних модулей

• Необходимость доказательства
  целесообразности
• Замусоривание системы
• Замусоривание блоков 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
eval

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
• Какие-то проблемы?
• Методы runtime-
  кодогенерации
• Таблица символов:
  матчасть
• От теории к практике
• Как не выстрелить себе
  в ногу
• RTFM

                           18
Таблица символов

• Таблица символов – это хэш
  %PackageName::
  %main::
• Ключи – глобальные переменные и
  подпрограммы
• Значения - тайпглобы




                   www.mail.ru      19
Таблица символов

package Test;


our $data = 'test';                      *Test::data
our @data = qw(1 2 3);
our %data = (key1 => 'value1', key2 =>
'value2');

                                         my $fh = *FH;
sub data { return 0; }


package main;
say $Test::{$_} for keys %Test::;




                           www.mail.ru                    20
Структура тайпглоба




*glob{PACKAGE}         имя пакета
*glob{NAME}            имя элемента (переменной или функции)
*glob{SCALAR}          ссылка на значение-скаляр
*glob{ARRAY}           ссылка на значение-массив
*glob{HASH}            ссылка на значение-хэш
*glob{CODE}            ссылка на подпрограмму




                      corp.mail.ru
Работа с тайпглобом

Получение данных                      Запись данных
my $scalar = ${ *Test::data };        *Test::data = 'new value';
my %hash    = %{ *Test::data };       *Test::data = [4, 5, 6];
my @array   = @{ *Test::data };       *Test::data = {
&{ *Test::data }();                          key3 => 'value3',
                                             key4 => 'value4‘
                                      };
                                      *Test::data = sub { return 1; };




                            www.mail.ru                              22
• Какие-то проблемы?
• Методы runtime-
  кодогенерации
• Таблица символов:
  матчасть
• От теории к практике
• Как не выстрелить себе
  в ногу
• RTFM

                           23
Генерация аксессоров

package MakeAccessor;                             package Test;
sub import {                                      use MakeAccessor;
    my $package = caller(0);
    no strict 'refs';
                                                  has 'name';
    *{"$package::has"} = &has;
                                                  has 'age';
}


sub has ($) {                                     sub new { return bless {},
    my $name = shift;
                                                  shift; }
    my $package = caller(0);
    no strict 'refs';                             package main;
    *{"$package::$name"} = sub {
         my $self = shift;                        my $o = Test->new;
         $self->{$name} = $_[0] if @_;            $o->name('Ann');
         return $self->{$name};
                                                  say $o->name;
    };
}


                                    www.mail.ru                                24
Боремся с __ANON__
package MakeAccessor;
sub import {
    my $package = caller(0);
    no strict 'refs';
    *{"$package::has"} = &has;
}

sub has ($) {
    my $name = shift;
    my $package = caller(0);                    MakeAccessor::__ANON__
    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__

package MakeAccessor;

sub import {
    my $package = caller(0);
    no strict 'refs';
    *{"$package::has"} = &has;
}

sub has ($) {
    my $name = shift;
                                                    Test::name
    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;
}




                                      www.mail.ru                26
От теории к практике

•   Генераторы классов: десериализация, ORM
•   Реализация паттерна «прокси»
•   Тестирование: mock, stub, fake object
•   Хуки для подпрограмм: before, after, around
•   Патчи во время выполнения
•   Расширение функционала сторонних модулей
•   Синонимы для устаревших функций при
    рефакторинге

                   www.mail.ru                27
Прокси
package Response;                                package main;
use CGI;                                         my $obj = Response->new;
sub new {
                                                 print $obj->header('text/html');
    return bless { cgi => CGI->new }, shift;
}
our $AUTOLOAD;
sub AUTOLOAD {
    my ($method) = $AUTOLOAD =~ /([^:]+)$/;
                                                 Content-Type: text/html;
    return if $method eq 'DESTROY';
    return unless CGI->can($method);             charset=ISO-8859-1
    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 Wrapper;                                                package Test1;

sub make_deprecated {                                           package Test2;
    my $deprecated = shift;
    {                                                           sub new_func {
        no strict 'refs';                                           Wrapper::make_deprecated(
        return if *{$deprecated}{CODE};                                 'Test1::old_func');
    };                                                              return 'test';
    my $package = scalar caller(0);                             }
    my $method = (caller(1))[3];
                                                                package main;
    my $func = sub {                                            say Test2::new_func();
        local *__ANON__ = $deprecated;                          say Test1::old_func();
        warn "$deprecated called at " . sprintf("%s (%s)",
(caller)[1, 2]) . " is deprecated. Use $package::$methodn";   test
        eval "use $package;" unless $package->can('can');
                                                                Test1::old_func called at test12.pl
        my $sub = $package->can($method);
                                                                (40) is deprecated. Use
        $sub->(@_);
                                                                Test2::Test2::new_func
    };
                                                                test
    no strict 'refs';
    *{$deprecated} = $func;
}



                                          www.mail.ru                                                 29
Stub

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
Хуки

package Wrapper;                                 package Test;

sub before(@&) {                                 sub test { say 'test'; }
    my ($methods, $wrapper) = @_;
    my $package = caller(0);                     Wrapper::before [ 'test' ], sub { say 'wrapper';
                                                 };
    for my $method (@$methods) {
        my $orig = $package->can($method);
                                                 package main;
        my $sub = sub {
                                                 Test::test();
            local *__ANON__ =
"$package::$method";
            $wrapper->(@_);
            $orig->(@_);
        };
        no strict 'refs';
        *{"$package::$method"} = $sub;          wrapper
    }                                            test
}




                                       www.mail.ru                                            31
• Какие-то проблемы?
• Методы 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

PHP Tricks
PHP TricksPHP Tricks
PHP Tricks
BlackFan
 
Реализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoРеализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в Magento
Magecom Ukraine
 
YiiConf 2012 - Alexander Makarov - Yii2, что нового
YiiConf 2012 - Alexander Makarov - Yii2, что новогоYiiConf 2012 - Alexander Makarov - Yii2, что нового
YiiConf 2012 - Alexander Makarov - Yii2, что нового
Alexander Makarov
 
Импорт данных с фреймворком Migrate. Владислав Богатырев.
Импорт данных с фреймворком Migrate. Владислав Богатырев.Импорт данных с фреймворком Migrate. Владислав Богатырев.
Импорт данных с фреймворком Migrate. Владислав Богатырев.
DrupalCampDN
 
Web осень 2013 лекция 6
Web осень 2013 лекция 6Web осень 2013 лекция 6
Web осень 2013 лекция 6
Technopark
 
I tmozg js_school
I tmozg js_schoolI tmozg js_school
I tmozg js_school
ITmozg
 

La actualidad más candente (20)

Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1
 
Разработка на Perl под Raspberry PI
Разработка на Perl под Raspberry PIРазработка на Perl под Raspberry PI
Разработка на Perl под Raspberry PI
 
PHP Tricks
PHP TricksPHP Tricks
PHP Tricks
 
PHP Advanced
PHP AdvancedPHP Advanced
PHP Advanced
 
Реализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в MagentoРеализация шаблонов корпоративных приложений в Magento
Реализация шаблонов корпоративных приложений в Magento
 
Написание DSL в Perl
Написание DSL в PerlНаписание DSL в Perl
Написание DSL в Perl
 
PHP basic
PHP basicPHP basic
PHP basic
 
Javascript
JavascriptJavascript
Javascript
 
Yii 2. Что нового?
Yii 2. Что нового?Yii 2. Что нового?
Yii 2. Что нового?
 
YiiConf 2012 - Alexander Makarov - Yii2, что нового
YiiConf 2012 - Alexander Makarov - Yii2, что новогоYiiConf 2012 - Alexander Makarov - Yii2, что нового
YiiConf 2012 - Alexander Makarov - Yii2, что нового
 
Импорт данных с фреймворком Migrate. Владислав Богатырев.
Импорт данных с фреймворком Migrate. Владислав Богатырев.Импорт данных с фреймворком Migrate. Владислав Богатырев.
Импорт данных с фреймворком Migrate. Владислав Богатырев.
 
Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1Подробная презентация JavaScript 6 в 1
Подробная презентация JavaScript 6 в 1
 
Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3
 
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"
 
Collider
ColliderCollider
Collider
 
Yserver
YserverYserver
Yserver
 
Web осень 2013 лекция 6
Web осень 2013 лекция 6Web осень 2013 лекция 6
Web осень 2013 лекция 6
 
Работа с БД в Drupal 7
Работа с БД в Drupal 7Работа с БД в Drupal 7
Работа с БД в Drupal 7
 
I tmozg js_school
I tmozg js_schoolI tmozg js_school
I tmozg js_school
 
Примеры решения типичных задач за рамками ядра Yii2
Примеры решения типичных задач за рамками ядра Yii2Примеры решения типичных задач за рамками ядра Yii2
Примеры решения типичных задач за рамками ядра Yii2
 

Destacado

Imkt120 ip1 parker_simora social media 2.0
Imkt120 ip1 parker_simora social media 2.0Imkt120 ip1 parker_simora social media 2.0
Imkt120 ip1 parker_simora social media 2.0
parkerst
 
Powerpoint etika pengunaan internet
Powerpoint etika pengunaan internetPowerpoint etika pengunaan internet
Powerpoint etika pengunaan internet
norainimie
 
Powerpoint etika pengunaan internet
Powerpoint etika pengunaan internetPowerpoint etika pengunaan internet
Powerpoint etika pengunaan internet
norainimie
 

Destacado (7)

Imkt120 ip1 parker_simora social media 2.0
Imkt120 ip1 parker_simora social media 2.0Imkt120 ip1 parker_simora social media 2.0
Imkt120 ip1 parker_simora social media 2.0
 
Powerpoint etika pengunaan internet
Powerpoint etika pengunaan internetPowerpoint etika pengunaan internet
Powerpoint etika pengunaan internet
 
Powerpoint etika pengunaan internet
Powerpoint etika pengunaan internetPowerpoint etika pengunaan internet
Powerpoint etika pengunaan internet
 
Statistic and Data Internet usage in the world and asia
Statistic and Data Internet usage in the world and asiaStatistic and Data Internet usage in the world and asia
Statistic and Data Internet usage in the world and asia
 
Sosialisasi Internet Sehat dan Aman
Sosialisasi Internet Sehat dan AmanSosialisasi Internet Sehat dan Aman
Sosialisasi Internet Sehat dan Aman
 
Handbook Internet BAIK
Handbook Internet BAIKHandbook Internet BAIK
Handbook Internet BAIK
 
Presentasi Internet Sehat untuk Anak SD
Presentasi Internet Sehat untuk Anak SDPresentasi Internet Sehat untuk Anak SD
Presentasi Internet Sehat untuk Anak SD
 

Similar a Perl: Symbol table

Школа-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиШкола-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с данными
Глеб Тарасов
 

Similar a Perl: Symbol table (20)

DSLs в Perl
DSLs в PerlDSLs в Perl
DSLs в Perl
 
Пластилиновый код: как перестать кодить и начать жить
Пластилиновый код: как перестать кодить и начать житьПластилиновый код: как перестать кодить и начать жить
Пластилиновый код: как перестать кодить и начать жить
 
Present saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasovPresent saint-per3-by-pavel-vlasov
Present saint-per3-by-pavel-vlasov
 
Caching on highload Drupal site - Alexander Shumenko
Caching on highload Drupal site - Alexander ShumenkoCaching on highload Drupal site - Alexander Shumenko
Caching on highload Drupal site - Alexander Shumenko
 
Почему Mojolicious?
Почему Mojolicious?Почему Mojolicious?
Почему Mojolicious?
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Nginx.pm
Nginx.pmNginx.pm
Nginx.pm
 
Perl – жив?!
Perl – жив?!Perl – жив?!
Perl – жив?!
 
DBIx Class
DBIx ClassDBIx Class
DBIx Class
 
Everything You Need to Know About WP_Query, WordCamp Russia 2014
Everything You Need to Know About WP_Query, WordCamp Russia 2014Everything You Need to Know About WP_Query, WordCamp Russia 2014
Everything You Need to Know About WP_Query, WordCamp Russia 2014
 
Приручаем linux-консоль
Приручаем linux-консольПриручаем linux-консоль
Приручаем linux-консоль
 
Rose::DB
Rose::DBRose::DB
Rose::DB
 
Алексей Плеханов: 25 причин попробовать Laravel
Алексей Плеханов: 25 причин попробовать LaravelАлексей Плеханов: 25 причин попробовать Laravel
Алексей Плеханов: 25 причин попробовать Laravel
 
Survive with OOP
Survive with OOPSurvive with OOP
Survive with OOP
 
UWDC 2013, Yii2
UWDC 2013, Yii2UWDC 2013, Yii2
UWDC 2013, Yii2
 
Страх и ненависть в исходном коде
Страх и ненависть в исходном кодеСтрах и ненависть в исходном коде
Страх и ненависть в исходном коде
 
Миша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPressМиша Рудрастых: Введение в HTTP API WordPress
Миша Рудрастых: Введение в HTTP API WordPress
 
Perl in practice
Perl in practicePerl in practice
Perl in practice
 
Школа-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиШкола-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с данными
 
Как очистить массив
Как очистить массивКак очистить массив
Как очистить массив
 

Perl: Symbol table

  • 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. Data::Dumper и кириллица в utf8 print Dumper {test => 'Тестовая строка'}; $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}" }; www.mail.ru 10
  • 11. Решение: CPAN 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
  • 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. eval 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
  • 17. 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
  • 18. • Какие-то проблемы? • Методы runtime- кодогенерации • Таблица символов: матчасть • От теории к практике • Как не выстрелить себе в ногу • RTFM 18
  • 19. Таблица символов • Таблица символов – это хэш %PackageName:: %main:: • Ключи – глобальные переменные и подпрограммы • Значения - тайпглобы www.mail.ru 19
  • 20. Таблица символов package Test; our $data = 'test'; *Test::data our @data = qw(1 2 3); our %data = (key1 => 'value1', key2 => 'value2'); my $fh = *FH; sub data { return 0; } package main; say $Test::{$_} for keys %Test::; www.mail.ru 20
  • 21. Структура тайпглоба *glob{PACKAGE} имя пакета *glob{NAME} имя элемента (переменной или функции) *glob{SCALAR} ссылка на значение-скаляр *glob{ARRAY} ссылка на значение-массив *glob{HASH} ссылка на значение-хэш *glob{CODE} ссылка на подпрограмму corp.mail.ru
  • 22. Работа с тайпглобом Получение данных Запись данных my $scalar = ${ *Test::data }; *Test::data = 'new value'; my %hash = %{ *Test::data }; *Test::data = [4, 5, 6]; my @array = @{ *Test::data }; *Test::data = { &{ *Test::data }(); key3 => 'value3', key4 => 'value4‘ }; *Test::data = sub { return 1; }; www.mail.ru 22
  • 23. • Какие-то проблемы? • Методы runtime- кодогенерации • Таблица символов: матчасть • От теории к практике • Как не выстрелить себе в ногу • RTFM 23
  • 24. Генерация аксессоров package MakeAccessor; package Test; sub import { use MakeAccessor; my $package = caller(0); no strict 'refs'; has 'name'; *{"$package::has"} = &has; has 'age'; } sub has ($) { sub new { return bless {}, my $name = shift; shift; } my $package = caller(0); no strict 'refs'; package main; *{"$package::$name"} = sub { my $self = shift; my $o = Test->new; $self->{$name} = $_[0] if @_; $o->name('Ann'); return $self->{$name}; say $o->name; }; } www.mail.ru 24
  • 25. Боремся с __ANON__ package MakeAccessor; sub import { my $package = caller(0); no strict 'refs'; *{"$package::has"} = &has; } sub has ($) { my $name = shift; my $package = caller(0); MakeAccessor::__ANON__ no strict 'refs'; *{"$package::$name"} = sub { my $self = shift; say ((caller(0))[3]); $self->{$name} = $_[0] if @_; return $self->{$name}; }; } www.mail.ru 25
  • 26. Боремся с __ANON__ package MakeAccessor; sub import { my $package = caller(0); no strict 'refs'; *{"$package::has"} = &has; } sub has ($) { my $name = shift; Test::name 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; } www.mail.ru 26
  • 27. От теории к практике • Генераторы классов: десериализация, ORM • Реализация паттерна «прокси» • Тестирование: mock, stub, fake object • Хуки для подпрограмм: before, after, around • Патчи во время выполнения • Расширение функционала сторонних модулей • Синонимы для устаревших функций при рефакторинге www.mail.ru 27
  • 28. Прокси package Response; package main; use CGI; my $obj = Response->new; sub new { print $obj->header('text/html'); return bless { cgi => CGI->new }, shift; } our $AUTOLOAD; sub AUTOLOAD { my ($method) = $AUTOLOAD =~ /([^:]+)$/; Content-Type: text/html; return if $method eq 'DESTROY'; return unless CGI->can($method); charset=ISO-8859-1 my $sub = sub { local *__ANON__ = $AUTOLOAD; my $self = shift; return $self->{cgi}->$method(@_); }; { no strict 'refs'; *{$AUTOLOAD} = $sub; }; return $sub->(@_); } www.mail.ru 28
  • 29. Синонимы package Wrapper; package Test1; sub make_deprecated { package Test2; my $deprecated = shift; { sub new_func { no strict 'refs'; Wrapper::make_deprecated( return if *{$deprecated}{CODE}; 'Test1::old_func'); }; return 'test'; my $package = scalar caller(0); } my $method = (caller(1))[3]; package main; my $func = sub { say Test2::new_func(); local *__ANON__ = $deprecated; say Test1::old_func(); warn "$deprecated called at " . sprintf("%s (%s)", (caller)[1, 2]) . " is deprecated. Use $package::$methodn"; test eval "use $package;" unless $package->can('can'); Test1::old_func called at test12.pl my $sub = $package->can($method); (40) is deprecated. Use $sub->(@_); Test2::Test2::new_func }; test no strict 'refs'; *{$deprecated} = $func; } www.mail.ru 29
  • 30. Stub 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
  • 31. Хуки package Wrapper; package Test; sub before(@&) { sub test { say 'test'; } my ($methods, $wrapper) = @_; my $package = caller(0); Wrapper::before [ 'test' ], sub { say 'wrapper'; }; for my $method (@$methods) { my $orig = $package->can($method); package main; my $sub = sub { Test::test(); local *__ANON__ = "$package::$method"; $wrapper->(@_); $orig->(@_); }; no strict 'refs'; *{"$package::$method"} = $sub; wrapper } test } www.mail.ru 31
  • 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