Presentation is loading. Please wait.

Presentation is loading. Please wait.

Take control Introductie in het wijzigen van standaard Perl gedrag use Workshop::Perl::Dutch 5; date( '2008-02-29' ); author( abeltje => 'Abe Timmerman'

Similar presentations


Presentation on theme: "Take control Introductie in het wijzigen van standaard Perl gedrag use Workshop::Perl::Dutch 5; date( '2008-02-29' ); author( abeltje => 'Abe Timmerman'"— Presentation transcript:

1 Take control Introductie in het wijzigen van standaard Perl gedrag use Workshop::Perl::Dutch 5; date( ' ' ); 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 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 'CharArray', \$orig; is $ca[0], 'v', "First value (${ ) })"; 's'; 6, "new length (${ ) })"; my $sorted = join "", is $sorted, 'aelsuv', "sorting the array works ($sorted)"; 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( ) $$self.= sprintf } 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 ) { = grep length $_ => $$self =~ m{(.*?(?:$/|\z))}sg; $$self = undef; } 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"; = ; is 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"; while ( ) { $_ } is 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 :00:00 GMT *CORE::GLOBAL::gmtime = sub (;$) { my $stamp ? $_[0] : ; 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, ) # 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 => ; # 29 Feb :00:00 GMT $fixstamp = time; is $fixstamp, , "Fixed point in time ($fixstamp)"; is scalar gmtime, "Fri Feb 29 12:00: ", 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 => ; # 29 Feb :00:00 GMT $fixstamp = time; is $fixstamp, , "Fixed point in time ($fixstamp)"; is scalar gmtime, "Fri Feb 29 12:00: ", 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) = gmtime; = ( 0, 0, 12, 29, 1, 108, 5, 59, 0 ); { use fixedtime stamp => ; # 29 Feb :00:00 GMT = gmtime; is_deeply "gmtime() is fixed scalar gmtime ]})" or diag Dumper { # nested calls should update the fixed stamp use fixedtime stamp => * 60; $fltime[2] += 1; = gmtime; is_deeply "gmtime() in scope scalar gmtime ]})" or diag Dumper = gmtime; is_deeply "gmtime() is back scalar gmtime ]})" or diag Dumper no fixedtime; = gmtime; is_deeply "times compare scalar gmtime ]})" or diag Dumper } = gmtime; is_deeply "times compare scalar gmtime ]})" or diag Dumper

60 28/2/2008Take control60 Meer informatie perldoc perlpragma

61 28/2/2008Take control61 Vragen?

62 28/2/2008Take control62 Dank je wel!


Download ppt "Take control Introductie in het wijzigen van standaard Perl gedrag use Workshop::Perl::Dutch 5; date( '2008-02-29' ); author( abeltje => 'Abe Timmerman'"

Similar presentations


Ads by Google