User:Feixie/Perl/Intermedia Perl

Variables Scope

 * Variables
 * lexical variable: my
 * global variable: our
 * package variable
 * Block & Module

eixie@feixie-desktop:~/Programs/Perl$ cat callee1.pm use strict;

our $var1="var1"; my $div = 1/0; {sub c1{print "c1\n";}} return 1; feixie@feixie-desktop:~/Programs/Perl$ cat callee2.pm use strict;

our $var2="var2"; {sub c2{print "c2\n";}} return 1; feixie@feixie-desktop:~/Programs/Perl$ cat Callee.pm package Callee; use strict;
 * 1) my $div = 1/0;

our $var3="var3"; my $var4="var4"; {sub c3{print "c3\n";}} return 1; feixie@feixie-desktop:~/Programs/Perl$ cat cat caller.pl cat: cat: No such file or directory use strict;
 * 1) !/usr/bin/perl

eval 'my $div = 1/0;'; #compile every time eval {my $div = 1/0}; #compile once print "main is alive\n";
 * 1) eval {my $div=}; #compile fail

do 'callee1.pm'; # similar to eval require 'callee2.pm'; # only exec once for each file, but won't survive syntax in required file use Callee;

our $var1; our $var2; our $var3; print "var1=$var1\n"; print "var2=$var2\n"; print "var3=$var3\n"; print "Callee::var3=$Callee::var3\n"; {sub a{print "a\n";}} a; c1; c2; Callee::c3; feixie@feixie-desktop:~/Programs/Perl$ ./caller.pl main is alive var1=var1 var2=var2 var3= Callee::var3=var3 a c1 c2 c3

Manipulate Complex Data

 * Observe
 * perl -d file.pl
 * Data::Dumper
 * use Storable;
 * Indirect grep/map
 * grep indices of list
 * select elements or values of elements

Subrouting Reference
use File::Find; use File::stat; use Date::Manip; use Date::Manip::Date;

my $time_fmt = "%Y%m%d %H%M%S"; sub make_filter_time_func {  my @result_set; my $return_func = sub {    return @result_set; }; my ($begin, $end) = @_; my $filter_func = sub {    my $filename = $_; my $sb = stat $filename; my $mtime = new Date::Manip::Date; my $secs = $sb->mtime; $mtime->parse("epoch $secs"); #print "compare ". $mtime->printf($time_fmt). " with ". $begin->printf($time_fmt). " and ". $end->printf($time_fmt). "\n"; if ($mtime->cmp($begin) > 0 and $mtime->cmp($end) < 0) {      #print "pushing ". $mtime->printf($time_fmt). "\n"; push @result_set, $filename; } };  return ($filter_func, $return_func); } my ($begin_str, $end_str) = @ARGV; my $begin = new Date::Manip::Date; my $end = new Date::Manip::Date; my $err = $begin->parse($begin_str); $err = $end->parse($end_str);
 * 1) print $begin->printf($time_fmt) . "\n";
 * 2) print $end->printf($time_fmt) . "\n";

if ($err) {  print "$begin_str and $end_str are not valid\n"; exit; }

my ($func, $ret_func) = make_filter_time_func($begin, $end);

find($func, "."); print join("\n", $ret_func->);

File Handle Reference
use IO::File; use DateTime; use IO::Tee; use IO::Scalar;

my %dest_fhs; my $src_fh;

my $log = ""; my $log_fh = new IO::Scalar(\$log);

open($src_fh, ") { my ($p, $f) = split(/:/, $_); if (!exists $dest_fhs{$p}) {   open(my $fh, ">$p") or die "can't open file $p"; my $tfh = new IO::Tee($log_fh, $fh); $dest_fhs{$p} = $tfh; print $tfh "start!\n";  # NO need braces around ref to file handler if it is a scalar var } my $now = DateTime->now; print {$dest_fhs{$p}} "at $now: $p eats $f";   # do need braces around non-scalar var sleep 1; } print $log;

Class Method

 * inheritance
 * our @ISA = qw(Base);
 * use Base; use vars qw(@ISA); @ISA = qw(Base);
 * use base Base;
 * Calling
 * Class::method('ClassName', @args);
 * Class->method(@args);
 * my $class = 'ClassName'; $class->method(@args);
 * $class->SUPER::method(@args);

use strict;
 * 1) !/usr/bin/perl

{package LivingCreature; sub speak{ my $class = shift; print "$class say: ". (@_ ? "@_" : $class->sound). "\n"; } } {package Animal; our @ISA = qw(LivingCreature); #run time, our is needed with strict on sub speak { my $class = shift; $class->SUPER::speak; } } {package Person; use base qw(LivingCreature); #compile time operation sub speak{ my $class = shift; $class->LivingCreature::speak(@_); } sub sound{return "hummmn";}; } {package Dog; use vars qw(@ISA); @ISA = qw(Animal); sub sound{return "WongWong!";}; } Person::speak('Person', "hello"); Person->speak("haha"); my $p = 'Person';$p->speak("hehe"); $_->speak for qw(Person Dog);

Object with Data

 * bless can only be use on references to built-in types. The original purpose of blessing is to associate a class with that reference to allow Perl to find proper methods.
 * Tips:
 * use "ref" to differentiate class (string) and blessed reference
 * printing blessed reference shows both class name and scalar value of reference
 * use Carp qw(croak carp) for error tracking
 * croak is different from die in that croak places blame on the caller rather than itself
 * carp v.s. warn, same as croak v.s. die

Object destruction

 * DESTROY method: unlike C++, it won't calls its base class' DESTROY. You'd better do it by yourself.
 * Indirect Object Notation: method Class/blessed reference parameters. It only works on bare word, a simple scalar value and curly braces block which returns a class name or blessed reference. (trick way to simulate C++ new)
 * Class variable is actually package variable
 * weaken reference: use Scalar qw(weaken); If all ordinary reference are gone, the thingy will be destroyed and all weaken references are turned to undef
 * Tips:
 * ${+shift}: curly braces only contains bare word. In order to make this work, we need the unary plus operator which does nothing in Perl.
 * unlink/tempfile

Some OOP/Module Topics
use A::B::C qw(method); equals BEGIN{               <== means it happens at compile time require A::B::C;   <== load file once, file name would be A/B/C.pm  A::B::C->import(qw(method));   <== build aliases from callee pkg to caller pkg }
 * UNIVERSAL Methods: After the module search fails, Perl always look in one special class "UNIVERSAL". All classes are derived from it. Two methods of it are useful (Notice that it only works on blessed reference or scalar looks like class name, otherwise you will get a fatal error. Better to trap error with eval.):
 * isa('ClassName')
 * can('MethodName')
 * AUTOLOAD: After Perl searches the inheritance tree for a method, it will repeat the searching again for AUTOLOAD method. If found, AUTOLOAD is invoked in place of the searched method.
 * $AUTOLOAD contains the original method's full name
 * Parameters to AUTOLOAD method: class name or instance reference, arguments passed to original method
 * One use is lazy loading for some resource consuming method
 * Another use is Automatically generate methods that not defined such as getter/setter (generate only once)
 * Tips: goto, no strict 'ref'
 * Multiply Inheritance
 * Depth First Search for method searching
 * Exporter
 * Variables:
 * @EXPORT_OK : names exported on command
 * @EXPORT : names exported by default
 * %EXPORT_TAGS : group functions or variables under a single name. use Pkg qw(:group_name)

Module/Lib Distribution

 * run "h2xs -An ModuleName" to look around files

Test

 * Test::More
 * use Test::More tests=>NumberOfTestcases;
 * use Test::More "no_plan";
 * ok(actual, "desc")
 * is(actual, expected, "desc")
 * isnt(...)
 * like(actual, regex, "desc")
 * is_ok(obj, className);
 * can_ok(obj, methodName);
 * TODO: {local $TODO = "why to do?";...;}
 * SKIP: {skip("why skip?") unless ..;...;}
 * Makefile.pl runs testcase files in the nature order of file names; or you can specify t/test_manifest
 * More CPAN Modules
 * Test::LargeString : is_string(str1, str2)
 * Test::File : file_exist_ok(fileName);...
 * Test::Output : stdout_is($func_ref, str); stderr_like($func_ref, str);...
 * Test::MockObject : my $mo = Test::MockOjbect->new;$mo->set_true(funcName);$mo->mock(funcName => $func_ref);
 * Test::Builder : my $tb = Test::Builder->new; ... $tb->diag("why failed");$tb->ok(0/1);