Slide 1

Slide 1 text

Программирование на Perl Модульность 1 / 104

Slide 2

Slide 2 text

Отметьтесь на портале! 2 / 104

Slide 3

Slide 3 text

Модули: разделяй и властвуй Структурирование кода читабельность надежность Повторное использование кода в рамках проекта за пределами проекта Совместная работа над проектом 3 / 104

Slide 4

Slide 4 text

Модули: как разделять Низкий уровень Работа с внешней подсистемой база данных сеть xml-файлы Специфические вычисления работа с большими числами работа датами и временем шифрование Высокий уровень функционал для регистрации и авторизации пользователей функционал для загрузки, отображения и обработки фото на сайте 4 / 104

Slide 5

Slide 5 text

Модули: как властвовать Расположение кода в отдельных файлах eval do require use Пространства имен и области видимости пакеты и таблицы символов области видимости фазы компиляции и выполнения Модули версионность pragma CPAN 5 / 104

Slide 6

Slide 6 text

Функция eval видит переменные, объявленные снаружи имеет свою область видимости возвращает последнее вычисленное значение возвращает undef и устанавливает $@ в случае ошибки компиляции/ выполнения 6 / 104

Slide 7

Slide 7 text

Функция eval my $E = 2.72; print "eval=", # eval=3.14159265 eval(' warn "Loading...\n"; sub pow { $_[0] ** $_[1]; } $E = 2.71828183; my $PI = 3.14159265; '), "\n"; print "pow(2,8)=",pow(2,8),"\n"; # pow(2,8)=256 print "E=$E\n"; # E=2.71828183 print "PI=$PI\n"; # PI=undef 7 / 104

Slide 8

Slide 8 text

Функция do do = open + eval? видит переменные, объявленные снаружи имеет свою область видимости возвращает последнее вычисленное значение возвращает undef и устанавливает $! в случае ошибки открытия файла возвращает undef и устанавливает $@ в случае ошибки компиляции/ выполнения 8 / 104

Slide 9

Slide 9 text

Функция do do = open + eval? # Local/Math.pm warn "Loading...\n"; sub pow { $_[0] ** $_[1]; } $E = 2.71828183; my $PI = 3.14159265; 9 / 104

Slide 10

Slide 10 text

Функция do do = open + eval? sub my_do { my ($file) = @_; $! = $@ = undef; open my $fd, '<', $file or return; my $code = join '', <$fd>; close $fd; eval $code; } print 'my_do=', # Loading... my_do("Local/Math.pm"),"\n"; # do=3.14159265 print '$@=', $@, "\n"; # $@=undef print '$!=', $!, "\n"; # $!=undef print 'pow(2,8)=', pow(2,8), "\n"; # pow(2,8)=256 10 / 104

Slide 11

Slide 11 text

Функция do do = open + eval? $ perl -e 'print join "\n", @INC' | head –3 /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl $ PERL5LIB=/home/www/lib \ > perl -e 'print join "\n", @INC' | head -2 /home/www/lib /usr/local/lib64/perl5 $ perl -I/home/www/lib \ > -e 'print join "\n", @INC' | head -2 /home/www/lib /usr/local/lib64/perl5 11 / 104

Slide 12

Slide 12 text

Функция do do = open + eval + @INC! # simplified implementation sub find_in_inc { my ($file) = @_; return $file if $file =~ m/^\//; foreach my $path (@INC) { return "$path/$file" if -f "$path/$file"; } die "Can't find file $file in \@INC"; } sub my_do { my ($file) = @_; $file = find_in_inc($file); # ... } 12 / 104

Slide 13

Slide 13 text

Функция require require = do + die + %INC? останавливает выполнение в случае ошибки открытия файла, компиляции или выполнения не пытается загрузить и выполнить файл, если он уже был загружен ранее проверяет последнее вычисленное значение, останавливает выполнение, если оно ложно при первой загрузке файла возвращает последнее вычисленное значение, при последующих попытках его загрузить возвращает 1 13 / 104

Slide 14

Slide 14 text

Функция require require = do + die + %INC? # simplified implementation sub my_require { my ($file) = @_; return 1 if $INC{$file}; my $filepath = find_in_inc($file) or die "Can't find $file in \@INC"; my $result = do $filepath or die "$file did not return true value"; die $@ if $@; $INC{$file} = $filepath; return $result; } 14 / 104

Slide 15

Slide 15 text

Функция require require = do + die + %INC? $E = 2.72; # Loading... require "Local/Math.pm"; # 3.14159265 print "E=$E\n"; # E=2.71828183 $E = 2.72; require "Local/Math.pm"; # 1 print "E=$E\n"; # E=2.72 15 / 104

Slide 16

Slide 16 text

Пакеты require "Some/Module.pm"; some_function(); require "Another/Module.pm"; some_function(); # WTF?! 16 / 104

Slide 17

Slide 17 text

Пакеты require "Some/Module.pm"; Some::Module::some_function(); # fqn require "Another/Module.pm"; Another::Module::some_function(); # fqn 17 / 104

Slide 18

Slide 18 text

Пакеты package Local::Math; # ... package Local::Math::Integer; # ... # ... # end of file { package Local::Math; # ... } package Local::Math { # ... } 18 / 104

Slide 19

Slide 19 text

Пакеты package Local::Math; $PI = 3.14159265; sub pow { $_[0] ** $_[1] } sub sqr { pow($_[0], 0.5) } # the same # sub sqr { Local::Math::pow($_[0], 0.5) } package main; print "sqr(4)=", Local::Math::sqr(4), "\n"; # sqr(4)=2 print "fqn PI=", $Local::Math::PI, "\n"; # fqn PI=3.14159265 print "PI=$PI\n"; # PI=undef 19 / 104

Slide 20

Slide 20 text

Пакеты package Local::Math; sub pow { $_[0] ** $_[1] } package main; $Local::Math::PI = 3.14159265; sub Local::Math::sqr { Local::Math::pow($_[0], 0.5) } print "sqr(4)=", Local::Math::sqr(4), "\n"; # sqr(4)=2 print "fqn PI=", $Local::Math::PI, "\n"; # fqn PI=3.14159265 print "PI=$PI\n"; # PI=undef 20 / 104

Slide 21

Slide 21 text

Пакеты # Local/Math.pm package Local::Math; sub pow { $_[0] ** $_[1] } printf "Pkg %s, file %s, line %d\n", __PACKAGE__, __FILE__, __LINE__; # Pkg Local::Math, file Local/Math.pm, line 4 # :-) 1; 21 / 104

Slide 22

Slide 22 text

Пакеты # script.pl require "Local/Math.pm"; printf "Pkg %s, file %s, line %d\n", __PACKAGE__, __FILE__, __LINE__; # Pkg main, file script.pl, line 3 22 / 104

Slide 23

Slide 23 text

Пакеты # script.pl { package Local::Math; sub sqr {pow($_[0], 0.5) } printf "Pkg %s, file %s, line %d\n", __PACKAGE__, __FILE__, __LINE__; # Pkg Local::Math, file script.pl, line 5 } printf "Pkg %s, file %s, line %d\n", __PACKAGE__, __FILE__, __LINE__; # Pkg main, file script.pl, line 11 23 / 104

Slide 24

Slide 24 text

Таблицы символов package Some::Package { $var = 500; @var = (1,2,3); %func = (1 => 2, 3 => 4); sub func { return 400 } open F, "<", "/dev/null"; } package Some::Package::Deeper {} printf "%-10s => %s\n", $_, $Some::Package::{$_} foreach keys %Some::Package::; F => *Some::Package::F Deeper:: => *Some::Package::Deeper:: var => *Some::Package::var func => *Some::Package::func 24 / 104

Slide 25

Slide 25 text

Таблицы символов TYPEGLOB: *foo SCALAR: $foo ARRAY: @foo HASH: %foo CODE: &foo IO: foo NAME: "foo" PACKAGE: "main" 25 / 104

Slide 26

Slide 26 text

Таблицы символов package Local::Math { $PI = 3.14159265; sub PI { print 3.14 } } *Other::Math::PI = *Local::Math::PI; print $Other::Math::PI, "\n"; # 3.14159265 Other::Math::PI(); # 3.14 26 / 104

Slide 27

Slide 27 text

Таблицы символов package Local::Math { $PI = 3.14159265; sub PI { print 3.14 } } *Other::Math::PI = \$Local::Math::PI; print $Other::Math::PI, "\n"; # 3.14159265 Other::Math::PI(); # Undefined subroutine &Other::Math::PI called 27 / 104

Slide 28

Slide 28 text

Таблицы символов package Local::Math { $PI = 3.14159265; sub PI { print 3.14 } } *Other::Math::PI = \&Local::Math::PI; print $Other::Math::PI, "\n"; # undef Other::Math::PI(); # 3.14 28 / 104

Slide 29

Slide 29 text

Таблицы символов *PI = \3.14159265; print $PI, "\n"; # 3.14159265 $PI = 4; # Modification of a read-only value attempted $glob = *FH; print *{$glob}{PACKAGE}, "::", *{$glob}{NAME}; # main::FH 29 / 104

Slide 30

Slide 30 text

Области видимости package Local::Math; our $PI = 3.14159265; package main; print $PI, "\n"; # 3.14159265 print $::PI, "\n"; # undef print $Local::Math::PI, "\n"; # 3.14159265 30 / 104

Slide 31

Slide 31 text

Области видимости package Local::Math; my $PI = 3.14159265; package main; print $PI, "\n"; # 3.14159265 print $::PI, "\n"; # undef print $Local::Math::PI, "\n"; # undef 31 / 104

Slide 32

Slide 32 text

Области видимости my $x = 4; { my $x = 5; print $x, "\n"; # 5 } print $x, "\n"; # 4 32 / 104

Slide 33

Slide 33 text

Области видимости use feature 'state'; sub test { state $x = 42; return $x++; } printf( # 42 43 44 45 46 '%d %d %d %d %d', test(),test(),test(),test(),test() ); print $x; # undef 33 / 104

Slide 34

Slide 34 text

Области видимости our $x = 10; our %y = (x => 20, y => 30); { local $x = -10; local $y{x} = -20; print $x, "\n"; # -10 print $y{x}, "\n"; # -20 } print $x, "\n"; # 10 print $y{x}, "\n"; # 20 34 / 104

Slide 35

Slide 35 text

Области видимости # 1,2,3 { local $/ = ","; $x=<>; $y = <>; $z=<>; # "1," "2," "3\n" chomp $y; # "2" } chomp $z; # "3" # 1\n2\n3\n { local $/; $all = <>; # "1\n2\n3\n" } 35 / 104

Slide 36

Slide 36 text

Функция require require =do+die+%INC+namespace! require "/home/www/lib/Local/Math.pm"; require "Local/Math.pm"; require Local::Math; # BAREWORD! 36 / 104

Slide 37

Slide 37 text

Функция require require =do+die+%INC+namespace! sub pkg_to_filename { my ($pkg) = @_; $pkg =~ s!::!/!g; return "${pkg}.pm"; } sub my_require { my ($file) = @_; # simplified implementation $file = pkg_to_filename($file) unless $file =~ m![./]!; # ... } 37 / 104

Slide 38

Slide 38 text

Фазы работы интерпретатора ${^GLOBAL_PHASE} – фаза работы интерпретатора perl CONSTRUCT START CHECK INIT RUN END DESTRUCT 38 / 104

Slide 39

Slide 39 text

Фазы работы интерпретатора warn "[${^GLOBAL_PHASE}] Runtime 1\n"; END { warn "[${^GLOBAL_PHASE}] End 1\n" } CHECK { warn "[${^GLOBAL_PHASE}] Check 1\n" } UNITCHECK { warn "[${^GLOBAL_PHASE}] UnitCheck 1\n" } INIT { warn "[${^GLOBAL_PHASE}] Init 1\n" } BEGIN { warn "[${^GLOBAL_PHASE}] Begin 1\n" } END { warn "[${^GLOBAL_PHASE}] End 2\n" } CHECK { warn "[${^GLOBAL_PHASE}] Check 2\n" } UNITCHECK { warn "[${^GLOBAL_PHASE}] UnitCheck 2\n" } INIT { warn "[${^GLOBAL_PHASE}] Init 2\n" } BEGIN { warn "[${^GLOBAL_PHASE}] Begin 2\n" } warn "[${^GLOBAL_PHASE}] Runtime 2\n"; 39 / 104

Slide 40

Slide 40 text

Фазы работы интерпретатора [START] Begin 1 [START] Begin 2 [START] UnitCheck 2 [START] UnitCheck 1 [CHECK] Check 2 [CHECK] Check 1 [INIT] Init 1 [INIT] Init 2 [RUN] Runtime 1 [RUN] Runtime 2 [END] End 2 [END] End 1 40 / 104

Slide 41

Slide 41 text

Фазы работы интерпретатора require использует eval mod_perl выполняет приложение, используя eval как работают фазы и специальные блоки в eval? 41 / 104

Slide 42

Slide 42 text

Фазы работы интерпретатора warn "[${^GLOBAL_PHASE}] --- BEFORE EVAL\n"; eval ' warn "[${^GLOBAL_PHASE}] Runtime\n"; END { warn "[${^GLOBAL_PHASE}] End\n" } CHECK { warn "[${^GLOBAL_PHASE}] Check\n" } UNITCHECK { warn "[${^GLOBAL_PHASE}] UnitCheck\n" } INIT { warn "[${^GLOBAL_PHASE}] Init\n" } BEGIN { warn "[${^GLOBAL_PHASE}] Begin\n" } '; warn "[${^GLOBAL_PHASE}] --- AFTER EVAL\n"; 42 / 104

Slide 43

Slide 43 text

Фазы работы интерпретатора [RUN] --- BEFORE EVAL [RUN] Begin [RUN] UnitCheck [RUN] Runtime [RUN] --- AFTER EVAL [END] End # RUN? # CHECK?! # INIT?!! # END?!!! 43 / 104

Slide 44

Slide 44 text

Фазы работы интерпретатора # Local/Phases.pm package Local::Phases; BEGIN { warn __PACKAGE__, " compile start\n" } UNITCHECK { warn __PACKAGE__, " UNITCHECK\n" } CHECK { warn __PACKAGE__, " CHECK\n" } INIT { warn __PACKAGE__, " INIT\n" } warn __PACKAGE__, " runtime\n"; BEGIN { warn __PACKAGE__, " compile end\n" } # phases.pl BEGIN { warn __PACKAGE__, " compile start\n" } UNITCHECK { warn __PACKAGE__, " UNITCHECK\n" } CHECK { warn __PACKAGE__, " CHECK\n" } INIT { warn __PACKAGE__, " INIT\n" } warn __PACKAGE__, " runtime\n"; require Local::Phases; BEGIN { warn __PACKAGE__, " compile end\n" } 44 / 104

Slide 45

Slide 45 text

Фазы работы интерпретатора main compile start main compile end main UNITCHECK main CHECK main INIT main runtime Local::Phases compile start Local::Phases compile end Local::Phases UNITCHECK Local::Phases runtime # Local::Phases CHECK ?!! # Local::Phases INIT ?!! 45 / 104

Slide 46

Slide 46 text

Фазы работы интерпретатора # Local/Phases.pm package Local::Phases; BEGIN { warn __PACKAGE__, " compile start\n" } UNITCHECK { warn __PACKAGE__, " UNITCHECK\n" } CHECK { warn __PACKAGE__, " CHECK\n" } INIT { warn __PACKAGE__, " INIT\n" } warn __PACKAGE__, " runtime\n"; BEGIN { warn __PACKAGE__, " compile end\n" } # phases.pl BEGIN { warn __PACKAGE__, " compile start\n" } UNITCHECK { warn __PACKAGE__, " UNITCHECK\n" } CHECK { warn __PACKAGE__, " CHECK\n" } INIT { warn __PACKAGE__, " INIT\n" } warn __PACKAGE__, " runtime\n"; BEGIN { require Local::Phases; } BEGIN { warn __PACKAGE__, " compile end\n" } 46 / 104

Slide 47

Slide 47 text

Фазы работы интерпретатора main compile start Local::Phases compile start Local::Phases compile end Local::Phases UNITCHECK Local::Phases runtime main compile end main UNITCHECK Local::Phases CHECK main CHECK main INIT Local::Phases INIT main runtime 47 / 104

Slide 48

Slide 48 text

Директива use use = BEGIN + require? use Local::Math; # BAREWORD # BEGIN { require Local::Math; } BEGIN { print Local::Math::pow(2, 8) } # 256 require Local::Math; BEGIN { print Local::Math::pow(2, 8) } # Undefined subroutine &Local::Math::pow 48 / 104

Slide 49

Slide 49 text

Директива use use = BEGIN + require + import? use Some::Module (); BEGIN { require Some::Module; } # import? 49 / 104

Slide 50

Slide 50 text

Директива use use = BEGIN + require + import? use Some::Module; BEGIN { require Some::Module; Some::Module->import(); # if can # Some::Module::import('Some::Module'); } use Some::Module ('arg1', 'arg2'); BEGIN { require Some::Module; Some::Module->import('arg1', 'arg2'); } 50 / 104

Slide 51

Slide 51 text

Директива use use = BEGIN + require + import? # Local/Math.pm sub import { my $self = shift; my ($pkg) = caller(0); foreach my $func (@_) { *{"${pkg}::$func"} = \&{$func}; } } # main.pl use Local::Math qw/pow sqr/; print pow(2,8), "\n"; # 256 51 / 104

Slide 52

Slide 52 text

Директива use use = BEGIN + require + import? # Local/Math.pm sub unimport { my $self = shift; my ($pkg) = caller(0); delete ${"${pkg}::"}{$_} foreach @_; } # main.pl use Local::Math qw/pow sqr/; print pow(2,8), "\n"; # 256 no Local::Math qw/pow/; print pow(2,8), "\n"; # Undefined subroutine &main::pow called 52 / 104

Slide 53

Slide 53 text

Директива use use = BEGIN + require + import + version! # Local/Math.pm package Local::Math; our $VERSION = 1.25; # package Local::Math 1.25; print $Local::Math::VERSION; # 1.25 # main.pl use Local::Math 1.26; # Local::Math version 1.26 required--this is # only version 1.25 53 / 104

Slide 54

Slide 54 text

Директива use use = BEGIN + require + import + version! package Local::Math; our $VERSION = v1.25.01; print $Local::Math::VERSION; # ??? print v67.97.109.101.108.33; # Camel! package Local::Math v1.25.01; print $Local::Math::VERSION; # v1.25.01 use Local::Math v1.26.2; # Local::Math version v1.26.2 required--this is # only version v1.25.1 54 / 104

Slide 55

Slide 55 text

Директива use use = BEGIN + require + import + version! use 5.20; # Perl v5.200.0 required (did you mean v5.20.0?)-- # this is only v5.16.3, stopped use v5.20; # Perl v5.20.0 required--this # is only v5.16.3, stopped use 5.020_000; # Perl v5.20.0 required--this # is only v5.16.3, stopped 55 / 104

Slide 56

Slide 56 text

Стандартные модули Модуль Exporter package Local::Math; use Exporter; *import = \&Exporter::import; our @EXPORT_OK = qw/$PI pow sqr/; our %EXPORT_TAGS = ( func => [ qw/pow sqr/ ], const => [ qw/$PI $E/ ], ); our @EXPORT = qw/$PI/; our $PI = 3.14159265; our $E = 2.71828183; sub pow { $_[0] ** $_[1] } sub sqr { pow($_[0], 0.5) } 56 / 104

Slide 57

Slide 57 text

Стандартные модули Модуль Exporter use Local::Math (); # nothing use Local::Math; # $PI use Local::Math qw/$PI/; # $PI use Local::Math qw/pow/; # pow use Local::Math qw/:const pow/; # $PI $E pow use Local::Math qw/:const &sqr/; # $PI $E sqr 57 / 104

Slide 58

Slide 58 text

Стандартные модули Модуль Data::Dumper use Data::Dumper; $u = \\3.14; $v = *STDIN; $w = "qwerty"; $x = sub { 1 }; @y = (1, "2", 3, "x"); %z = (x => 1, y => 2); warn Dumper($u, $v, $w, $x, \@y, \%z); 58 / 104

Slide 59

Slide 59 text

Стандартные модули Модуль Data::Dumper $VAR1 = \\'3.14'; $VAR2 = *::STDIN; $VAR3 = 'qwerty'; $VAR4 = sub { "DUMMY" }; $VAR5 = [ 1, '2', 3, 'x' ]; $VAR6 = { 'y' => 2, 'x' => 1 }; 59 / 104

Slide 60

Slide 60 text

Стандартные модули Модуль Getopt::Long use Getopt::Long; use Data::Dumper; GetOptions( 'format=s' => \$format, verbose => \$verbose, ); print Dumper [$format, $verbose]; # ./script.pl --format xml --verbose $VAR1 = [ 'xml', 1 ]; 60 / 104

Slide 61

Slide 61 text

Стандартные модули Модуль POSIX use POSIX (); print POSIX::ceil(2.72), "\n"; # 3 print POSIX::floor(2.72), "\n"; # 2 print POSIX::strftime("%Y-%m-%d %T / %B", localtime(0)), "\n"; # 1970-01-01 03:00:00 / January use POSIX qw(setlocale LC_ALL); setlocale(LC_ALL, "ru_RU.UTF-8"); print POSIX::strftime("%Y-%m-%d %T / %B", localtime(0)), "\n"; # 1970-01-01 03:00:00 / Январь 61 / 104

Slide 62

Slide 62 text

Прагмы Модуль strict use strict 'vars'; our $foo = 1; # ok my $bar = 2; # ok $baz = 3; # Global symbol "$baz" requires # explicit package name 62 / 104

Slide 63

Slide 63 text

Прагмы Модуль strict $foo = "foo"; $ref = \$foo; print $$ref; # foo use strict 'refs'; $ref = "foo"; print $$ref; # Can't use string ("foo") as a SCALAR ref # while "strict refs" in use 63 / 104

Slide 64

Slide 64 text

Прагмы Модуль strict $x = \foo; print $$x, "\n"; # foo use strict 'subs'; $x = \"foo"; # ok $x = \foo; # Bareword "foo" not allowed # while "strict subs" in use 64 / 104

Slide 65

Slide 65 text

Прагмы Модуль strict use strict; # qw/vars refs subs/ our $var = "foo"; my $ref = "var"; { no strict 'refs'; print $$ref; # foo } print $$ref; # Can't use string ("var") as a SCALAR ref # while "strict refs" in use 65 / 104

Slide 66

Slide 66 text

Прагмы Модуль warnings use warnings; use warnings 'deprecated'; print "foo" . undef; # foo # Use of uninitialized value in concatenation (.) # or string no warnings 'uninitialized'; print "foo" . undef; # foo $ perl -we 'print 5 + "a"' # 5 # Argument "a" isn't numeric in addition (+) 66 / 104

Slide 67

Slide 67 text

Прагмы Модуль diagnostics use diagnostics; print 5+"a"; # 5 # Argument "a" isn't numeric in addition (+) # (W numeric) The indicated string was fed as # an argument to an operator that expected # a numeric value instead. If you're fortunate # the message will identify which operator was # so unfortunate. 67 / 104

Slide 68

Slide 68 text

Прагмы Модуль lib use lib qw(/home/www/lib /home/www/lib2); BEGIN { unshift @INC, '/home/www/lib', '/home/www/lib2' } 68 / 104

Slide 69

Slide 69 text

Прагмы Модуль feature use feature qw/say state/; # a lot of features use feature ":5.10"; # features for 5.10 say 'New line follows this'; state $x = 10; 69 / 104

Slide 70

Slide 70 text

Прагмы Модуль constant use constant PI => 3.14159265; # sub PI () { 3.14159265 } print PI; # 3.14159265 # print 3.14159265; use constant { PI => 3.14159265, E => 2.71828183, }; 70 / 104

Slide 71

Slide 71 text

CPAN Comprehensive Perl Archive Network DBI, DBD::mysql, DBD::Pg, DBD::SQLite Digest::SHA, Digest::MD5, Digest::SipHash Crypt::RSA, Crypt::Rijndael XML::Parser, XML::LibXML, YAML, JSON::XS LWP , Net::T witter, Net::SMTP Devel::StackTrace, Devel::NYTProf Archive::Zip, MP3::Info, Image::ExifT ool, GD См. perlmodlib. 71 / 104

Slide 72

Slide 72 text

CPAN $ perl –MCPAN -eshell $ cpan cpan shell -- CPAN exploration and modules installation ( ReadLine support available (try 'install Bundle::CPAN' cpan> install Crypt::Rijndael ... cpan> ? 72 / 104

Slide 73

Slide 73 text

CPAN wget http://search.cpan.org/CPAN/authors/id/L/LE/LEONT/Cr tar –xzf Crypt-Rijndael-1.13.tar.gz cd Crypt-Rijndael-1.13 perl Makefile.PL make make test make install 73 / 104

Slide 74

Slide 74 text

CPAN $ module-starter --module Local::Math \ > --author Vadim --email [email protected] Local-Math/ ├── Changes ├── ignore.txt ├── lib │ └── Local │ └── Math.pm ├── Makefile.PL ├── MANIFEST ├── README └── t ├── 00-load.t ├── boilerplate.t ├── manifest.t ├── pod-coverage.t └── pod.t 74 / 104

Slide 75

Slide 75 text

CPAN # Makefile.PL use 5.006; use strict; use warnings FATAL => 'all'; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'Local::Math', AUTHOR => 'Vadim ', VERSION_FROM => 'lib/Local/Math.pm', ABSTRACT_FROM => 'lib/Local/Math.pm', LICENSE => 'Artistic_2_0', PL_FILES => {}, BUILD_REQUIRES => { 'Test::More' => 0, }, # ... ); 75 / 104

Slide 76

Slide 76 text

CPAN $ apt-cache search libjson-perl libjson-perl - module for manipulating JSON-formatted data libjson-pp-perl - module for manipulating JSON-formatted data (Pure Perl) libjson-xs-perl - module for manipulating JSON-formatted data (C/XS-accelerated) $ yum search perl-JSON =============== Matched: perl-json =============== perl-JSON-XS.x86_64 : JSON serialising/ deserialising, done correctly and fast perl-JSON.noarch : Parse and convert to JSON (JavaScript Object Notation) perl-JSON-PP.noarch : JSON::XS compatible pure-Perl module 76 / 104

Slide 77

Slide 77 text

Список литературы perlmod perlsub perlvar perlfunc perlpragma perlmodlib cpan perlnewmod perlmodstyle 77 / 104

Slide 78

Slide 78 text

Пишем модуль Задача: написать скрипт, выполняющий аутентификацию пользователя по его email и паролю для аутентифицированных пользователей должно выводиться персонифицированное приветствие, код возврата скрипта - 0 в остальных случаях выдавать сообщение об ошибке, код возврата скрипта - любой, кроме 0 всю обработку, связанную с пользовательскими данными, выделить в отдельный модуль база данных пользователей должна храниться в том же модуле (мы еще не умеем ходить в настоящие базы данных) 78 / 104

Slide 79

Slide 79 text

Пишем модуль #!/usr/bin/perl use strict; use feature 'say'; use Local::User; my ($email, $passwd) = @ARGV; die "USAGE: $0 \n“ unless length $email && length $passwd; my $user = get_by_email($email); die "Пользователь с адресом '$email' не найден\n" unless $user; die "Введен неправильный пароль\n" unless $user->{passwd} eq $passwd; say welcome_string($user); say 'Добро пожаловать'; 79 / 104

Slide 80

Slide 80 text

Пишем модуль package Local::User 1.1; use strict; use warnings; use List::Util qw/first/; use Exporter 'import'; our @EXPORT = qw/get_by_email name welcome_string/; 80 / 104

Slide 81

Slide 81 text

Пишем модуль my @USERS = ( { first_name => 'Василий', last_name => 'Пупкин', gender => 'm', email => '[email protected]', passwd => '12345', }, { first_name => 'Николай', middle_name => 'Петрович', last_name => 'Табуреткин', gender => 'm', email => '[email protected]', passwd => 'admin', }, ); 81 / 104

Slide 82

Slide 82 text

Пишем модуль # first imported from List::Util sub get_by_email { my $email = shift; my $user = first { $_->{email} eq $email } @USERS; return $user; } 82 / 104

Slide 83

Slide 83 text

Пишем модуль sub name { my $user = shift; return join ' ', grep { length $_ } map { $user->{$_} } qw/first_name middle_name last_name/; } 83 / 104

Slide 84

Slide 84 text

Пишем модуль sub welcome_string { my $user = shift; return ( $user->{gender} eq 'm' ? "Уважаемый " : "Уважаемая " ) . name($user) . "!"; } 84 / 104

Slide 85

Slide 85 text

Пишем модуль # :-) 1; 85 / 104

Slide 86

Slide 86 text

Пишем модуль $ perl auth USAGE: auth $ perl auth [email protected] 123 Пользователь с адресом '[email protected]' не найден $ perl auth [email protected] 12345 Введен неправильный пароль $ perl auth [email protected] admin Уважаемый Николай Петрович Табуреткин! Добро пожаловать 86 / 104

Slide 87

Slide 87 text

Пишем модуль Задача: изменить скрипт и модуль так, чтобы пароли не хранились в открытом виде использовать хеширование паролей использовать секретный ключ ("соль") 87 / 104

Slide 88

Slide 88 text

Пишем модуль package Local::User 1.2; # ... # not strong enough :-( use Digest::MD5 'md5_hex'; # ... my @USERS = ( { first_name => 'Василий', last_name => 'Пупкин', gender => 'm', email => '[email protected]', passwd => 'd19f77fefeae0fabdfc75f17abc47c96', }, # ... ); 88 / 104

Slide 89

Slide 89 text

Пишем модуль our @EXPORT = qw/ get_by_email name welcome_string is_password_valid /; # ... { my $SALT = "perl rulez!"; sub is_password_valid { my ($user, $passwd) = @_; return $user->{passwd} eq md5_hex($passwd.$SALT); } } 89 / 104

Slide 90

Slide 90 text

Пишем модуль #!/usr/bin/perl use Local::User 1.2; # ... die "Введен неправильный пароль\n" unless is_password_valid($user, $passwd); # ... 90 / 104

Slide 91

Slide 91 text

Пишем модуль Задача: усовершенствовать механизм хранения и проверки паролей использовать дополнительный случайный ключ для усложнения подбора пароля по хешу предусмотреть возможное изменение механизма проверки пароля в будущем оставить обратную совместимость с форматом хранения паролей из версии 1.2 91 / 104

Slide 92

Slide 92 text

Пишем модуль package Local::User 1.3; # ... my @USERS = ( { first_name => 'Василий', last_name => 'Пупкин', gender => 'm', email => '[email protected]', passwd => '$1$f^34d*$24cc1e0d198dbf6bbfd812a30f1b4460', }, # ... ); 92 / 104

Slide 93

Slide 93 text

Пишем модуль sub is_password_valid { my ($user, $passwd) = @_; my ($version, $data) = (0, $user->{passwd}); if ($user->{passwd} =~ /^\$(\d+)\$(.+)$/) { # new scheme ($version, $data) = ($1, $2); die "Don't know passwd version $version" unless $CHECKERS{$version}; } return $CHECKERS{$version}->($data, $passwd); } 93 / 104

Slide 94

Slide 94 text

Пишем модуль # (password_hashed_data, password_to_check) my %CHECKERS = ( 0 => sub { $_[0] eq md5_hex($_[1] . $SALT) }, 1 => sub { my ($rand, $hash) = split '$', $_[0]; return $hash eq md5_hex($_[1] . $SALT . $rand); }, ); 94 / 104

Slide 95

Slide 95 text

Пишем модуль Что дальше? заменяем устаревший MD5 на другой алгоритм хеширования (SHA512, bcrypt, scrypt) переносим информацию о пользователях в базу данных или другое внешнее хранилище добавляем функционал для регистрации новых пользователей и изменения существующих данных интегрируем модуль в веб-приложение ... 95 / 104

Slide 96

Slide 96 text

Домашнее задание Требуется написать скрипт , который на вход принимает список файлов музыкальной библиотеки, а на выходе рисует таблицу всех композиций согласно параметрам. Функционал должен быть разумно распределен по модулям, в самом скрипте должен остаться абслютно необходимый минимум. Дополнительно предлагается к получившимся модулям добавить автотесты. Это полностью опциональный пункт , на количество баллов его исполнение не повлияет . https://github.com/Nikolo/T echnosfera-perl/tree/master/homeworks/music_library 96 / 104

Slide 97

Slide 97 text

Домашнее задание Формат входных данных На вход подается список относительных путей (с ведущими ./) всех файлов музыкальной библиотеки, начиная с ее корня. $ find -type f ./Dreams Of Sanity/1999 - Masquerade/The Phantom of the Opera.mp3 ./Dreams Of Sanity/1999 - Masquerade/Masquerade Act 1.mp3 ./Dreams Of Sanity/1999 - Masquerade/Opera.mp3 ./Dreams Of Sanity/1999 - Masquerade/Lost Paradise '99.mp3 ./Dreams Of Sanity/1999 - Masquerade/Masquerade - Interlude.mp3 ./Dreams Of Sanity/1999 - Masquerade/Within (The Dragon).mp3 ./Midas Fall/2015 - The Menagerie Inside/Push.ogg ./Midas Fall/2015 - The Menagerie Inside/Half a Mile Outside.ogg ./Midas Fall/2015 - The Menagerie Inside/Circus Performer.ogg Путь к каждому файлу стандартизирован: ./группа/год - альбом/ трек.формат 97 / 104

Slide 98

Slide 98 text

Домашнее задание Формат выходных данных На выходе должна быть изображена таблица. По умолчанию она содержит следующие колонки (слева-направо): группа, год, альбом, трек, формат . Вид таблицы строго определен: /------------------------------------------------------------------------------------\ | Midas Fall | 2015 | The Menagerie Inside | Low | ogg | |------------+------+----------------------+-----------------------------------+-----| | Midas Fall | 2015 | The Menagerie Inside | Push | ogg | |------------+------+----------------------+-----------------------------------+-----| | Midas Fall | 2015 | The Menagerie Inside | The Morning Asked and I Said 'No' | ogg | |------------+------+----------------------+-----------------------------------+-----| | Midas Fall | 2015 | The Menagerie Inside | Afterthought | ogg | |------------+------+----------------------+-----------------------------------+-----| | Midas Fall | 2015 | The Menagerie Inside | A Song Built From Scraps of Paper | ogg | |------------+------+----------------------+-----------------------------------+-----| | Midas Fall | 2015 | The Menagerie Inside | Counting Colours | ogg | \------------------------------------------------------------------------------------/ 98 / 104

Slide 99

Slide 99 text

Домашнее задание Формат выходных данных Для пустот используются только пробелы. Ширина колонки задается самым длинным значением, оно должно отступать от краев на один пробел (слева и справа). Остальные значения выравниваются по правому краю ячейки (отступая от него на один пробел). Для границ используются только символы /\-+|. В случае, если в таблице нет ни одной строки, ничего выводить не надо. 99 / 104

Slide 100

Slide 100 text

Домашнее задание Параметры Параметры задаются скрипту ключами запуска. Параметр Смысл Параметр Смысл --band BAND Оставить только композиции группы BAND --year YEAR Оставить только композиции с альбомов года YEAR --album ALBUM Оставить только композиции с альбомов с именем ALBUM --track TRACK Оставить только композиции с именем TRACK --format FORMAT Оставить только композиции в формате FORMAT --sort FIELD Сортировать по возрастанию значения указанного параметра. FIELD может принимать значения band, year, album, track и format --columns COL_1,...,COL_N Список колонок через запятую, которые должны появиться в таблице (с учетом порядка). COL_I может принимать значения band, year, album, track и format. Дублирование допускается. Опциональный параметр, при отсутствии — использовать значение по умолчанию. 100 / 104

Slide 101

Slide 101 text

Домашнее задание Параметры Необходимо учесть, что фильтрация и сортировка по году должна выполняться с учетом того, что год — это целое число, а не строка. (Однако выводить год в таблице следует без изменений: так, как он указан в имени файла.) 101 / 104

Slide 102

Slide 102 text

Домашнее задание Пример $ find . -type f | ~/.../music_library.pl \ --band 'Midas Fall' --sort track --columns year,band,album,track,year /-------------------------------------------------------------------------------------\ | 2015 | Midas Fall | The Menagerie Inside | A Song Built From Scraps of Paper | 2015 | |------+------------+----------------------+-----------------------------------+------| | 2015 | Midas Fall | The Menagerie Inside | Afterthought | 2015 | |------+------------+----------------------+-----------------------------------+------| | 2015 | Midas Fall | The Menagerie Inside | Holes | 2015 | |------+------------+----------------------+-----------------------------------+------| | 2015 | Midas Fall | The Menagerie Inside | Low | 2015 | |------+------------+----------------------+-----------------------------------+------| | 2015 | Midas Fall | The Menagerie Inside | Push | 2015 | |------+------------+----------------------+-----------------------------------+------| | 2015 | Midas Fall | The Menagerie Inside | The Morning Asked and I Said 'No' | 2015 | |------+------------+----------------------+-----------------------------------+------| | 2015 | Midas Fall | The Menagerie Inside | Tramadol Baby | 2015 | \-------------------------------------------------------------------------------------/ 102 / 104

Slide 103

Slide 103 text

Всем спасибо! 103 / 104

Slide 104

Slide 104 text

Спасибо за внимание! Оставьте отзыв Вадим Пуштаев [email protected] 104 / 104