Download presentation
Presentation is loading. Please wait.
Published byWayne Griswold Modified over 10 years ago
1
Take control Introductie in het wijzigen van standaard Perl gedrag use Workshop::Perl::Dutch 5; date( '2008-02-29' ); author( abeltje => 'Abe Timmerman' );
2
28/2/2008Take control2 Technieken overload tie CORE::GLOBAL Attribute::Handlers
3
28/2/2008Take control3 overload gebruikers?
4
28/2/2008Take control4 overload stringify –String functies Numify –Rekenkundige bewerkingen –Rekenkundige functies overload::constant()
5
28/2/2008Take control5 overload API Operator overloading met sub Unary operators: –1 argument Binary operators –3 argumenten 1ste altijd een object 2de object of constante 3de geeft aan of 1ste en 2de zijn verwisseld
6
28/2/2008Take control6 Coords.pm package Coords; sub new { my( $class, $x, $y ) = @_; bless { _x => $x || 0, _y => $y || 0 }, $class; } sub move { my( $self, $dx, $dy ) = @_; ref $dx eq __PACKAGE__ and ( $dx, $dy ) = ( $dx->{_x}, $dx->{_y} ); $self->{_x} += $dx; $self->{_y} += $dy; return $self; } sub as_string { my( $self ) = @_; return sprintf "(%d, %d)", $self->{_x}, $self->{_y}; }
7
28/2/2008Take control7 Coords.pm package Coords; use overload q{""} => \&as_string, fallback => 1; sub new { my( $class, $x, $y ) = @_; bless { _x => $x || 0, _y => $y || 0 }, $class; } sub move { my( $self, $dx, $dy ) = @_; ref $dx eq __PACKAGE__ and ( $dx, $dy ) = ( $dx->{_x}, $dx->{_y} ); $self->{_x} += $dx; $self->{_y} += $dy; return $self; } sub as_string { my( $self ) = @_; return sprintf "(%d, %d)", $self->{_x}, $self->{_y}; }
8
28/2/2008Take control8 Testing Coords.pm use Test::More 'no_plan'; my $c = Coords->new( 150, 150 ); is $c, $c->as_string, "overloaded stringify: $c"; $c->move( -50, 50 ); is $c, "(100, 200)", "->move(-50,50): $c"; my $m = Coords->new( 50, -50 ); $c->move( $m ); is $c, "(150, 150)", "->move$m: $c"; # overload/coords/1fase/ -> prove -lv t/*.t
9
28/2/2008Take control9 Using '+' to move use Test::More 'no_plan'; my $c1 = Coords->new( 150, 150 ); is $c1, $c1->as_string, "overloaded stringify: $c1"; my $c2 = Coords->new( -50, 50 ); is $c2, $c2->as_string, "overloaded stringify: $c2"; my $r2 = $c1 + $c2; isa_ok $r2, 'Coords'; is $r2, "(100, 200)", "overloaded addition: $r2";
10
28/2/2008Take control10 Using '+' to move use Test::More 'no_plan'; my $c1 = Coords->new( 150, 150 ); is $c1, $c1->as_string, "overloaded stringify: $c1"; my $c2 = Coords->new( -50, 50 ); is $c2, $c2->as_string, "overloaded stringify: $c2"; my $r1 = $c1->copy; isa_ok $r1, 'Coords'; is $r1, $c1, "->copy: $r1"; $r1->move( $c2 ); is $r1, "(100, 200)", "->move$c2: $r1"; my $r2 = $c1 + $c2; isa_ok $r2, 'Coords'; is $r2, "(100, 200)", "overloaded addition: $r2";
11
28/2/2008Take control11 Using '+' to move package Coords; use overload q{""} => \&as_string, fallback => 1; sub new { my( $class, $x, $y ) = @_; bless { _x => $x || 0, _y => $y || 0 }, $class; } sub copy { return bless { _x => $_[0]->{_x}, _y => $_[0]->{_y} }, ref $_[0]; } sub move { my( $self, $dx, $dy ) = @_; ref $dx and ( $dx, $dy ) = ( $dx->{_x}, $dx->{_y} ); $self->{_x} += $dx; $self->{_y} += $dy; return $self; } sub as_string { my( $self ) = @_; return sprintf "(%d, %d)", $self->{_x}, $self->{_y}; }
12
28/2/2008Take control12 Using '+' to move package Coords; use overload q{""} => \&as_string, q{+} => \&add_move, fallback => 1; sub new { my( $class, $x, $y ) = @_; bless { _x => $x || 0, _y => $y || 0 }, $class; } sub copy { return bless { _x => $_[0]->{_x}, _y => $_[0]->{_y} }, ref $_[0]; } sub move { my( $self, $dx, $dy ) = @_; ref $dx and ( $dx, $dy ) = ( $dx->{_x}, $dx->{_y} ); $self->{_x} += $dx; $self->{_y} += $dy; return $self; } sub add_move { my( $a1, $a2 ) = @_; ref $a2 or die "Cannot move() with constants!"; $a1->copy->move( $a2 ); } sub as_string { my( $self ) = @_; return sprintf "(%d, %d)", $self->{_x}, $self->{_y}; }
13
28/2/2008Take control13 Meer informatie perldoc overload
14
28/2/2008Take control14 tie() gebruikers?
15
28/2/2008Take control15 Geef een object de interface van een Perl variabele type Mogelijke typen: –Scalar –Array –Hash –Handle Toegang tot het onderliggende object met behulp van tied() tie()
16
28/2/2008Take control16 API: –TIEARRAY constructor –FETCH, STORE –FETCHSIZE, STORESIZE –CLEAR, EXTEND –EXISTS, DELETE –PUSH, POP, –SHIFT, UNSHIFT, SPLICE –UNTIE, DESTROY TIEARRAY API
17
28/2/2008Take control17 TIEARRAY Geef een object de interface van een array In het voorbeeld: gebruik een scalar als array –substr() push/pop/unshift/shift/slice
18
28/2/2008Take control18 CharArray (src1) package CharArray; use warnings; use strict; sub TIEARRAY { my $class = shift; ref $_[0] or die "Usage: tie my @a, CharArray => \$scalar;"; bless $_[0], $class; } sub UNTIE { } sub FETCHSIZE { my $self = shift; defined $$self ? length( $$self ) : 0; }
19
28/2/2008Take control19 CharArray (src2) sub FETCH { my( $self, $index ) = @_; $index > length $$self and $$self.= "" x ( 1 + $index - length $$self ); defined $$self ? substr $$self, $index, 1 : undef; } sub STORE { my( $self, $index, $value ) = @_; $index > length $$self and $$self.= "" x ( 1 + $index - length $$self ); substr $$self, $index, 1, $value; } sub PUSH { my $self = shift; $$self.= join "", @_; length $$self; } sub POP { my $self = shift; my $last = substr $$self, -1, 1; $$self = substr $$self, 0, length( $$self ) - 1; $last; } 1;
20
28/2/2008Take control20 Testing CharArray.pm #! /usr/bin/perl use warnings; use strict; use Test::More 'no_plan'; use_ok 'CharArray'; { my $orig = 'value'; tie my @ca, 'CharArray', \$orig; is $ca[0], 'v', "First value '@ca' (${ tied( @ca ) })"; push @ca, 's'; is @ca, 6, "new length (${ tied( @ca ) })"; my $sorted = join "", sort @ca; is $sorted, 'aelsuv', "sorting the array works ($sorted)"; untie @ca; is $orig, 'values', "still the changed value in original ($orig)"; } # tie/array/ -> prove -lv t/*.t
21
28/2/2008Take control21 API: –TIEHANDLE constructor –schrijven PRINT, PRINTF WRITE –lezen READLINE READ, GETC –CLOSE –UNTIE, DESTROY TIEHANDLE API
22
28/2/2008Take control22 TIEHANDLE (output) Output –STDOUT, STDERR –Iedere andere GLOB Methods: –TIEHANDLE() –PRINT –PRINTF
23
28/2/2008Take control23 CatchOut.pm package CatchOut; use strict; use warnings; our $VERSION = 0.04; # tie *HANDLE, CatchOut => sub TIEHANDLE { my $class = shift; ref $_[0] eq __PACKAGE__ and return $_[0]; ref $_[0] eq 'SCALAR' or die "Usage:\n\ttie *HANDLE, CatchOut => "; bless $_[0], $class; } sub PRINT { my $self = shift; $$self.= join "", @_; } sub PRINTF { my $self = shift; my( $fmt, @args ) = @_; $$self.= sprintf $fmt, @args; } 1;
24
28/2/2008Take control24 Testing CatchOut.pm #! perl use warnings; use strict; use Test::More 'no_plan'; use_ok 'CatchOut'; { my $outbuf; { local *OUT; tie *OUT, 'CatchOut', \$outbuf; print OUT "Testline\n"; untie *OUT; } is $outbuf, <<' __EOTEST__', "Caught the right output"; Testline __EOTEST__ }
25
28/2/2008Take control25 TIEHANDLE (input) Input –STDIN –Elke andere GLOB Methods: –TIEHANDLE –READLINE
26
28/2/2008Take control26 FeedIn.pm package FeedIn; use warnings; use strict; our $VERSION = 0.01; # tie *FH, FeedIn => $text; sub TIEHANDLE { my( $class, $store ) = @_; bless \$store, $class; } sub READLINE { my $self = shift; defined $$self or return; length $$self or return; if ( ! defined $/ ) { # slurp-mode my $all = $$self; $$self = undef; return $all; } if ( wantarray ) { my @lines = grep length $_ => $$self =~ m{(.*?(?:$/|\z))}sg; $$self = undef; return @lines; } else { return defined $$self =~ s{(.*?(?:$/|\z))}{}s ? $1 : undef; } 1;
27
28/2/2008Take control27 Testing FeedIn.pm #! perl use warnings; use strict; use Test::More 'no_plan'; use_ok 'FeedIn'; { local *IN; tie *IN, 'FeedIn', "regel 1\nregel 2"; my @line = ; is scalar @line, 2, "2 lines in list-context"; is $line[0], "regel 1\n", "Read a line '$line[0]'"; is $line[1], "regel 2", "Read a line '$line[1]'"; } { local *IN; tie *IN, 'FeedIn', "regel 1\nregel 2"; my @line; while ( ) { push @line, $_ } is scalar @line, 2, "2 lines in list-context"; is $line[0], "regel 1\n", "Read a line '$line[0]'"; is $line[1], "regel 2", "Read a line '$line[1]'"; } { local *IN; tie *IN, 'FeedIn', "regel 1\nregel 2"; my $lines = do { local $/; }; is $lines, "regel 1\nregel 2", "Slurp-mode"; }
28
28/2/2008Take control28 Meer informatie perldoc perltie
29
28/2/2008Take control29 CORE::GLOBAL gebruikers?
30
28/2/2008Take control30 CORE::GLOBAL:: Herdefinieren interne functies –prototype CORE:: –In de compileer fase (BEGIN) Origineel altijd nog beschikbaar –CORE::
31
28/2/2008Take control31 CORE::GLOBAL::gmtime #! /usr/bin/perl use warnings; use strict; BEGIN { # 29 Feb 2008 12:00:00 GMT *CORE::GLOBAL::gmtime = sub (;$) { my $stamp = @_ ? $_[0] : 1204286400; CORE::gmtime( $stamp ); }; } printf "[ empty] %s\n", scalar gmtime( ); printf "[time()] %s\n", scalar gmtime( time );
32
28/2/2008Take control32 Een test case voor open() Ik wil de volgende soort code testen: – open my $fh, '<', '/proc/cpuinfo' Herdefinieer –CORE::GLOBAL::open Gebruik een tied handle voor invoer –FeedIn.pm
33
28/2/2008Take control33 MyOpen.pm package MyOpen; use warnings; use strict; our $VERSION = 0.01; sub core_open (*;$@) { my( $handle, $mode, $file, @list ) = @_; # make sure filehandles are in their own package my $pkg = caller; if ( defined $handle and !ref $handle ) { # bareword handle no strict 'refs'; $handle = *{ "$pkg\:\:$handle" }; } elsif ( !defined $handle ) { # undefined scalar, provide GLOBref $_[0] = $handle = do { no strict 'refs'; \*{ sprintf "%s::NH%d%d%d", $pkg, $$, time, rand 100 }; }; } # convert to two argumented open() defined $file and $mode.= " $file"; CORE::open( $handle, $mode ); }; # prepare open() for runtime override BEGIN { *CORE::GLOBAL::open = \&core_open } 1;
34
28/2/2008Take control34 Testing MyOpen.pm #! perl use warnings; use strict; use Test::More 'no_plan'; BEGIN { use_ok 'MyOpen' } ok defined &CORE::GLOBAL::open, "CORE::GLOBAL::open() defined"; my $content; { CORE::open( my $fh, '<', $0 ) or die "Cannot CORE::open($0): $!"; isa_ok $fh, 'GLOB'; $content = do { local $/; }; close $fh; like $content, qr/BEGIN { use_ok 'MyOpen' }/, "contains MyOpen"; } { open my $fh, '<', $0 or die "Cannot open($0): $!"; isa_ok $fh, 'GLOB'; my $file = do { local $/; }; close $fh; is $file, $content, "contents still the same"; }
35
28/2/2008Take control35 Bringing it togther (1/2) #! perl use warnings; use strict; use Test::More 'no_plan'; BEGIN { use_ok 'MyOpen' } ok defined &CORE::GLOBAL::open, "CORE::GLOBAL::open() defined"; use_ok 'FeedIn'; { no warnings 'redefine'; local *CORE::GLOBAL::open = \&tied_open; open my $fh, '<', $0 or die "Cannot tied_open($0): $!"; isa_ok tied( $fh ), 'FeedIn'; my $file = do { local $/; }; close $fh; is $file, "open: $0", "tied_open() returned '$file'"; }
36
28/2/2008Take control36 Bringing it together (2/2) sub tied_open (*;$@) { my( $handle, $mode, $file ) = @_; # make sure filehandles are in their own package my $pkg = caller; if ( defined $handle and !ref $handle ) { # bareword handle no strict 'refs'; $handle = *{ "$pkg\:\:$handle" }; } elsif ( !defined $handle ) { # undefined scalar, provide a GLOB $_[0] = $handle = do { no strict 'refs'; *{ sprintf "%s::NH%d%d%d", $pkg, $$, time, rand 100 }; }; } # convert to two argumented open() defined $file and $mode.= " $file"; # do the magic-tie for open "< $0" or pass to CORE::open() if ( $mode =~ m/^(?:<\s*)?($0)/ ) { tie $handle, FeedIn => "open: $1"; } else { CORE::open( $handle, $mode ); }
37
28/2/2008Take control37 Meer informatie perldoc perlsub
38
28/2/2008Take control38 Attribute::Handler gebruikers?
39
28/2/2008Take control39 Attribute::Handlers Perl heeft syntax voor attributes –:my_attribute(data) Perl heeft twee geïmplementeerde attributes –:lvalue –:ATTR Via :ATTR is de attribute implementatie uit te breiden –Een attribute is een sub met die naam die het :ATTR attribute heeft
40
28/2/2008Take control40 Types voor een attribute Deze typen kunnen een attribute krijgen –SCALAR –ARRAY –HASH –CODE (sub)
41
28/2/2008Take control41 Aandachtspunten De handler sub moet bekend zijn in de aanroepende namespace –use base –Declareer in UNIVERSAL:: Argumenten aan de handler sub –Aanroepende package –Referentie naar de symbol table (CODE) –Referentie naar de variabele/code –Attribute naam –Data die aan het attribute wordt mee gegeven –Fase voor de handler (BEGIN,CHECK,INIT,END)
42
28/2/2008Take control42 Een attribute voor tie() package Tie_OddEven; use strict; use warnings; our $VERSION = 0.01; use Attribute::Handlers; sub OddEven :ATTR(SCALAR) { my( $pkg, $symbol, $referent, $attr, $data ) = @_; tie $$referent, __PACKAGE__, $data; } sub TIESCALAR { my $class = shift; bless \(my $self = shift), $class; } sub FETCH { my $self = shift; return $$self % 2 == 0 ? 'even' : 'odd'; } sub STORE { my $self = shift; $$self = shift; } 1;
43
28/2/2008Take control43 Voorbeeld code voor gebruik #! /usr/bin/perl use warnings; use strict; use lib 'lib'; use Tie_OddEven; tie my $oe, Tie_OddEven => 0; while ( 1 ) { print "Number: "; chomp( my $input = <> ); last unless $input =~ /^-?\d+$/; $oe = $input; printf "$input is $oe (%d)\n", ${ tied $oe }; }
44
28/2/2008Take control44 Voorbeeld code voor gebruik #! /usr/bin/perl use warnings; use strict; use lib 'lib'; use base 'Tie_OddEven'; my $oe :OddEven(0); while ( 1 ) { print "Number: "; chomp( my $input = <> ); last unless $input =~ /^-?\d+$/; $oe = $input; printf "$input is $oe (%d)\n", ${ tied $oe }; }
45
28/2/2008Take control45 Oorspronkelijke attribute package Tie_OddEven; use strict; use warnings; our $VERSION = 0.01; use Attribute::Handlers; sub OddEven :ATTR(SCALAR) { my( $pkg, $symbol, $referent, $attr, $data ) = @_; tie $$referent, __PACKAGE__, $data; } sub TIESCALAR { my $class = shift; bless \(my $self = shift), $class; } sub FETCH { my $self = shift; return $$self % 2 == 0 ? 'even' : 'odd'; } sub STORE { my $self = shift; $$self = shift; } 1;
46
28/2/2008Take control46 Een UNIVERSAL:: attribute package Universal_OddEven; use strict; use warnings; our $VERSION = 0.01; use Attribute::Handlers; sub UNIVERSAL::OddEven :ATTR(SCALAR) { my( $pkg, $symbol, $referent, $attr, $data ) = @_; tie $$referent, __PACKAGE__, $data; } sub TIESCALAR { my $class = shift; bless \(my $self = shift), $class; } sub FETCH { my $self = shift; return $$self % 2 == 0 ? 'even' : 'odd'; } sub STORE { my $self = shift; $$self = shift; } 1;
47
28/2/2008Take control47 Oorspronkelijke voorbeeld #! /usr/bin/perl use warnings; use strict; use lib 'lib'; use base 'Tie_OddEven'; my $oe :OddEven(0); while ( 1 ) { print "Number: "; chomp( my $input = <> ); last unless $input =~ /^-?\d+$/; $oe = $input; printf "$input is $oe (%d)\n", ${ tied $oe }; }
48
28/2/2008Take control48 Gebruik UNIVERSAL attribute #! /usr/bin/perl use warnings; use strict; use lib 'lib'; use Universal_OddEven; my $oe :OddEven(0); while ( 1 ) { print "Number: "; chomp( my $input = <> ); last unless $input =~ /^-?\d+$/; $oe = $input; printf "$input is $oe (%d)\n", ${ tied $oe }; }
49
28/2/2008Take control49 Oorspronkelijke attribute package Tie_OddEven; use strict; use warnings; our $VERSION = 0.01; use Attribute::Handlers; sub OddEven :ATTR(SCALAR) { my( $pkg, $symbol, $referent, $attr, $data ) = @_; tie $$referent, __PACKAGE__, $data; } sub TIESCALAR { my $class = shift; bless \(my $self = shift), $class; } sub FETCH { my $self = shift; return $$self % 2 == 0 ? 'even' : 'odd'; } sub STORE { my $self = shift; $$self = shift; } 1;
50
28/2/2008Take control50 Een attribute en autotie package Auto_OddEven; use strict; use warnings; our $VERSION = 0.01; use Attribute::Handlers autotie => { '__CALLER__::OddEven' => __PACKAGE__ }; sub TIESCALAR { my $class = shift; bless \(my $self = shift), $class; } sub FETCH { my $self = shift; return $$self % 2 == 0 ? 'even' : 'odd'; } sub STORE { my $self = shift; $$self = shift; } 1;
51
28/2/2008Take control51 Gebruik autotie attribute #! /usr/bin/perl use warnings; use strict; use lib 'lib'; use Auto_OddEven; my $oe :OddEven(0); while ( 1 ) { print "Number: "; chomp( my $input = <> ); last unless $input =~ /^-?\d+$/; $oe = $input; printf "$input is $oe (%d)\n", ${ tied $oe }; }
52
28/2/2008Take control52 Meer informatie perldoc Attribute::Handlers
53
28/2/2008Take control53 User-defined lexical pragma gebruikers?
54
28/2/2008Take control54 fixedtime pragma SYNOPSIS use Test::More 'no_plan'; my $nowstamp = time; my $fixstamp; { use fixedtime stamp => 1204286400; # 29 Feb 2008 12:00:00 GMT $fixstamp = time; is $fixstamp, 1204286400, "Fixed point in time ($fixstamp)"; is scalar gmtime, "Fri Feb 29 12:00:00 2008", "@{[scalar gmtime]}"; no fixedtime; is time, $nowstamp, "we ran fast enough ($nowstamp)"; } is time, $nowstamp, "we ran fast enough ($nowstamp)";
55
28/2/2008Take control55 User-defined lexical pragma Nieuw in Perl 5.10 %^H hints hash (compiletime) –$^H{yourpragma} = 1 in sub import –$^H{yourpragma} = 0 in sub unimport –Alleen "eenvoudige" scalars (integer, string) (caller 1)[10] ref naar %^H (runtime) –Inspecteer $hh->{yourpragma} voor status
56
28/2/2008Take control56 fixedtime.pm (src1) package fixedtime; use 5.010; # this is a user-defined pragma and needs perl 5.10 or higher use warnings; use strict; our $VERSION = 0.01; sub import { shift; my %args = @_; $^H{fixedtime} = exists $args{stamp} ? $args{stamp} // CORE::time : CORE::time; } sub unimport { $^H{fixedtime} = undef } sub epoch_offset { my $level = shift // 0; my $ctrl_h = ( caller $level + 1 )[10]; return $ctrl_h->{fixedtime}; }
57
28/2/2008Take control57 fixedtime.pm (src2) BEGIN { *CORE::GLOBAL::time = sub { return fixedtime::epoch_offset() // CORE::time; }; *CORE::GLOBAL::gmtime = sub (;$) { my $stamp = shift // fixedtime::epoch_offset() // CORE::time; CORE::gmtime( $stamp ); }; *CORE::GLOBAL::localtime = sub (;$) { my $stamp = shift // fixedtime::epoch_offset() // CORE::time; CORE::localtime( $stamp ); }; } 1;
58
28/2/2008Take control58 Testing fixedtime.pm (1/2) #! perl use warnings; use strict; use Test::More 'no_plan'; { my $nowstamp = time; my $fixstamp; { use fixedtime stamp => 1204286400; # 29 Feb 2008 12:00:00 GMT $fixstamp = time; is $fixstamp, 1204286400, "Fixed point in time ($fixstamp)"; is scalar gmtime, "Fri Feb 29 12:00:00 2008", "(@{[ scalar gmtime ]})"; no fixedtime; is time, $nowstamp, "we ran fast enough inner ($nowstamp)"; } is time, $nowstamp, "we ran fast enough outer ($nowstamp)"; isnt $nowstamp, $fixstamp, "now() != fixed"; }
59
28/2/2008Take control59 Testing fixedtime.pm (2/2) my @cgtime = gmtime; my @fgtime = ( 0, 0, 12, 29, 1, 108, 5, 59, 0 ); { use fixedtime stamp => 1204286400; # 29 Feb 2008 12:00:00 GMT my @ftime = gmtime; is_deeply \@ftime, \@fgtime, "gmtime() is fixed (@{[ scalar gmtime ]})" or diag Dumper \@ftime; { # nested calls should update the fixed stamp use fixedtime stamp => 1204286400 + 60 * 60; my @fltime = @fgtime; $fltime[2] += 1; my @ltime = gmtime; is_deeply \@ltime, \@fltime, "gmtime() in scope (@{[ scalar gmtime ]})" or diag Dumper \@ltime; } @ftime = gmtime; is_deeply \@ftime, \@fgtime, "gmtime() is back (@{[ scalar gmtime ]})" or diag Dumper \@ftime; no fixedtime; my @gtime = gmtime; is_deeply \@gtime, \@cgtime, "times compare (@{[ scalar gmtime ]})" or diag Dumper \@gtime; } my @gtime = gmtime; is_deeply \@gtime, \@cgtime, "times compare (@{[ scalar gmtime ]})" or diag Dumper \@gtime;
60
28/2/2008Take control60 Meer informatie perldoc perlpragma
61
28/2/2008Take control61 Vragen?
62
28/2/2008Take control62 Dank je wel!
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.