Search This Blog

Friday, June 12, 2020

PERL cheat sheet

                      

Perl Cheat Sheet

Get information on a function by typing, e.g., perldoc -f chomp at the command line.
Scalar variables
while (defined ($x=<>)) {code}
False if variable has never been set (or when you try to read past the end of an input file)
length($x)
Length of a string
chomp($line);
Remove a newline at the end of a string
$short=substr ($long, 2, 5)
Characters 3-7 of $long (first char is 0!)
Arrays
push @arr, $x
Add to end of array
$x = pop @arr;
Remove last element of array, put in $x
shift @arr;  (See also unshift)
Remove first element of an arrray, put in $x
$size = scalar @arr;
Number of things in the array
See also: split, join,
splice, sort
split string->array, join array->string,
delete part of array, sort array in many ways
Hashes
@key = keys %hash
The lookup terms in the hash
if (exists $hh{“Hsp”}) {...}
See whether hash %hh has a value for that key
Input/Output and Files
open(HANDLE, ">outfile") or die “Can’t open $outfile: $!\n”
Open outfile for writing, and associate it with filehandle HANDLE. Use “<infile” for reading
print $x;
print HANDLE $x;
Prints to standard output (screen),
Print to filehandle HANDLE
warn “Something wrong\n”;
Prints to standard error (screen)
$x=<HANDLE>
Read a line from filehandle HANDLE, put in $x
close(HANDLE);
Stop reading/writing a previously opened file
Exit
exit;
Exits the program
die "Something broke!\n";
Exits the program with error message

Operators and Loops

Assign value
$x = 1
Sets variable to a value. Don’t confuse with ==, which tests whether numerical values are equal
Math
print 1 * (2 + 3/4)
Regular math symbols
10%3==1; 12%3==0
Modulus (remainder) operator
$x += 4;
Same as $x=$x=4; Also -= *= /=
$x++;
Same as $x=$x+1;
Conditions
if (.1 == 0.1) {print “same num”}
Are numbers equal? Don’t confuse with =
if (1 != 2) {print “diff num”}
Are numbers different?
> < >= <=
Are numbers greater than, less than, etc.
if (“a” eq “a”) {print “same text”}
Does text have exactly the same letters?
if (“A” ne “a”) {print “diff text”}
Does text have different letters?
if (($x > 1) && ($x < 2)) {code}
AND (true if both sides are true)
if (($x > 10) || ($x < -10)) {code}
OR (true if one or both sides are true)
=~ !~
Test for a match: See Matching cheat sheet
Loops
foreach $i (1 .. 100) {code}
(for and foreach are equivalent)
Sets $i to 1 and does code. Sets $i to 2, …
up to (and including) 100

while ($a < $b) {code}
Does code while the condition is true
(If condition is false, never enters the loop.)


Matching and Regular Expressions

Test for Match
=~
Test for match
if ($x =~ /abc/) {
    ...}
Does $x have the string “abc” anywhere in it?
!~
Test for non-match
if ($x !~ /abc/) {
    ...}
Does $x NOT have the string “abc” anywhere in it?
$_
Default variable
if (/abcd/) {
    s/bc/x/ }
// and s/// work on $_ by default, no =~ needed
Substitute
s///
Do a Substitution
$x =~ s/abc/def/;
Replace (only) first occurrence of “abc” in $x with def
Options to Search / Substitution
i
Ignore case.
/abc/i
Matches abc, ABC, aBc, etc.
g
Global substitution.
s/a/c/g
Replace ALL occurrences
Special Match Items
.
Any one character (except \n)
/a.c/
“arc”, “a9c”, but not “ac”.
[ ]
Any one of.
/[abc]/
Any one of “a”, “b”, or “c”.  [a-zA-Z] matches any letter
\d
Digit (Same as [0-9])
/\d\d:\d\d/
“10:30” (but not “9:30”)
\s
Space, tab, or newline
/^\s*$/
An empty line.
\
Literally match special characters:  + * ( ) / [ ] \ | { } ^ $ @
/1\+2/
“1+2”, not “1112”. The backslash “quotes” or “escapes” the plus sign.
Item Locations
^
Beginning of a line
/^a/
"arginine" but not "valine”.
$
End of a line
/a$/
"beta" but not "beat".
Item Repetitions
?
An optional thing
/ab?c/
“ac” or “abc”.
*
Any number of copies OR nothing at all
/a*/
"", "a", "aaa".
+
Any number of copies
/a+b/
"ab" or "aaab" but not "b".
{ }
m to n copies
/ab{2,4}c/
“abbc”, “abbbc”, “abbbbc”, but not “abc” or “abbbbbc”
Misc
|
One or the other
/abc|def/
“abc” or “def”
( )
Group things together AND capture in numbered variables
/a(b(..)e)f/
“abcdef”. This will also set $1 to “c” and $2 to “bcde”.


#####################################
1:An Overview of Perl/Getting Started
#####################################

print "Howdy, world!\n";

######################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax
######################################################################

$phrase = "Howdy, world!\n";          # Set a variable.
print $phrase;                        # Print the variable.

####################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Singularities
####################################################################################

$answer = 42;                # an integer
$pi = 3.14159265;            # a "real" number
$avocados = 6.02e23;         # scientific notation
$pet = "Camel";              # string
$sign = "I love my $pet";    # string with interpolation
$cost = 'It costs $100';     # string without interpolation
$thence = $whence;           # another variable's value
$salsa = $moles * $avocados; # a gastrochemical expression
$exit = system("vi $file");  # numeric status of a command
$cwd = `pwd`;                # string output from a command

--------------

$ary = \@myarray;            # reference to a named array
$hsh = \%myhash;             # reference to a named hash
$sub = \&mysub;              # reference to a named subroutine

$ary = [1,2,3,4,5];          # reference to an unnamed array
$hsh = {Na => 19, Cl => 35}; # reference to an unnamed hash
$sub = sub { print $state }; # reference to an unnamed subroutine

$fido = new Camel "Amelia";  # ref to an object

--------------

$camels = '123';
print $camels + 1, "\n";

--------------

$fido = new Camel "Amelia";
if (not $fido) { die "dead camel"; }
$fido->saddle();

##########################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Pluralities/Arrays.
##########################################################################################

@home = ("couch", "chair", "table", "stove");

--------------

($potato, $lift, $tennis, $pipe) = @home;

--------------

($alpha,$omega) = ($omega,$alpha);

--------------

$home[0] = "couch";
$home[1] = "chair";
$home[2] = "table";
$home[3] = "stove";

##########################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Pluralities/Hashes.
##########################################################################################

%longday = ("Sun", "Sunday", "Mon", "Monday", "Tue", "Tuesday",
            "Wed", "Wednesday", "Thu", "Thursday", "Fri",
            "Friday", "Sat", "Saturday");

--------------

%longday = (
    "Sun" => "Sunday",
    "Mon" => "Monday",
    "Tue" => "Tuesday",
    "Wed" => "Wednesday",
    "Thu" => "Thursday",
    "Fri" => "Friday",
    "Sat" => "Saturday",
);

--------------

$wife{"Adam"} = "Eve";

###################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Complexities
###################################################################################

$wife{"Jacob"} = ("Leah", "Rachel", "Bilhah", "Zilpah");

--------------

$wife{"Jacob"} = ["Leah", "Rachel", "Bilhah", "Zilpah"];

--------------

$wife{"Jacob"}[0] = "Leah";
$wife{"Jacob"}[1] = "Rachel";
$wife{"Jacob"}[2] = "Bilhah";
$wife{"Jacob"}[3] = "Zilpah";

--------------

$kids_of_wife{"Jacob"} = {
    "Leah"   => ["Reuben", "Simeon", "Levi",
                 "Judah", "Issachar", "Zebulun"],
    "Rachel" => ["Joseph", "Benjamin"],
    "Bilhah" => ["Dan", "Naphtali"],
    "Zilpah" => ["Gad", "Asher"],
};

--------------

$kids_of_wife{"Jacob"}{"Leah"}[0]   = "Reuben";
$kids_of_wife{"Jacob"}{"Leah"}[1]   = "Simeon";
$kids_of_wife{"Jacob"}{"Leah"}[2]   = "Levi";
$kids_of_wife{"Jacob"}{"Leah"}[3]   = "Judah";
$kids_of_wife{"Jacob"}{"Leah"}[4]   = "Issachar";
$kids_of_wife{"Jacob"}{"Leah"}[5]   = "Zebulun";
$kids_of_wife{"Jacob"}{"Rachel"}[0] = "Joseph";
$kids_of_wife{"Jacob"}{"Rachel"}[1] = "Benjamin";
$kids_of_wife{"Jacob"}{"Bilhah"}[0] = "Dan";
$kids_of_wife{"Jacob"}{"Bilhah"}[1] = "Naphtali";
$kids_of_wife{"Jacob"}{"Zilpah"}[0] = "Gad";
$kids_of_wife{"Jacob"}{"Zilpah"}[1] = "Asher";

--------------

$fido = new Camel "Amelia";

###################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Simplicities
###################################################################################

package Camel;

--------------

package Camel;
$fido = &fetch();

--------------

package Dog;
$fido = &fetch();

--------------

$fido = new Camel "Amelia";

--------------

$fido->saddle();

--------------

use Camel;

--------------

$fido = new Camel "Amelia";

--------------

use Some::Cool::Module;

--------------

use strict;

############################################################
1:An Overview of Perl/Natural and Artificial Languages/Verbs
############################################################

print "Adam's wife is $wife{'Adam'}.\n";

--------------

$e = exp(1);   # 2.718281828459 or thereabouts

########################################
1:An Overview of Perl/An Average Example
########################################

#!/usr/bin/perl

open(GRADES, "grades") or die "Can't open grades: $!\n";
while ($line = <GRADES>) {
    ($student, $grade) = split(" ", $line);
    $grades{$student} .= $grade . " ";
}

foreach $student (sort keys %grades) {
    $scores = 0;
    $total = 0;    
    @grades = split(" ", $grades{$student});
    foreach $grade (@grades) {
        $total += $grade;
        $scores++;
    }
    $average = $total / $scores;
    print "$student: $grades{$student}\tAverage: $average\n";
}

#####################################################
1:An Overview of Perl/An Average Example/How to Do It
#####################################################

% perl -e 'print "Hello, world!\n";'

--------------

% perl gradation

--------------

#!/usr/bin/perl

--------------

% gradation

--------------

% ../bin/gradation

--------------

#!/bin/sh -- # perl, to stop looping
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
    if 0;

--------------

#!/usr/bin/perl -w

#################################
1:An Overview of Perl/Filehandles
#################################

open(SESAME, "filename")               # read from existing file
open(SESAME, "<filename")              #   (same thing, explicitly)
open(SESAME, ">filename")              # create file and write to it
open(SESAME, ">>filename")             # append to existing file
open(SESAME, "| output-pipe-command")  # set up an output filter
open(SESAME, "input-pipe-command |")   # set up an input filter

--------------

print STDOUT "Enter a number: ";          # ask for a number
$number = <STDIN>;                        # input the number
print STDOUT "The number is $number.\n";  # print the number

--------------

chop($number = <STDIN>);    # input number and remove newline

--------------

$number = <STDIN>;          # input number
chop($number);              # remove newline

################################################
1:An Overview of Perl/Operators/String Operators
################################################

$a = 123;
$b = 456;
print $a + $b;     # prints 579
print $a . $b;     # prints 123456

--------------

$a = 123;
$b = 3;
print $a * $b;     # prints 369
print $a x $b;     # prints 123123123

--------------

print $a . ' is equal to ' . $b . ".\n";    # dot operator
print $a, ' is equal to ', $b, ".\n";       # list
print "$a is equal to $b.\n";               # interpolation

--------------

print "-" x $scrwid, "\n";

####################################################
1:An Overview of Perl/Operators/Assignment Operators
####################################################

$a = $b;
$a = $b + 5;
$a = $a * 3;

--------------

$a *= 3;

--------------

$line .= "\n";  # Append newline to $line.
$fill x= 80;    # Make string $fill into 80 repeats of itself.
$val ||= "2";   # Set $val to 2 if it isn't already "true".

--------------

$a = $b = $c = 0;

--------------

($temp -= 32) *= 5/9;

--------------

chop($number = <STDIN>);

##########################################################
1:An Overview of Perl/Operators/Unary Arithmetic Operators
##########################################################

$a = 5;        # $a is assigned 5
$b = ++$a;     # $b is assigned the incremented value of $a, 6
$c = $a--;     # $c is assigned 6, then $a is decremented to 5

#################################################
1:An Overview of Perl/Operators/Logical Operators
#################################################

open(GRADES, "grades") or die "Can't open file grades: $!\n";

########################################################
1:An Overview of Perl/Operators/Some File Test Operators
########################################################

-e "/usr/bin/perl" or warn "Perl is improperly installed\n";
-f "/vmlinuz" and print "I see you are a friend of Linus\n";

#######################################################
1:An Overview of Perl/Control Structures/What Is Truth?
#######################################################

0          # would become the string "0", so false.
1          # would become the string "1", so true.
10 - 10    # 10-10 is 0, would convert to string "0", so false.
0.00       # equals 0, would convert to string "0", so false.
"0"        # the string "0", so false.
""         # a null string, so false.
"0.00"     # the string "0.00", neither "" nor "0", so true!
"0.00" + 0 # the number 0 (coerced by the +), so false.
\$a        # a reference to $a, so true, even if $a is false.
undef()    # a function returning the undefined value, so false.

####################################################################################
1:An Overview of Perl/Control Structures/What Is Truth?/The if and unless statements
####################################################################################

if ($debug_level > 0) {
    # Something has gone wrong.  Tell the user.
    print "Debug: Danger, Will Robinson, danger!\n";
    print "Debug: Answer was '54', expected '42'.\n";
}

--------------

if ($city eq "New York") {
    print "New York is northeast of Washington, D.C.\n";
}
elsif ($city eq "Chicago") {
    print "Chicago is northwest of Washington, D.C.\n";
}
elsif ($city eq "Miami") {
    print "Miami is south of Washington, D.C.  And much warmer!\n";
}
else {
    print "I don't know where $city is, sorry.\n";
}

--------------

unless ($destination eq $home) {
    print "I'm not going home.\n";
}

######################################################################################################
1:An Overview of Perl/Control Structures/Iterative (Looping) Constructs/The while and until statements
######################################################################################################

while ($tickets_sold < 10000) {
    $available = 10000 - $tickets_sold;
    print "$available tickets are available.  How many would you like: ";
    $purchase = <STDIN>;
    chomp($purchase);
    $tickets_sold += $purchase;
}

--------------

print "This show is sold out, please come back later.\n";

--------------

while (@ARGV) {
    process(shift @ARGV);
}

#########################################################################################
1:An Overview of Perl/Control Structures/Iterative (Looping) Constructs/The for statement
#########################################################################################

for ($sold = 0; $sold < 10000; $sold += $purchase) {
    $available = 10000 - $sold;
    print "$available tickets are available.  How many would you like: ";
    $purchase = <STDIN>;
    chomp($purchase);
}

#############################################################################################
1:An Overview of Perl/Control Structures/Iterative (Looping) Constructs/The foreach statement
#############################################################################################

foreach $user (@users) {
    if (-f "$home{$user}/.nexrc") {
        print "$user is cool... they use a perl-aware vi!\n";
    }
}

--------------

foreach $key (sort keys %hash) {

###################################################################################################
1:An Overview of Perl/Control Structures/Iterative (Looping) Constructs/Breaking out: next and last
###################################################################################################

foreach $user (@users) {
    if ($user eq "root" or $user eq "lp") {
        next;
    }
    if ($user eq "special") {
        print "Found the special account.\n";
        # do some processing
        last;
    }
}

--------------

LINE: while ($line = <ARTICLE>) {
    last LINE if $line eq "\n"; # stop on first blank line
    next LINE if $line =~ /^#/; # skip comment lines
    # your ad here
}

#########################################
1:An Overview of Perl/Regular Expressions
#########################################

if (/Windows 95/) { print "Time to upgrade?\n" }

--------------

s/Windows/Linux/;

--------------

($good, $bad, $ugly) = split(/,/, "vi,emacs,teco");

--------------

while ($line = <FILE>) {
    if ($line =~ /http:/) {
        print $line;
    }
}

--------------

while (<FILE>) {
    print if /http:/;
}

--------------

while (<FILE>) {
    print if /http:/;
    print if /ftp:/;
    print if /mailto:/;
    # What next?
}

#####################################################
1:An Overview of Perl/Regular Expressions/Quantifiers
#####################################################

$_ = "fred xxxxxxx barney";
s/x*//;

#############################################################
1:An Overview of Perl/Regular Expressions/Nailing Things Down
#############################################################

/\bFred\b/

--------------

next LINE if $line =~ /^#/;

########################################################
1:An Overview of Perl/Regular Expressions/Backreferences
########################################################

s/(\S+)\s+(\S+)/$2 $1/

#####################################
1:An Overview of Perl/List Processing
#####################################

@array = (1 + 2, 3 - 4, 5 * 6, 7 / 8);

--------------

sort @dudes, @chicks, other();

--------------

print reverse sort map {lc} keys %hash;

--------------

($hour, $min, $sec, $ampm) = /(\d+):(\d+):(\d+) *(\w+)/;

--------------

@hmsa = /(\d+):(\d+):(\d+) *(\w+)/;

#####################################
2:Bits and Pieces/Built-in Data Types
#####################################

$x = $y;

--------------

$x = $y + 1;

###########################
2:Bits and Pieces/Variables
###########################

@days = 1 .. 7;

#######################
2:Bits and Pieces/Names
#######################

$Santa::Helper::Reindeer::Rudolph::nose

####################################
2:Bits and Pieces/Names/Name Lookups
####################################

$bert

--------------

${ some_expression() }

################################################
2:Bits and Pieces/Scalar Values/Numeric literals
################################################

$x = 12345;                # integer
$x = 12345.67;             # floating point
$x = 6.02e23;              # scientific notation
$x = 4_294_967_296;        # underline for legibility
$x = 0377;                 # octal
$x = 0xffff;               # hexadecimal
$x = 0b1100_0000;          # binary

###############################################
2:Bits and Pieces/Scalar Values/String literals
###############################################

$Price = '$100';                    # not interpolated
print "The price is $Price.\n";     # interpolated

--------------

$days{'Feb'}

--------------

$days{Feb}

--------------

$days{'February 29th'}   # Ok.
$days{"February 29th"}   # Also ok. "" doesn't have to interpolate.
$days{ February 29th }   # WRONG, produces parse error.

--------------

@days{'Jan','Feb'}       # Ok.
@days{"Jan","Feb"}       # Also ok.
@days{ Jan,  Feb }       # Kinda wrong (breaks under use strict)

--------------

print "\n";              # Ok, print a newline.
print  \n ;              # WRONG, no interpolative context.

####################################################
2:Bits and Pieces/Scalar Values/Pick your own quotes
####################################################

$single = q!I said, "You said, 'She said it.'"!;

$double = qq(Can't we get some "good" $variable?);

$chunk_of_code = q {
    if ($condition) {
        print "Gotcha!";
    }
};

--------------

tr (a-f)
   [A-F];

--------------

s {foo}   # Replace foo
  {bar};  #    with bar.

tr [a-f]  # Translate lowercase hex
   [A-F]; #        to uppercase hex

################################################################
2:Bits and Pieces/Scalar Values/Or leave the quotes out entirely
################################################################

@days = (Mon,Tue,Wed,Thu,Fri);
print STDOUT hello, ' ', world, "\n";

--------------

@days = qw(Mon Tue Wed Thu Fri);
print STDOUT "hello world\n";

--------------

use strict 'subs';

--------------

no strict 'subs';

--------------

"${verb}able"
$days{Feb}

##########################################################
2:Bits and Pieces/Scalar Values/Interpolating array values
##########################################################

$temp = join( $", @ARGV );
print $temp;

print "@ARGV";

################################################
2:Bits and Pieces/Scalar Values/"Here" documents
################################################

    print <<EOF;    # same as earlier example
The price is $Price.
EOF

    print <<"EOF";  # same as above, with explicit quotes
The price is $Price.
EOF

    print <<'EOF';    # single-quoted quote
All things (e.g. a camel's journey through
A needle's eye) are possible, it's true.
But picture how the camel feels, squeezed out
In one long bloody thread, from tail to snout.
                                -- C.S. Lewis
EOF

    print << x 10;    # print next line 10 times
The camels are coming!  Hurrah!  Hurrah!

    print <<"" x 10;  # the preferred way to write that
The camels are coming!  Hurrah!  Hurrah!

    print <<`EOC`;    # execute commands
echo hi there
echo lo there
EOC

    print <<"dromedary", <<"camelid"; # you can stack them
I said bactrian.
dromedary
She said llama.
camelid

    funkshun(<<"THIS", 23, <<'THAT');
Here's a line
or two.
THIS
And here's another.
THAT

--------------

    print <<'odd'
2345
odd
    + 10000;   # prints 12345

--------------

($quote = <<'QUOTE') =~ s/^\s+//gm;
    Christians and camels receive
    their blessings on their knees.
QUOTE

--------------

@sauces = <<End_Lines =~ m/(\S.*\S)/g;
   normal tomato
   spicy tomato
   green chile
   pesto
   white wine
End_Lines

#################################################
2:Bits and Pieces/Scalar Values/V-String Literals
#################################################

$crlf = v13.10;           # ASCII carriage return, line feed

--------------

"\x{1}\x{14}\x{12c}\x{fa0}"
pack("U*", 1, 20, 300, 4000)
chr(1) . chr(20) . chr(300) . chr(4000)

--------------

print v9786;              # prints UTF-8 encoded SMILEY, "\x{263a}"
print v102.111.111;       # prints "foo"
print 102.111.111;        # same thing

use 5.6.0;                # require a particular Perl version (or later)

$ipaddr = 204.148.40.9;   # the IPv4 address of oreilly.com

#################################################
2:Bits and Pieces/Context/Scalar and list context
#################################################

$x         = funkshun();  # scalar context
$x[1]      = funkshun();  # scalar context
$x{"ray"}  = funkshun();  # scalar context

--------------

@x         = funkshun();  # list context
@x[1]      = funkshun();  # list context
@x{"ray"}  = funkshun();  # list context
%x         = funkshun();  # list context

--------------

($x,$y,$z) = funkshun();  # list context
($x)       = funkshun();  # list context

--------------

my $x      = funkshun();  # scalar context
my @x      = funkshun();  # list context
my %x      = funkshun();  # list context
my ($x)    = funkshun();  # list context

#########################################
2:Bits and Pieces/Context/Boolean context
#########################################

unlink @files;      # Delete all files, ignoring errors.

--------------

while (@files) {
    my $file = shift @files;
    unlink $file or warn "Can't delete $file: $!\n";
}

######################################
2:Bits and Pieces/Context/Void context
######################################

"Camel Lot";

########################################
2:Bits and Pieces/List Values and Arrays
########################################

@stuff = ("one", "two", "three");

--------------

$stuff = ("one", "two", "three");

--------------

@stuff = ("one", "two", "three");
$stuff = @stuff;

--------------

(@stuff,@nonsense,funkshun())

--------------

@releases = (
    "alpha",
    "beta",
    "gamma",
);

--------------

@froots = qw(
    apple       banana      carambola
    coconut     guava       kumquat
    mandarin    nectarine   peach
    pear        persimmon   plum
);

--------------

# Stat returns list value.
$modification_time = (stat($file))[9];

# SYNTAX ERROR HERE.
$modification_time = stat($file)[9];  # OOPS, FORGOT PARENS

# Find a hex digit.
$hexdigit = ('a','b','c','d','e','f')[$digit-10];

# A "reverse comma operator".
return (pop(@foo),pop(@foo))[0];

# Get multiple values as a slice.
($day, $month, $year) = (localtime)[3,4,5];

########################################################
2:Bits and Pieces/List Values and Arrays/List assignment
########################################################

($a, $b, $c) = (1, 2, 3);

($map{red}, $map{green}, $map{blue}) = (0xff0000, 0x00ff00, 0x0000ff);

--------------

($dev, $ino, undef, undef, $uid, $gid) = stat($file);

--------------

($a, $b, @rest) = split;
my ($a, $b, %rest) = @arg_list;

--------------

() = funkshun();

--------------

$x = ( ($a, $b) = (7,7,7) );    # set $x to 3, not 2
$x = ( ($a, $b) = funk() );     # set $x to funk()'s return count
$x = ( () = funk() );           # also set $x to funk()'s return count

--------------

while (($login, $password) = getpwent) {
    if (crypt($login, $password) eq $password) {
        print "$login has an insecure password!\n";
    }
}

#####################################################
2:Bits and Pieces/List Values and Arrays/Array length
#####################################################

@days + 0;      # implicitly force @days into a scalar context
scalar(@days)   # explicitly force @days into a scalar context

--------------

@whatever = ();
$#whatever = -1;

--------------

scalar(@whatever) == $#whatever + 1;

########################
2:Bits and Pieces/Hashes
########################

%map = ('red',0xff0000,'green',0x00ff00,'blue',0x0000ff);

--------------

%map = ();            # clear the hash first
$map{red}   = 0xff0000;
$map{green} = 0x00ff00;
$map{blue}  = 0x0000ff;

--------------

%map = (
    red   => 0xff0000,
    green => 0x00ff00,
    blue  => 0x0000ff,
);

--------------

$rec = {
    NAME  => 'John Smith',
    RANK  => 'Captain',
    SERNO => '951413',
};

--------------

$field = radio_group(
             NAME      => 'animals',
             VALUES    => ['camel', 'llama', 'ram', 'wolf'],
             DEFAULT   => 'camel',
             LINEBREAK => 'true',
             LABELS    => \%animal_names,
         );

###########################################
2:Bits and Pieces/Typeglobs and Filehandles
###########################################

$fh = *STDOUT;

--------------

$fh = \*STDOUT;

--------------

sub newopen {
    my $path = shift;
    local *FH;          # not my() nor our()
    open(FH, $path) or return undef;
    return *FH;         # not \*FH!
}
$fh = newopen('/etc/passwd');

--------------

*foo = *bar;

--------------

*foo = \$bar;

--------------

local *Here::blue = \$There::green;

###################################################################
2:Bits and Pieces/Input Operators/Command input (backtick) operator
###################################################################

$info = `finger $user`;

--------------

$perl_info  = qx(ps $$);            # that's Perl's $$
$shell_info = qx'ps $$';            # that's the shell's $$

#############################################################
2:Bits and Pieces/Input Operators/Line input (angle) operator
#############################################################

while (defined($_ = <STDIN>)) { print $_; }   # the longest way
while ($_ = <STDIN>) { print; }               # explicitly to $_
while (<STDIN>) { print; }                    # the short way
for (;<STDIN>;) { print; }                    # while loop in disguise
print $_ while defined($_ = <STDIN>);         # long statement modifier
print while $_ = <STDIN>;                     # explicitly to $_
print while <STDIN>;                          # short statement modifier

--------------

while (<FH1> && <FH2>) { ... }          # WRONG: discards both inputs
if (<STDIN>)      { print; }            # WRONG: prints old value of $_
if ($_ = <STDIN>) { print; }            # suboptimal: doesn't test defined
if (defined($_ = <STDIN>)) { print; }   # best

--------------

while (local $_ = <STDIN>) { print; }   # use local $_

--------------

while (my $line = <STDIN>) { print $line; } # now private

--------------

$one_line = <MYFILE>;   # Get first line.
@all_lines = <MYFILE>;  # Get the rest of the lines.

--------------

while (<>) {
    ...                     # code for each line
}

--------------

@ARGV = ('-') unless @ARGV;     # assume STDIN iff empty
while (@ARGV) {
    $ARGV = shift @ARGV;        # shorten @ARGV each time
    if (!open(ARGV, $ARGV)) {
        warn "Can't open $ARGV: $!\n";
        next;
    }
    while (<ARGV>) {
        ...                     # code for each line
    }
}

--------------

# default to README file if no args given
@ARGV = ("README") unless @ARGV;

--------------

while (@ARGV and $ARGV[0] =~ /^-/) {
    $_ = shift;
    last if /^--$/;
    if (/^-D(.*)/) { $debug = $1 }
    if (/^-v/)     { $verbose++  }
    ...             # other switches
}
while (<>) {
    ...             # code for each line
}

--------------

$fh = \*STDIN;
$line = <$fh>;

--------------

open($fh, "<data.txt");
$line = <$fh>;

############################################################
2:Bits and Pieces/Input Operators/Filename globbing operator
############################################################

@files = <*.xml>;

--------------

@files = glob("*.xml");

--------------

while (glob "*.c") {
    chmod 0644, $_;
}

--------------

while (<*.c>) {
    chmod 0644, $_;
}

--------------

chmod 0644, <*.c>;

--------------

($file) = <blurch*>;  # list context

--------------

$file = <blurch*>;    # scalar context

--------------

@files = <$dir/*.[ch]>;         # Works, but avoid.
@files = glob("$dir/*.[ch]");   # Call glob as function.
@files = glob $some_pattern;    # Call glob as operator.

############################
3:Unary and Binary Operators
############################

! $x                # a unary operator
$x * $y             # a binary operator
$x ? $y : $z        # a trinary operator
print $x, $y, $z    # a list operator

--------------

2 + 3 * 4           # yields 14, not 20

--------------

2 * 3 * 4           # means (2 * 3) * 4, left associative
2 ** 3 ** 4         # means 2 ** (3 ** 4), right associative
2 != 3 != 4         # illegal, non-associative

################################################################
3:Unary and Binary Operators/Terms and List Operators (Leftward)
################################################################

chdir $foo    || die;       # (chdir $foo) || die
chdir($foo)   || die;       # (chdir $foo) || die
chdir ($foo)  || die;       # (chdir $foo) || die
chdir +($foo) || die;       # (chdir $foo) || die

--------------

chdir $foo * 20;            # chdir ($foo * 20)
chdir($foo) * 20;           # (chdir $foo) * 20
chdir ($foo) * 20;          # (chdir $foo) * 20
chdir +($foo) * 20;         # chdir ($foo * 20)

--------------

rand 10 * 20;               # rand (10 * 20)
rand(10) * 20;              # (rand 10) * 20
rand (10) * 20;             # (rand 10) * 20
rand +(10) * 20;            # rand (10 * 20)

--------------

@ary = (1, 3, sort 4, 2);
print @ary;         # prints 1324

--------------

# These evaluate exit before doing the print:
print($foo, exit);  # Obviously not what you want.
print $foo, exit;   # Nor this.

# These do the print before evaluating exit:
(print $foo), exit; # This is what you want.
print($foo), exit;  # Or this.
print ($foo), exit; # Or even this.

--------------

print ($foo & 255) + 1, "\n";   # prints ($foo & 255)

###############################################
3:Unary and Binary Operators/The Arrow Operator
###############################################

$aref->[42]                 # an array dereference
$href->{"corned beef"}      # a hash dereference
$sref->(1,2,3)              # a subroutine dereference

--------------

$yogi = Bear->new("Yogi");  # a class method call
$yogi->swipe($picnic);      # an object method call

############################################################
3:Unary and Binary Operators/Autoincrement and Autodecrement
############################################################

print ++($foo = '99');      # prints '100'
print ++($foo = 'a0');      # prints 'a1'
print ++($foo = 'Az');      # prints 'Ba'
print ++($foo = 'zz');      # prints 'aaa'

##############################################
3:Unary and Binary Operators/Binding Operators
##############################################

$string !~ /pattern/
not $string =~ /pattern/

--------------

if ( ($k,$v) = $string =~ m/(\w+)=(\w*)/ ) {
    print "KEY $k VALUE $v\n";
}

#####################################################
3:Unary and Binary Operators/Multiplicative Operators
#####################################################

print '-' x 80;             # print row of dashes

print "\t" x ($tab/8), ' ' x ($tab%8);      # tab over

--------------

@ones = (1) x 80;           # a list of 80 1's
@ones = (5) x @ones;        # set all elements to 5

--------------

@keys = qw(perls before swine);
@hash{@keys} = ("") x @keys;

--------------

$hash{perls}  = "";
$hash{before} = "";
$hash{swine}  = "";

###############################################
3:Unary and Binary Operators/Additive Operators
###############################################

$almost = "Fred" . "Flintstone";    # returns FredFlintstone

--------------

$fullname = "$firstname $lastname";

############################################
3:Unary and Binary Operators/Shift Operators
############################################

1 << 4;     # returns 16
32 >> 4;    # returns 2

################################################################
3:Unary and Binary Operators/Named Unary and File Test Operators
################################################################

sleep 4 | 3;

--------------

(sleep 4) | 3;

--------------

print 4 | 3;

--------------

print (4 | 3);

--------------

next if length < 80;

--------------

next if length() < 80;
next if (length) < 80;
next if 80 > length;
next unless length >= 80;

--------------

while (<>) {
    chomp;
    next unless -f $_;      # ignore "special" files
    ...
}

--------------

next unless -f $file && -T $file;

--------------

print "Can do.\n" if -r $a || -w _ || -x _;

stat($filename);
print "Readable\n" if -r _;
print "Writable\n" if -w _;
print "Executable\n" if -x _;
print "Setuid\n" if -u _;
print "Setgid\n" if -g _;
print "Sticky\n" if -k _;
print "Text\n" if -T _;
print "Binary\n" if -B _;

--------------

next unless -M $file > .5;      # files older than 12 hours
&newfile if -M $file < 0;       # file is newer than process
&mailwarning if int(-A) == 90;  # file ($_) accessed 90 days ago today

--------------

$^T = time;

##############################################
3:Unary and Binary Operators/Bitwise Operators
##############################################

"123.45" & "234.56"

--------------

"020.44"

--------------

"123.45" & 234.56

--------------

123.45 & 234.56

--------------

123 & 234

--------------

if ( "fred" & "\1\2\3\4" ) { ... }

--------------

if ( ("fred" & "\1\2\3\4") =~ /[^\0]/ ) { ... }

######################################################################
3:Unary and Binary Operators/C-style Logical (Short Circuit) Operators
######################################################################

open(FILE, "somefile") || die "Can't open somefile: $!\n";

--------------

$home = $ENV{HOME}
     || $ENV{LOGDIR}
     || (getpwuid($<))[7]
     || die "You're homeless!\n";

--------------

@a = @b || @c;             # This doesn't do the right thing
@a = scalar(@b) || @c;     # because it really means this.
@a = @b ? @b : @c;         # This works fine, though.

###########################################
3:Unary and Binary Operators/Range Operator
###########################################

if (101 .. 200) { print; }  # print 2nd hundred lines
next line if (1 .. /^$/);   # skip header lines
s/^/> / if (/^$/ .. eof()); # quote body

--------------

for (101 .. 200) { print; }            # prints 101102...199200
@foo = @foo[0 .. $#foo];               # an expensive no-op
@foo = @foo[ -5 .. -1];                # slice last 5 items

--------------

@alphabet = ('A' .. 'Z');

--------------

$hexdigit = (0 .. 9, 'a' .. 'f')[$num & 15];

--------------

@z2 = ('01' .. '31');  print $z2[$mday];

--------------

@combos = ('aa' .. 'zz');

--------------

@bigcombos = ('aaaaaa' .. 'zzzzzz');

#################################################
3:Unary and Binary Operators/Conditional Operator
#################################################

$a = $ok ? $b : $c;  # get a scalar
@a = $ok ? @b : @c;  # get an array
$a = $ok ? @b : @c;  # get a count of an array's elements

--------------

printf "I have %d camel%s.\n",
               $n,     $n == 1 ? "" : "s";

--------------

$leapyear =
    $year % 4 == 0
        ? $year % 100 == 0
          ? $year % 400 == 0
            ? 1
            : 0
          : 1
        : 0;

--------------

$leapyear =
    $year % 4
        ? 0
        : $year % 100
          ? 1
          : $year % 400
            ? 0
            : 1;

--------------

$leapyear =
    $year %   4 ? 0 :
    $year % 100 ? 1 :
    $year % 400 ? 0 : 1;

--------------

printf "Yes, I like my %s book!\n",
    $i18n eq "french"   ? "chameau"          :
    $i18n eq "german"   ? "Kamel"            :
    $i18n eq "japanese" ? "\x{99F1}\x{99DD}" :
                          "camel"

--------------

($a_or_b ? $a : $b) = $c;  # sets either $a or $b to equal $c

--------------

$a % 2 ? $a += 10 : $a += 2         # WRONG

--------------

(($a % 2) ? ($a += 10) : $a) += 2

#################################################
3:Unary and Binary Operators/Assignment Operators
#################################################

$var[$a++] += $value;               # $a is incremented once
$var[$a++] = $var[$a++] + $value;   # $a is incremented twice

--------------

($tmp = $global) += $constant;

--------------

$tmp = $global + $constant;

--------------

($a += 2) *= 3;

--------------

$a += 2;
$a *= 3;

--------------

($new = $old) =~ s/foo/bar/g;

--------------

$a = $b = $c = 0;

--------------

while (($key, $value) = each %gloss) { ... }

next unless ($dev, $ino, $mode) = stat $file;

############################################
3:Unary and Binary Operators/Comma Operators
############################################

$a = (1, 3);

--------------

@a = (1, 3);

--------------

atan2(1, 3);

##########################################################
3:Unary and Binary Operators/Logical and, or, not, and xor
##########################################################

unlink "alpha", "beta", "gamma"
        or gripe(), next LINE;

--------------

unlink("alpha", "beta", "gamma")
        || (gripe(), next LINE);

--------------

$xyz = $x || $y || $z;

--------------

$xyz = $x or $y or $z;      # WRONG

--------------

$xyz = ( $x or $y or $z );

##########################################################
3:Unary and Binary Operators/C Operators Missing from Perl
##########################################################

$ref_to_var = \$var;

###############################################
4:Statements and Declarations/Simple Statements
###############################################

$trash->take('out') if $you_love_me;
shutup() unless $you_want_me_to_leave;

--------------

$expression++ while -e "$file$expression";
kiss('me') until $I_die;

--------------

s/java/perl/ for @resumes;
print "field: $_\n" foreach split /:/, $dataline;

--------------

do {
    $line = <STDIN>;
    ...
} until $line eq ".\n";

#################################################
4:Statements and Declarations/Compound Statements
#################################################

unless (open(FOO, $foo))    { die "Can't open $foo: $!" }
if (!open(FOO, $foo))       { die "Can't open $foo: $!" }

die "Can't open $foo: $!"   unless open(FOO, $foo);
die "Can't open $foo: $!"   if !open(FOO, $foo);

open(FOO, $foo)             || die "Can't open $foo: $!";
open FOO, $foo              or die "Can't open $foo: $!";

--------------

chdir $dir                  or die "chdir $dir: $!";
open FOO, $file             or die "open $file: $!";
@lines = <FOO>              or die "$file is empty?";
close FOO                   or die "close $file: $!";

######################################################
4:Statements and Declarations/If and Unless Statements
######################################################

unless ($x == 1) ...

--------------

if ($x != 1) ...

--------------

if (!($x == 1)) ...

--------------

if ((my $color = <STDIN>) =~ /red/i) {
    $value = 0xff0000;
}
elsif ($color =~ /green/i) {
    $value = 0x00ff00;
}
elsif ($color =~ /blue/i) {
    $value = 0x0000ff;
}
else {
    warn "unknown RGB component `$color', using black instead\n";
    $value = 0x000000;
}

########################################################################
4:Statements and Declarations/Loop Statements/While and Until Statements
########################################################################

while (my $line = <STDIN>) {
    $line = lc $line;
}
continue {
    print $line;   # still visible
}
# $line now out of scope here

#######################################################
4:Statements and Declarations/Loop Statements/For Loops
#######################################################

LABEL:
  for (my $i = 1; $i <= 10; $i++) {
      ...
  }

--------------

{
    my $i = 1;
  LABEL:
    while ($i <= 10) {
        ...
    }
    continue {
        $i++;
    }
}

--------------

for ($i = 0, $bit = 0; $i < 32; $i++, $bit <<= 1) {
    print "Bit $i is set\n" if $mask & $bit;
}
# the values in $i and $bit persist past the loop

--------------

for (my ($i, $bit) = (0, 1); $i < 32; $i++, $bit <<= 1) {
    print "Bit $i is set\n" if $mask & $bit;
}
# loop's versions of $i and $bit now out of scope

--------------

$on_a_tty = -t STDIN && -t STDOUT;
sub prompt { print "yes? " if $on_a_tty }
for ( prompt(); <STDIN>; prompt() ) {
    # do something
}

--------------

for (;;) {
    ...
}

--------------

while (1) {
    ...
}

###########################################################
4:Statements and Declarations/Loop Statements/Foreach Loops
###########################################################

$sum = 0; foreach $value (@array) { $sum += $value }

for $count (10,9,8,7,6,5,4,3,2,1,'BOOM') {  # do a countdown
    print "$count\n"; sleep(1);
}

for (reverse 'BOOM', 1 .. 10) {             # same thing
    print "$_\n"; sleep(1);
}

for $field (split /:/, $data) {             # any LIST expression
    print "Field contains: `$field'\n";
}

foreach $key (sort keys %hash) {
    print "$key => $hash{$key}\n";
}

--------------

foreach $pay (@salaries) {               # grant 8% raises
    $pay *= 1.08;
}

for (@christmas, @easter) {              # change menu
    s/ham/turkey/;
}
s/ham/turkey/ for @christmas, @easter;   # same thing

for ($scalar, @array, values %hash) {
    s/^\s+//;                            # strip leading  whitespace
    s/\s+$//;                            # strip trailing whitespace
}

--------------

for my  $i    (1 .. 10) { ... }         # $i always lexical
for our $Tick (1 .. 10) { ... }         # $Tick always global

--------------

for ($i = 0; $i < @ary1; $i++) {
    for ($j = 0; $j < @ary2; $j++) {
        if ($ary1[$i] > $ary2[$j]) {
            last;         # Can't go to outer loop. :-(
        }
        $ary1[$i] += $ary2[$j];
    }
    # this is where that last takes me
}

--------------

WID: foreach $this (@ary1) {
    JET: foreach $that (@ary2) {
        next WID if $this > $that;
        $this += $that;
    }
}

##########################################################
4:Statements and Declarations/Loop Statements/Loop Control
##########################################################

next LINE if /^#/;      # discard comments

--------------

LINE: while (<STDIN>) {
    last LINE if /^$/;      # exit when done with mail header
    ...
}

--------------

LINE: while (<STDIN>) {
    next LINE if /^#/;      # skip comments
    next LINE if /^$/;      # skip blank lines
    ...
} continue {
    $count++;
}

--------------

while (<>) {
    chomp;
    if (s/\\$//) {
        $_ .= <>;
        redo unless eof;    # don't read past each file's eof
    }
    # now process $_
}

--------------

LINE: while (defined($line = <ARGV>)) {
    chomp($line);
    if ($line =~ s/\\$//) {
        $line .= <ARGV>;
        redo LINE unless eof(ARGV);
    }
    # now process $line
}

--------------

ARG: while (@ARGV && $ARGV[0] =~ s/^-(?=.)//) {
    OPT: for (shift @ARGV) {
            m/^$/       && do {                             next ARG; };
            m/^-$/      && do {                             last ARG; };
            s/^d//      && do { $Debug_Level++;             redo OPT; };
            s/^l//      && do { $Generate_Listing++;        redo OPT; };
            s/^i(.*)//  && do { $In_Place = $1 || ".bak";   next ARG; };
            say_usage("Unknown option: $_");
    }
}

--------------

open FILE, $file
     or warn "Can't open $file: $!\n", next FILE;   # WRONG

--------------

open FILE, $file
     or warn("Can't open $file: $!\n"), next FILE;   # okay

--------------

unless (open FILE, $file) {
     warn "Can't open $file: $!\n";
     next FILE;
}

#########################################
4:Statements and Declarations/Bare Blocks
#########################################

if (/pattern/) {{
    last if /alpha/;
    last if /beta/;
    last if /gamma/;
    # do something here only if still in if()
}}

--------------

do {{
    next if $x == $y;
    # do something here
}} until $x++ > $z;

--------------

{
    do {
        last if $x = $y ** 2;
        # do something here
    } while $x++ <= $z;
}

--------------

DO_LAST: {
            do {
DO_NEXT:          {
                    next DO_NEXT if $x == $y;
                    last DO_LAST if $x =  $y ** 2;
                    # do something here
                  }
            } while $x++ <= $z;
         }

--------------

for (;;) {
    next if $x == $y;
    last if $x =  $y ** 2;
    # do something here
    last unless $x++ <= $z;
}

#########################################################
4:Statements and Declarations/Bare Blocks/Case Structures
#########################################################

SWITCH: {
    if (/^abc/) { $abc = 1; last SWITCH; }
    if (/^def/) { $def = 1; last SWITCH; }
    if (/^xyz/) { $xyz = 1; last SWITCH; }
    $nothing = 1;
}

--------------

SWITCH: {
    /^abc/      && do { $abc = 1; last SWITCH; };
    /^def/      && do { $def = 1; last SWITCH; };
    /^xyz/      && do { $xyz = 1; last SWITCH; };
    $nothing = 1;
}

--------------

SWITCH: {
    /^abc/      && do {
                        $abc = 1;
                        last SWITCH;
                   };
    /^def/      && do {
                        $def = 1;
                        last SWITCH;
                   };
    /^xyz/      && do {
                        $xyz = 1;
                        last SWITCH;
                    };
    $nothing = 1;
}

--------------

if    (/^abc/) { $abc = 1 }
elsif (/^def/) { $def = 1 }
elsif (/^xyz/) { $xyz = 1 }
else           { $nothing = 1 }

--------------

for ($very_nasty_long_name[$i++][$j++]->method()) {
    /this pattern/      and do { push @flags, '-e'; last; };
    /that one/          and do { push @flags, '-h'; last; };
    /something else/    and do {                    last; };
    die "unknown value: `$_'";
}

--------------

for ($user_color_preference) {
    $value = /red/      ?   0xFF0000  :
             /green/    ?   0x00FF00  :
             /blue/     ?   0x0000FF  :
                            0x000000  ;   # black if all fail
}

--------------

%color_map = (
    azure       => 0xF0FFFF,
    chartreuse  => 0x7FFF00,
    lavender    => 0xE6E6FA,
    magenta     => 0xFF00FF,
    turquoise   => 0x40E0D0,
);

--------------

$value = $color_map{ lc $user_color_preference } || 0x000000;

##################################
4:Statements and Declarations/Goto
##################################

goto(("FOO", "BAR", "GLARCH")[$i]);         # hope 0 <= i < 3

@loop_label = qw/FOO BAR GLARCH/;
goto $loop_label[rand @loop_label];         # random teleport

#################################################
4:Statements and Declarations/Global Declarations
#################################################

sub count (@);       # Compiler now knows how to call count().
my $x;               # Compiler now knows about lexical variable.
$x = count(3,2,1);   # Compiler can validate function call.
sub count (@) { @_ } # Compiler now knows what count() means.

--------------

sub myname;
$me = myname $0             or die "can't get myname";

--------------

sub myname ($);
$me = myname $0             || die "can't get myname";

##############################################################################
4:Statements and Declarations/Scoped Declarations/Scoped Variable Declarations
##############################################################################

my $nose;
our $House;
local $TV_channel;

--------------

my ($nose, @eyes, %teeth);
our ($House, @Autos, %Kids);
local (*Spouse, $phone{HOME});

--------------

my ($foo) = <STDIN>;
my @array = <STDIN>;

--------------

my $foo = <STDIN>;

--------------

my $foo, $bar = 1;              # WRONG

--------------

my $foo;
$bar = 1;

--------------

sub check_warehouse {
    for my $widget (our @Current_Inventory) {
        print "I have a $widget in stock today.\n";
    }
}

###################################################################################
4:Statements and Declarations/Scoped Declarations/Lexically Scoped Variables: C<my>
###################################################################################

my $name = "fred";
my @stuff = ("car", "house", "club");
my ($vehicle, $home, $tool) = @stuff;

--------------

{
    my $state = 0;

    sub on     { $state = 1 }
    sub off    { $state = 0 }
    sub toggle { $state = !$state }
}

--------------

my $x = $x;

##############################################################################################
4:Statements and Declarations/Scoped Declarations/Lexically Scoped Global Declarations: C<our>
##############################################################################################

sub check_warehouse {
    our @Current_Inventory;
    my  $widget;
    foreach $widget (@Current_Inventory) {
        print "I have a $widget in stock today.\n";
    }
}

--------------

our $PROGRAM_NAME = "waiter";
{
    our $PROGRAM_NAME = "server";
    # Code called here sees "server".
    ...
}
# Code executed below still sees "server".

--------------

my $i = 10;
{
    my $i = 99;
    ...
}
# Code compiled below sees outer variable.

local $PROGRAM_NAME = "waiter";
{
    local $PROGRAM_NAME = "server";
    # Code called here sees "server".
    ...
}
# Code executed below sees "waiter" again.

--------------

{
    local our @Current_Inventory = qw(bananas);
    check_warehouse();  # no, we haven't no bananas :-)
}

########################################################################################
4:Statements and Declarations/Scoped Declarations/Dynamically Scoped Variables: C<local>
########################################################################################

{
    local $var = $newvalue;
    some_func();
    ...
}

--------------

{
    $oldvalue = $var;
    $var = $newvalue;
    some_func();
    ...
}
continue {
    $var = $oldvalue;
}

--------------

# WARNING: Changes are temporary to this dynamic scope.
local $Some_Global = $Some_Global;

#####################################
4:Statements and Declarations/Pragmas
#####################################

use warnings;
use strict;
use integer;
use bytes;
use constant pi => ( 4 * atan2(1,1) );

##########################################################
4:Statements and Declarations/Pragmas/Controlling Warnings
##########################################################

use warnings;       # Enable warnings from here till end of file.
...
{
    no warnings;    # Disable warnings through end of block.
    ...
}
# Warnings are automatically enabled again here.

--------------

{
    local $^W = 0;
    ...
}

####################################################################
4:Statements and Declarations/Pragmas/Controlling the Use of Globals
####################################################################

use strict 'vars';

--------------

no strict 'vars'

##################
5:Pattern Matching
##################

match( $string, $pattern );
subst( $string, $pattern, $replacement );

##################################################
5:Pattern Matching/The Regular Expression Bestiary
##################################################

/Frodo/

--------------

/Frodo|Pippin|Merry|Sam/

--------------

/(Frodo|Drogo|Bilbo) Baggins/

--------------

/(Frod|Drog|Bilb)o Baggins/

--------------

/(bar){3}/

#############################################
5:Pattern Matching/Pattern Matching Operators
#############################################

$foo = "bar";
/$foo$/;

--------------

/bar$/;

--------------

print "matches" if $somestring =~ $somepattern;

--------------

print "matches" if $somestring =~ m/$somepattern/;

--------------

$haystack =~ m/needle/                # match a simple pattern
$haystack =~  /needle/                # same thing

$italiano =~ s/butter/olive oil/      # a healthy substitution

$rotate13 =~ tr/a-zA-Z/n-za-mN-ZA-M/  # easy encryption (to break)

--------------

/new life/ and              # search in $_ and (if found)
    /new civilizations/     #    boldly search $_ again

s/sugar/aspartame/          # substitute a substitute into $_

tr/ATCG/TAGC/               # complement the DNA stranded in $_

--------------

"onshore" =~ s/on/off/;      # WRONG: compile-time error

--------------

if ((lc $magic_hat->fetch_contents->as_string) =~ /rabbit/) {
    print "Nyaa, what's up doc?\n";
}
else {
    print "That trick never works!\n";
}

--------------

if ($song !~ /words/) {
    print qq/"$song" appears to be a song without words.\n/;
}

--------------

$path =~ s#/tmp#/var/tmp/scratch#;

if ($dir =~ m[/bin]) {
    print "No binary directories please.\n";
}

--------------

s(egg)<larva>;
s{larva}{pupa};
s[pupa]/imago/;

--------------

s (egg)   <larva>;
s {larva} {pupa};
s [pupa]  /imago/;

--------------

"hot cross buns" =~ /cross/;
print "Matched: <$`> $& <$'>\n";    # Matched: <hot > cross < buns>
print "Left:    <$`>\n";            # Left:    <hot >
print "Match:   <$&>\n";            # Match:   <cross>
print "Right:   <$'>\n";            # Right:   < buns>

--------------

$_ = "Bilbo Baggins's birthday is September 22";
/(.*)'s birthday is (.*)/;
print "Person: $1\n";
print "Date: $2\n";

###############################################################
5:Pattern Matching/Pattern Matching Operators/Pattern Modifiers
###############################################################

m/\w+:(\s+\w+)\s*\d+/;       # A word, colon, space, word, space, digits.

m/\w+: (\s+ \w+) \s* \d+/x;  # A word, colon, space, word, space, digits.

m{
    \w+:                     # Match a word and a colon.
    (                        # (begin group)
         \s+                 # Match one or more spaces.
         \w+                 # Match another word.
    )                        # (end group)
    \s*                      # Match zero or more spaces.
    \d+                      # Match some digits
}x;

--------------

# Find duplicate words in paragraphs, possibly spanning line boundaries.
#   Use /x for space and comments, /i to match the both `is'
#   in "Is is this ok?", and use /g to find all dups.
$/ = "";        # paragrep mode
while (<>) {
    while ( m{
                \b            # start at a word boundary
                (\w\S+)       # find a wordish chunk
                (
                    \s+       # separated by some whitespace
                    \1        # and that chunk again
                ) +           # repeat ad lib
                \b            # until another word boundary
             }xig
         )
    {
        print "dup word '$1' at paragraph $.\n";
    }
}

#########################################################################
5:Pattern Matching/Pattern Matching Operators/The m// Operator (Matching)
#########################################################################

if ($shire =~ m/Baggins/) { ... }  # search for Baggins in $shire
if ($shire =~ /Baggins/)  { ... }  # search for Baggins in $shire

if ( m#Baggins# )         { ... }  # search right here in $_
if ( /Baggins/ )          { ... }  # search right here in $_

--------------

if (($key,$value) = /(\w+): (.*)/) { ... }

--------------

if (@perls = $paragraph =~ /perl/gi) {
    printf "Perl mentioned %d times.\n", scalar @perls;
}

--------------

$string = "password=xyzzy verbose=9 score=0";

--------------

%hash = (password => "xyzzy", verbose => 9, score => 0);

--------------

%hash = $string =~ /(\w+)=(\w+)/g;

--------------

open DICT, "/usr/dict/words" or die "Can't open words: $!\n";
while (<DICT>) {
    $first = $1 if ?(^neur.*)?;
    $last  = $1 if /(^neur.*)/;
}
print $first,"\n";          # prints "neurad"
print $last,"\n";           # prints "neurypnology"

##############################################################################
5:Pattern Matching/Pattern Matching Operators/The s/// Operator (Substitution)
##############################################################################

$lotr = $hobbit;           # Just copy The Hobbit
$lotr =~ s/Bilbo/Frodo/g;  #   and write a sequel the easy way.

--------------

if ($lotr =~ s/Bilbo/Frodo/) { print "Successfully wrote sequel." }
$change_count = $lotr =~ s/Bilbo/Frodo/g;

--------------

s/revision|version|release/\u$&/g;  # Use | to mean "or" in a pattern

--------------

s/version ([0-9.]+)/the $Names{$1} release/g;

--------------

s{
    version
    \s+
    (
        [0-9.]+
    )
}{
    $Names{$1}
        ? "the $Names{$1} release"
        : $&
}xge;

###########################################################################################################
5:Pattern Matching/Pattern Matching Operators/The s/// Operator (Substitution)/Modifying strings en passant
###########################################################################################################

$lotr = $hobbit;
$lotr =~ s/Bilbo/Frodo/g;

--------------

($lotr = $hobbit) =~ s/Bilbo/Frodo/g;

--------------

for (@chapters) { s/Bilbo/Frodo/g }  # Do substitutions chapter by chapter.
s/Bilbo/Frodo/g for @chapters;       # Same thing.

--------------

@oldhues = ('bluebird', 'bluegrass',  'bluefish', 'the blues');
for (@newhues = @oldhues) { s/blue/red/ }
print "@newhues\n";  # prints: redbird redgrass redfish the reds

--------------

for ($string) {
    s/^\s+//;       # discard leading whitespace
    s/\s+$//;       # discard trailing whitespace
    s/\s+/ /g;      # collapse internal whitespace
}

--------------

$string = join(" ", split " ", $string);

--------------

for ($newshow = $oldshow) {
    s/Fred/Homer/g;
    s/Wilma/Marge/g;
    s/Pebbles/Lisa/g;
    s/Dino/Bart/g;
}

##################################################################################################################################
5:Pattern Matching/Pattern Matching Operators/The s/// Operator (Substitution)/When a Global Substitution Just Isn't Global Enough
##################################################################################################################################

# put commas in the right places in an integer
1 while s/(\d)(\d\d\d)(?!\d)/$1,$2/;

# expand tabs to 8-column spacing
1 while s/\t+/' ' x (length($&)*8 - length($`)%8)/e;

# remove (nested (even deeply nested (like this))) comments
1 while s/\([^()]*\)//g;

# remove duplicate words (and triplicate (and quadruplicate...))
1 while s/\b(\w+) \1\b/$1/gi;

##################################################################################
5:Pattern Matching/Pattern Matching Operators/The tr/// Operator (Transliteration)
##################################################################################

$message =~ tr/A-Za-z/N-ZA-Mn-za-m/;    # rot13 encryption.

--------------

tr/aeiou/!/;                 # change any vowel into a !
tr{/\\\r\n\b\f. }{_};        # change strange chars into an underscore

tr/A-Z/a-z/ for @ARGV;       # canonicalize to lower case ASCII

$count = ($para =~ tr/\n//); # count the newlines in $para
$count = tr/0-9//;           # count the digits in $_

$word =~ tr/a-zA-Z//s;       # bookkeeper -> bokeper

tr/@$%*//d;                  # delete any of those
tr#A-Za-z0-9+/##cd;          # remove non-base64 chars

# change en passant
($HOST = $host) =~ tr/a-z/A-Z/;

$pathname =~ tr/a-zA-Z/_/cs; # change non-(ASCII)alphas to single underbar

tr [\200-\377]
   [\000-\177];              # strip 8th bit, bytewise

--------------

tr/AAA/XYZ/

--------------

$count = eval "tr/$oldlist/$newlist/";
die if $@;  # propagates exception from illegal eval contents

#################################################
5:Pattern Matching/Metacharacters and Metasymbols
#################################################

 \ | ( ) [ { ^ $ * + ? .

######################################################################
5:Pattern Matching/Metacharacters and Metasymbols/Wildcard Metasymbols
######################################################################

if ($pathname =~ /\.(.)\z/s) {
    print "Ends in $1\n";
}

--------------

use utf8;
use charnames qw/:full/;
$BWV[887] = "G\N{MUSIC SHARP SIGN} minor";
($note, $black, $mode) = $BWV[887] =~ /^([A-G])(.)\s+(\S+)/;
print "That's lookin' sharp!\n" if $black eq chr(9839);

###########################################################################
5:Pattern Matching/Character Classes/Classic Perl Character Class Shortcuts
###########################################################################

if ($var =~ /\D/)        { warn "contains non-digit" }
if ($var =~ /[^\w\s.]/)  { warn "contains non-(word, space, dot)" }

#######################################################
5:Pattern Matching/Character Classes/Unicode Properties
#######################################################

if ($var =~ /^\p{IsAlpha}+$/)      { print "all alphabetic" }
if ($var =~ s/[\p{Zl}\p{Zp}]/\n/g) { print "fixed newline wannabes" }

--------------

perl -MConfig -le 'print $Config{privlib}'

################################################################################
5:Pattern Matching/Character Classes/Unicode Properties/Unicode block properties
################################################################################

print "It's Greek to me!\n" if chr(931) =~ /\p{InGreek}/;

##############################################################################################
5:Pattern Matching/Character Classes/Unicode Properties/Defining your own character properties
##############################################################################################

sub InKana {
    return <<'END';
3040    309F
30A0    30FF
END
}

--------------

sub InKana {
    return <<'END';
+utf8::InHiragana
+utf8::InKatakana
END
}

--------------

sub IsKana {
    return <<'END';
+utf8::InHiragana
+utf8::InKatakana
-utf8::IsCn
END
}

--------------

sub IsNotKana {
    return <<'END';
!utf8::InHiragana
-utf8::InKatakana
+utf8::IsCn
END
}

##################################################################
5:Pattern Matching/Character Classes/POSIX-Style Character Classes
##################################################################

42 =~ /^[:digit:]$/         # WRONG

--------------

42 =~ /^[[:digit:]]+$/

##############################
5:Pattern Matching/Quantifiers
##############################

"exasperate" =~ /e(.*)e/    #  $1 now "xasperat"

--------------

"exasperate" =~ /e(.*?)e/   #  $1 now "xasp"

--------------

"exasperate" =~ /.*e(.*?)e/   #  $1 now "rat"

######################################################################
5:Pattern Matching/Positions/Beginnings: The C<\A> and C<^> Assertions
######################################################################

/\Abar/      # Matches "bar" and "barstool"
/^bar/       # Matches "bar" and "barstool"
/^bar/m      # Matches "bar" and "barstool" and "sand\nbar"

--------------

s/^\s+//gm;             # Trim leading whitespace on each line
$total++ while /^./mg;  # Count nonblank lines

###########################################################################
5:Pattern Matching/Positions/Endings: The C<\z>, C<\Z>, and C<$> Assertions
###########################################################################

/bot\z/      # Matches "robot"
/bot\Z/      # Matches "robot" and "abbot\n"
/bot$/       # Matches "robot" and "abbot\n"
/bot$/m      # Matches "robot" and "abbot\n" and "robot\nrules"

/^robot$/    # Matches "robot" and "robot\n"
/^robot$/m   # Matches "robot" and "robot\n" and "this\nrobot\n"
/\Arobot\Z/  # Matches "robot" and "robot\n"
/\Arobot\z/  # Matches only "robot" -- but why didn't you use eq?

--------------

s/\s*$//gm;   # Trim trailing whitespace on each line in paragraph

while (/^([^:]+):\s*(.*)/gm ) {  # get mail header
    $headers{$1} = $2;
}

#######################################################################
5:Pattern Matching/Positions/Boundaries: The C<\b> and C<\B> Assertions
#######################################################################

/\bis\b/   # matches "what it is" and "that is it"
/\Bis\B/   # matches "thistle" and "artist"
/\bis\B/   # matches "istanbul" and "so--isn't that butter?"
/\Bis\b/   # matches "confutatis" and "metropolis near you"

#################################################
5:Pattern Matching/Positions/Progressive Matching
#################################################

$burglar = "Bilbo Baggins";
while ($burglar =~ /b/gi) {
    printf "Found a B at %d\n", pos($burglar)-1;
}

$burglar = "Bilbo Baggins";
while ($burglar =~ /b/gci) {        # ADD /c
    printf "Found a B at %d\n", pos($burglar)-1;
}
while ($burglar =~ /i/gi) {
    printf "Found an I at %d\n", pos($burglar)-1;
}

####################################################################
5:Pattern Matching/Positions/Where You Left Off: The C<\G> Assertion
####################################################################

($recipe = <<'DISH') =~ s/^\s+//gm;
    Preheat oven to 451 deg. fahrenheit.
    Mix 1 ml. dilithium with 3 oz. NaCl and
    stir in 4 anchovies.  Glaze with 1 g.
    mercury.  Heat for 4 hours and let cool
    for 3 seconds.  Serves 10 aliens.
DISH

$recipe =~ /\d+ /g;
$recipe =~ /\G(\w+)/;           # $1 is now "deg"
$recipe =~ /\d+ /g;
$recipe =~ /\G(\w+)/;           # $1 is now "ml"
$recipe =~ /\d+ /g;
$recipe =~ /\G(\w+)/;           # $1 is now "oz"

--------------

pos($recipe) = 0;                 # Just to be safe, reset \G to 0
while ( $recipe =~ /(\d+) /g ) {
    my $amount = $1;
    if ($recipe =~ / \G (\w{0,3}) \. \s+ (\w+) /x) {  # abbrev. + word
        print "$amount $1 of $2\n";
    } else {
        $recipe =~ / \G (\w+) /x;                     # just a word
        print "$amount $1\n";
    }
}

#####################################################
5:Pattern Matching/Capturing and Clustering/Capturing
#####################################################

/(\d)(\d)/  # Match two digits, capturing them into $1 and $2
/(\d+)/     # Match one or more digits, capturing them all into $1
/(\d)+/     # Match a digit one or more times, capturing the last into $1

--------------

/\b(\w+) \1\b/i

--------------

From: gnat@perl.com
To: camelot@oreilly.com
Date: Mon, 17 Jul 2000 09:00:00 -1000
Subject: Eye of the needle

--------------

while (<>) {
    /^(.*?): (.*)$/;    # Pre-colon text into $1, post-colon into $2
    $fields{$1} = $2;
}

--------------

s/^(\S+) (\S+)/$2 $1/;  # Swap first two words

--------------

/^((\w+) (\w+))$/

--------------

($first, $last)        =  /^(\w+) (\w+)$/;
($full, $first, $last) =  /^((\w+) (\w+))$/;

--------------

%fields = /^(.*?): (.*)$/gm;

--------------

$_ = "Speak, <EM>friend</EM>, and enter.";
m[ (<.*?>) (.*?) (</.*?>) ]x;     # A tag, then chars, then an end tag
print "prematch: $`\n";           # Speak,
print "match: $&\n";              # <EM>friend</EM>
print "postmatch: $'\n";          # , and enter.
print "lastmatch: $+\n";          # </EM>

--------------

#!/usr/bin/perl
$alphabet = "abcdefghijklmnopqrstuvwxyz";
$alphabet =~ /(hi).*(stu)/;

print "The entire match began at $-[0] and ended at $+[0]\n";
print "The first  match began at $-[1] and ended at $+[1]\n";
print "The second match began at $-[2] and ended at $+[2]\n";

--------------

/\(e.g. .*?\)/

######################################################
5:Pattern Matching/Capturing and Clustering/Clustering
######################################################

@fields = split(/\b(?:a|b|c)\b/)

--------------

@fields = split(/\b(a|b|c)\b/)

########################################################################
5:Pattern Matching/Capturing and Clustering/Cloistered Pattern Modifiers
########################################################################

/Harry (?i:s) Truman/

--------------

/Harry (?x: [A-Z] \.? )? Truman/

--------------

/Harry (?ix: [A-Z] \.? )? Truman/

--------------

/Harry (?x-i: [A-Z] \.? )? Truman/i

--------------

/(?i)foo/            # Equivalent to /foo/i
/foo((?-i)bar)/i     # "bar" must be lower case
/foo((?x-i) bar)/    # Enables /x and disables /i for "bar"

##############################
5:Pattern Matching/Alternation
##############################

/Gandalf|Saruman|Radagast/

--------------

/prob|n|r|l|ate/    # Match prob, n, r, l, or ate
/pro(b|n|r|l)ate/   # Match probate, pronate, prorate, or prolate
/pro(?:b|n|r|l)ate/ # Match probate, pronate, prorate, or prolate

--------------

/(Sam|Samwise)/

--------------

"'Sam I am,' said Samwise" =~ /(Samwise|Sam)/;   # $1 eq "Sam"

--------------

"'Sam I am,' said Samwise" =~ /.*(Samwise|Sam)/; # $1 eq "Samwise"

--------------

"'Sam I am,' said Samwise" =~ /(Samwise|Sam)$/;  # $1 eq "Samwise"

--------------

#!/usr/bin/perl
while (<>) {
    print if /^__DATA__|^__END__/;
}

--------------

/^cat|dog|cow$/

--------------

/^(cat|dog|cow)$/

--------------

/^cat$|^dog$|^cow$/

--------------

/com(pound|)/;      # Matches "compound" or "com"
/com(pound(s|)|)/;  # Matches "compounds", "compound", or "com"

--------------

/com(pound)?/;      # Matches "compound" or "com"
/com(pound(s?))?/;  # Matches "compounds", "compound", or "com"
/com(pounds?)?/;    # Same, but doesn't use $2

##############################################################
5:Pattern Matching/Staying in Control/Letting Perl Do the Work
##############################################################

/Gandalf|Saruman|Radagast/

--------------

/Gandalf/ || /Saruman/ || /Radagast/

--------------

while (<CONF>) {
    next if /^#/;
    next if /^\s*(#|$)/;
    chomp;
    munchabunch($_);
}

--------------

warn "has nondigits"        if     /\D/;
warn "not a natural number" unless /^\d+$/;             # rejects -3
warn "not an integer"       unless /^-?\d+$/;           # rejects +3
warn "not an integer"       unless /^[+-]?\d+$/;
warn "not a decimal number" unless /^-?\d+\.?\d*$/;     # rejects .2
warn "not a decimal number" unless /^-?(?:\d+(?:\.\d*)?|\.\d+)$/;
warn "not a C float"
       unless /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;

############################################################
5:Pattern Matching/Staying in Control/Variable Interpolation
############################################################

if ($num =~ /^[-+]?\d+\.?\d*$/) { ... }

--------------

$sign = '[-+]?';
$digits = '\d+';
$decimal = '\.?';
$more_digits = '\d*';
$number = "$sign$digits$decimal$more_digits";
...
if ($num =~ /^$number$/o) { ... }

--------------

chomp($answer = <STDIN>);
if    ("SEND"  =~ /^\Q$answer/i) { print "Action is send\n"  }
elsif ("STOP"  =~ /^\Q$answer/i) { print "Action is stop\n"  }
elsif ("ABORT" =~ /^\Q$answer/i) { print "Action is abort\n" }
elsif ("LIST"  =~ /^\Q$answer/i) { print "Action is list\n"  }
elsif ("EDIT"  =~ /^\Q$answer/i) { print "Action is edit\n"  }

####################################################################################
5:Pattern Matching/Staying in Control/Variable Interpolation/When backslashes happen
####################################################################################

($col1, $col2) = /(.*?) \t+ (.*?)/x;

--------------

$colsep = "\t+";                         # (double quotes)
($col1, $col2) = /(.*?) $colsep (.*?)/x;

--------------

$var = '\U';
/${var}frodo/;

--------------

$hobbit = 'Frodo';
$var = '$hobbit';           # (single quotes)
/$var/;                     # means m'$hobbit', not m'Frodo'.

--------------

#!/usr/bin/perl
$pattern = shift;
while (<>) {
    print if /$pattern/o;
}

--------------

% pgrep '\t\d' *.c

--------------

% pgrep '(?i)ring' LotR*.pod

##########################################################################################
5:Pattern Matching/Staying in Control/Variable Interpolation/The qr// quote regex operator
##########################################################################################

print if /$pattern/o;

--------------

foreach $item (@data) {
    foreach $patstr (@patterns) {
        if ($item =~ /$patstr/) { ... }
    }
}

--------------

$regex = qr/my.STRING/is;
s/$regex/something else/;

--------------

s/my.STRING/something else/is;

--------------

@regexes = ();
foreach $patstr (@patterns) {
    push @regexes, qr/$patstr/;
}

--------------

@regexes = map { qr/$patstr/ } @patterns;

--------------

foreach $item (@data) {
    foreach $re (@regexes) {
        if ($item =~ /$re/) { ... }
    }
}

--------------

$regex = qr/$pattern/;
$string =~ /foo${regex}bar/;   # interpolate into larger patterns

--------------

$re = qr/my.STRING/is;
print $re;                  # prints (?si-xm:my.STRING)

--------------

$re = qr/$pat/is;                      # might escape and eat you
$re = eval { qr/$pat/is } || warn ...  # caught it in an outer cage

########################################################
5:Pattern Matching/Staying in Control/The Regex Compiler
########################################################

#!/usr/bin/perl
use re "debug";
"Smeagol" =~ /^Sm(.*)g[aeiou]l$/;

##########################################################################
5:Pattern Matching/Staying in Control/The Little Engine that /Could(n't)?/
##########################################################################

/x*y*/

--------------

$a = 'nobody';
$b = 'bodysnatcher';
if ("$a $b" =~ /^(\w+)(\w+) \2(\w+)$/) {
    print "$2 overlaps in $1-$2-$3\n";
}

#######################################################
5:Pattern Matching/Fancy Patterns/Lookaround Assertions
#######################################################

$_ = "Paris in THE THE THE THE spring.";

# remove duplicate words (and triplicate (and quadruplicate...))
1 while s/\b(\w+) \1\b/$1/gi;

--------------

s/ \b(\w+) \s (?= \1\b ) //gxi;

--------------

s/ \b(\w+) \s (?= \1\b (?! '\w))//xgi;

--------------

s/ \b(\w+) \s (?= \1\b (?! '\w | \s particular))//gix;

--------------

s/ \b(\w+) \s (?= \1\b (?! '\w | \s particular | \s nation))//igx;

--------------

@thatthat = qw(particular nation);
local $" = '|';
s/ \b(\w+) \s (?= \1\b (?! '\w | \s (?: @thatthat )))//xig;

--------------

s/ \b(\w+) \s (?= \1\b (?! '\w | (?<= that) \s (?: @thatthat )))//ixg;

--------------

s/(?<!c)ei/ie/g

##############################################################
5:Pattern Matching/Fancy Patterns/Non-Backtracking Subpatterns
##############################################################

$_ = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab";
/a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*[b]/;

--------------

/(?>a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*)[b]/;

--------------

#!/usr/bin/perl -00p
while ( /( (.+) ( (?<=\\) \n .* )+ ) /gx) {
    print "GOT $.: $1\n\n";
}

--------------

(.+(?:(?<=\\)\n.*)+)

--------------

((?>.+)(?:(?<=\\)\n.*)+)

##########################################################################
5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Generated patterns
##########################################################################

#!/usr/bin/perl
$vowels = 'aeiouy';
$cons   = 'cbdfghjklmnpqrstvwxzy';
%map = (C => $cons, V => $vowels);  # init map for C and V

for $class ($vowels, $cons) {       # now for each type
    for (split //, $class) {        # get each letter of that type
        $map{$_} .= $class;         # and map the letter back to the type
    }
}

for $char (split //, shift) {       # for each letter in template word
    $pat .= "[$map{$char}]";        # add appropriate character class
}

$re = qr/^${pat}$/i;                # compile the pattern
print "REGEX is $re\n";             # debugging output
@ARGV = ('/usr/dict/words')         # pick a default dictionary
    if -t && !@ARGV;

while (<>) {                        # and now blaze through the input
    print if /$re/;                 # printing any line that matches
}

################################################################################
5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Substitution evaluations
################################################################################

s/(\d+)/$1 * 2/;     # Replaces "42" with "42 * 2"
s/(\d+)/$1 * 2/e;    # Replaces "42" with "84"

--------------

$_ = "Preheat oven to 233C.\n";
s/\b(\d+\.?\d*)C\b/int($1 * 1.8 + 32) . "F"/e;   # convert to 451F

--------------

% perl -pi -e 's/^(\d+)(?=:)/100 + $1/e' filename

--------------

s/(\$\w+)/$1/eeg;       # Interpolate most scalars' values

--------------

$_ = "I have 4 + 19 dollars and 8/2 cents.\n";
s{ (
        \d+ \s*         # find an integer
        [+*/-]          # and an arithmetical operator
        \s* \d+         # and another integer
   )
}{ $1 }eegx;            # then expand $1 and run that code
print;                  # "I have 23 dollars and 4 cents."

##################################################################################
5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Match-time code evaluation
##################################################################################

"glyph" =~ /.+ (?{ print "hi" }) ./x;  # Prints "hi" twice.

--------------

$_ = 'lothlorien';
m/  (?{ $i = 0 })                    # Set $i to 0
    (.    (?{ $i++ })    )*          # Update $i, even after backtracking
    lori                             # Forces a backtrack
 /x;

--------------

$_ = 'lothlorien';
m/  (?{ $i = 0 })
    (. (?{ local $i = $i + 1; }) )*  # Update $i, backtracking-safe.
    lori
    (?{ $result = $i })              # Copy to non-localized location.
 /x;

--------------

"glyph" =~ /.+(?(?{ $foo{bar} gt "symbol" }).|signet)./;

--------------

"glyph" =~ m{
    .+                              # some anythings
    (?(?{                           # if
            $foo{bar} gt "symbol"   # this is true
        })
            .                       # match another anything
        |                           # else
            signet                  # match signet
    )
    .                               # and one more anything
}x;

--------------

/(.*?) (?{length($1) < 3 && warn}) $suffix/;  # Error without use re 'eval'

--------------

/foo${pat}bar/

--------------

"abcdef" =~ / .+ (?{print "Matched so far: $&\n"}) bcdef $/x;

########################################################################################
5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Match-time pattern interpolation
########################################################################################

/\w (??{ if ($threshold > 1) { "red" } else { "blue" } }) \d/x;

--------------

/^ (.+) .? (??{quotemeta reverse $1}) $/xi;

--------------

$text =~ /( \(+ ) (.*?) (??{ '\)' x length $1 })/x;

--------------

$np = qr{
           \(
           (?:
              (?> [^()]+ )    # Non-parens without backtracking
            |
              (??{ $np })     # Group with matching parens
           )*
           \)
        }x;

--------------

$funpat = qr/\w+$np/;
'myfunfun(1,(2*(3+4)),5)' =~ /^$funpat$/;   # Matches!

#################################################################################
5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Conditional interpolation
#################################################################################

#!/usr/bin/perl
$x = 'Perl is free.';
$y = 'ManagerWare costs $99.95.';

foreach ($x, $y) {
    /^(\w+) (?:is|(costs)) (?(2)(\$\d+)|\w+)/;  # Either (\$\d+) or \w+
    if ($3) {
        print "$1 costs money.\n";         # ManagerWare costs money.
    } else {
        print "$1 doesn't cost money.\n";  # Perl doesn't cost money.
    }
}

--------------

/[ATGC]+(?(?<=AA)G|C)$/;

##############################################################
5:Pattern Matching/Fancy Patterns/Defining Your Own Assertions
##############################################################

use Tagger;
$_ = '<I>camel</I>';
print "Tagged camel found" if /\tag\w+\tag/;

--------------

package Tagger;
use overload;

sub import { overload::constant 'qr' => \&convert }

sub convert {
    my $re = shift;
    $re =~ s/ \\tag  /<.*?>/xg;
    $re =~ s/ \\w    /[A-Za-z]/xg;
    return $re;
}

1;

--------------

$re = '\tag\w+\tag';   # This string begins with \t, a tab
print if /$re/;        # Matches a tab, followed by an "a"...

--------------

$re = '\tag\w+\tag';         # This string begins with \t, a tab
$re = Tagger::convert $re;   # expand \tag and \w
print if /$re/;              # $re becomes <.*?>[A-Za-z]+<.*?>

#######################
6:Subroutines/Semantics
#######################

sub razzle {
    print "Ok, you've been razzled.\n";
}

--------------

razzle();

###################################################
6:Subroutines/Semantics/Tricks with Parameter Lists
###################################################

sub maysetenv {
    my ($key, $value) = @_;
    $ENV{$key} = $value unless $ENV{$key};
}

--------------

sub max {
    my $max = shift(@_);
    for my $item (@_) {
        $max = $item if $max < $item;
    }
    return $max;
}

$bestday = max($mon,$tue,$wed,$thu,$fri);

--------------

sub configuration {
    my %options = @_;
    print "Maximum verbosity.\n" if $options{VERBOSE} == 9;
}

configuration(PASSWORD => "xyzzy", VERBOSE => 9, SCORE => 0);

--------------

upcase_in($v1, $v2);  # this changes $v1 and $v2
sub upcase_in {
    for (@_) { tr/a-z/A-Z/ }
}

--------------

upcase_in("frederick");

--------------

($v3, $v4) = upcase($v1, $v2);
sub upcase {
    my @parms = @_;
    for (@parms) { tr/a-z/A-Z/ }
    # Check whether we were called in list context.
    return wantarray ? @parms : $parms[0];
}

--------------

@newlist = upcase(@list1, @list2);
@newlist = upcase( split /:/, $var );

--------------

(@a, @b) = upcase(@list1, @list2);   # WRONG

#########################################
6:Subroutines/Semantics/Error Indications
#########################################

if ($something_went_awry) {
    return if defined wantarray;  # good, not void context.
    die "Pay attention to my error, you danglesocket!!!\n";
}

######################################
6:Subroutines/Semantics/Scoping Issues
######################################

&foo(1,2,3);    # pass three arguments
foo(1,2,3);     # the same

foo();          # pass a null list
&foo();         # the same

&foo;           # foo() gets current args, like foo(@_), but faster!
foo;            # like foo() if sub foo predeclared, else bareword "foo"

--------------

# top of file
my $x = 10;         # declare and initialize variable
sub bumpx { $x++ }  # function can see outer lexical variable

--------------

{
    my $counter = 0;
    sub next_counter { return ++$counter }
    sub prev_counter { return --$counter }
}

--------------

BEGIN {
    my @scale = ('A' .. 'G');
    my $note  = -1;
    sub next_pitch { return $scale[ ($note += 1) %= @scale ] };
}

################################
6:Subroutines/Passing References
################################

$total = sum ( \@a );

sub sum {
    my ($aref)  = @_;
    my ($total) = 0;
    foreach (@$aref) { $total += $_ }
    return $total;
}

--------------

@tailings = popmany ( \@a, \@b, \@c, \@d );

sub popmany {
    my @retlist = ();
    for my $aref (@_) {
        push @retlist, pop @$aref;
    }
    return @retlist;
}

--------------

@common = inter( \%foo, \%bar, \%joe );
sub inter {
    my %seen;
    for my $href (@_) {
        while (my $k = each %$href ) {
            $seen{$k}++;
        }
    }
    return grep { $seen{$_} == @_ } keys %seen;
}

--------------

(@a, @b) = func(@c, @d);

--------------

(%a, %b) = func(%c, %d);

--------------

($aref, $bref) = func(\@c, \@d);
print "@$aref has more than @$bref\n";
sub func {
    my ($cref, $dref) = @_;
    if (@$cref > @$dref) {
        return ($cref, $dref);
    } else {
        return ($dref, $cref);
    }
}

########################
6:Subroutines/Prototypes
########################

sub mypush (\@@);

--------------

use Symbol 'qualify_to_ref';

sub foo (*) {
    my $fh = qualify_to_ref(shift, caller);
    ...
}

--------------

mytime +2;

--------------

sub try (&$) {
    my ($try, $catch) = @_;
    eval { &$try };
    if ($@) {
        local $_ = $@;
        &$catch;
    }
}
sub catch (&) { $_[0] }

try {
    die "phooey";
}                   # not the end of the function call!
catch {
    /phooey/ and print "unphooey\n";
};

--------------

sub mygrep (&@) {
    my $coderef = shift;
    my @result;
    foreach $_ (@_) {
        push(@result, $_) if &$coderef;
    }
    return @result;
}

####################################################
6:Subroutines/Prototypes/Inlining Constant Functions
####################################################

sub pi ()           { 3.14159 }             # Not exact, but close.
sub PI ()           { 4 * atan2(1, 1) }     # As good as it gets

--------------

sub FLAG_FOO ()     { 1 << 8 }
sub FLAG_BAR ()     { 1 << 9 }
sub FLAG_MASK ()    { FLAG_FOO | FLAG_BAR }

sub OPT_GLARCH ()   { (0x1B58 & FLAG_MASK) == 0 }
sub GLARCH_VAL () {
    if (OPT_GLARCH) { return 23 }
    else            { return 42 }
}

sub N () { int(GLARCH_VAL) / 3 }
BEGIN {                 # compiler runs this block at compile time
    my $prod = 1;       # persistent, private variable
    for (1 .. N) { $prod *= $_ }
    sub NFACT () { $prod }
}

--------------

sub not_inlined () {
    return 23 || $$;
}

#############################################
6:Subroutines/Prototypes/Care with Prototypes
#############################################

sub func ($) {
    my $n = shift;
    print "you gave me $n\n";
}

--------------

func @foo;                  # counts @foo elements
func split /:/;             # counts number of fields returned
func "a", "b", "c";         # passes "a" only, discards "b" and "c"
func("a", "b", "c");        # suddenly, a compiler error!

--------------

sub func (\$) {
    my $nref = shift;
    print "you gave me $$nref\n";
}

--------------

func @foo;              # compiler error, saw @, want $
func split/:/;          # compiler error, saw function, want $
func $s;                # this one is ok -- got real $ symbol
func $a[3];             # and this one
func $h{stuff}[-1];     # or even this
func 2+5;               # scalar expr still a compiler error
func ${ \(2+5) };       # ok, but is the cure worse than the disease?

##########################################################################
6:Subroutines/Subroutine Attributes/The C<locked> and C<method> Attributes
##########################################################################

# Only one thread is allowed into this function.
sub afunc : locked { ... }

# Only one thread is allowed into this function on a given object.
sub afunc : locked method { ... }

--------------

sub afunc : method { ... }

--------------

sub fnord (&\%) : switch(10,foo(7,3))  :  expensive;
sub plugh () : Ugly('\(") :Bad;
sub xyzzy : _5x5 { ... }

--------------

sub fnord : switch(10,foo();  # ()-string not balanced
sub snoid : Ugly('(');        # ()-string not balanced
sub xyzzy : 5x5;              # "5x5" not a valid identifier
sub plugh : Y2::north;        # "Y2::north" not a simple identifier
sub snurt : foo + bar;        # "+" not a colon or space

###########################################################
6:Subroutines/Subroutine Attributes/The C<lvalue> attribute
###########################################################

my $val;
sub canmod : lvalue {
    $val;
}
sub nomod {
    $val;
}

canmod() = 5;   # Assigns to $val.
nomod()  = 5;   # ERROR

--------------

canmod $x  = 5;     # assigns 5 to $x first!
canmod 42  = 5;     # can't change a constant; compile-time error
canmod($x) = 5;     # this is ok
canmod(42) = 5;     # and so is this

--------------

canmod = 5;

--------------

$obj->canmod = 5;

--------------

data(2,3) = get_data(3,4);

--------------

(data(2,3)) = get_data(3,4);

--------------

(data(2),data(3)) = get_data(3,4);

#########
7:Formats
#########

$value =~ tr/\n\t\f/ /;

--------------

# a report on the /etc/passwd file
format STDOUT_TOP =
                         Passwd File
Name                Login    Office   Uid   Gid Home
------------------------------------------------------------------
.
format STDOUT =
@<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<@>>>> @>>>> @<<<<<<<<<<<<<<<<<
$name,              $login,  $office,$uid,$gid, $home
.

# a report from a bug report form
format STDOUT_TOP =
                         Bug Reports
@<<<<<<<<<<<<<<<<<<<<<<<     @|||         @>>>>>>>>>>>>>>>>>>>>>>>
$system,                      $%,         $date
------------------------------------------------------------------
.
format STDOUT =
Subject: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
         $subject
Index: @<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
       $index,                       $description
Priority: @<<<<<<<<<< Date: @<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
          $priority,        $date,   $description
From: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      $from,                         $description
Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
             $programmer,            $description
~                                    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                     $description
~                                    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                     $description
~                                    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                     $description
~                                    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                     $description
~                                    ^<<<<<<<<<<<<<<<<<<<<<<<...
                                     $description
.

###########################
7:Formats//Format Variables
###########################

select((select(OUTF), 
        $~ = "My_Other_Format",
        $^ = "My_Top_Format"
       )[0]);

--------------

$ofh = select(OUTF);
$~ = "My_Other_Format";
$^ = "My_Top_Format";
select($ofh);

--------------

use English;
$ofh = select(OUTF);
$FORMAT_NAME     = "My_Other_Format";
$FORMAT_TOP_NAME = "My_Top_Format";
select($ofh);

--------------

use FileHandle;
OUTF->format_name("My_Other_Format");
OUTF->format_top_name("My_Top_Format");

--------------

format Ident = 
    @<<<<<<<<<<<<<<<
    commify($n)
.

--------------

format Ident = 
I have an @ here.
         "@"
.

--------------

format Ident = 
@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
                          "Some text line"
.

--------------

$format  = "format STDOUT = \n"
         . '^' . '<' x $cols . "\n"
         . '$entry' . "\n"
         . "\t^" . "<" x ($cols-8) . "~~\n"
         . '$entry' . "\n"
         . ".\n";
print $format if $Debugging;
eval $format; 
die $@ if $@;

--------------

format STDOUT = 
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$entry
    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
$entry
.

--------------

format = 
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~
$_

.

$/ = "";
while (<>) {
    s/\s*\n\s*/ /g;
    write;
}

#########################################
7:Formats//Accessing Formatting Internals
#########################################

$str = formline <<'END', 1,2,3;
@<<<  @|||  @>>>
END

print "Wow, I just stored `$^A' in the accumulator!\n";

--------------

use Carp;
sub swrite {
    croak "usage: swrite PICTURE ARGS" unless @_;
    my $format = shift;
    $^A = "";
    formline($format, @_);
    return $^A;

$string = swrite(<<'END', 1, 2, 3);
Check me out
@<<<  @|||  @>>>
END
print $string;

--------------

use FileHandle;
STDOUT->formline("^" . ("<" x 72) . "~~\n", $long_text);


############
8:References
############

@john = (47, "brown", 186);
@mary = (23, "hazel", 128);
@bill = (35, "blue",  157);

--------------

@vitals = ('john', 'mary', 'bill');

#######################################################
8:References/Creating References/The Backslash Operator
#######################################################

$scalarref = \$foo;
$constref  = \186_282.42;
$arrayref  = \@ARGV;
$hashref   = \%ENV;
$coderef   = \&handler;
$globref   = \*STDOUT;

############################################################################
8:References/Creating References/Anonymous Data/The anonymous array composer
############################################################################

$arrayref = [1, 2, ['a', 'b', 'c', 'd']];

--------------

$table = [ [ "john", 47, "brown", 186],
           [ "mary", 23, "hazel", 128],
           [ "bill", 35, "blue",  157] ];

###########################################################################
8:References/Creating References/Anonymous Data/The anonymous hash composer
###########################################################################

$hashref = {
    'Adam'   => 'Eve',
    'Clyde'  => $bonnie,
    'Antony' => 'Cleo' . 'patra',
};

--------------

$table = {
            "john" => [ 47, "brown", 186 ],
            "mary" => [ 23, "hazel", 128 ],
            "bill" => [ 35, "blue",  157 ],
};

--------------

$table = {
           "john" => { age    => 47,
                       eyes   => "brown",
                       weight => 186,
                     },
           "mary" => { age    => 23,
                       eyes   => "hazel",
                       weight => 128,
                     },
           "bill" => { age    => 35,
                       eyes   => "blue",
                       weight => 157,
                     },
 };

--------------

sub hashem {        { @_ } }   # Silently WRONG -- returns @_.
sub hashem {       +{ @_ } }   # Ok.
sub hashem { return { @_ } }   # Ok.

#################################################################################
8:References/Creating References/Anonymous Data/The anonymous subroutine composer
#################################################################################

$coderef = sub { print "Boink!\n" };  # Now &$coderef prints "Boink!"

####################################################
8:References/Creating References/Object Constructors
####################################################

$objref = Doggie::->new(Tail => 'short', Ears => 'long');  #1
$objref = new Doggie:: Tail => 'short', Ears => 'long';    #2
$objref = Doggie->new(Tail => 'short', Ears => 'long');    #3
$objref = new Doggie Tail => 'short', Ears => 'long';      #4

##################################################
8:References/Creating References/Handle References
##################################################

splutter(\*STDOUT);

sub splutter {
    my $fh = shift;
    print $fh "her um well a hmmm\n";
}

$rec = get_rec(\*STDIN);
sub get_rec {
    my $fh = shift;
    return scalar <$fh>;
}

--------------

for $file (@names) {
    local *FH;
    open(*FH, $file) || next;
    $handle{$file} = *FH;
}

--------------

for $file (@names) {
    my $fh;
    open($fh, $file) || next;
    $handle{$file} = $fh;
}

########################################################
8:References/Creating References/Symbol Table References
########################################################

$scalarref = *foo{SCALAR};   # Same as \$foo
$arrayref  = *ARGV{ARRAY};   # Same as \@ARGV
$hashref   = *ENV{HASH};     # Same as \%ENV
$coderef   = *handler{CODE}; # Same as \&handler
$globref   = *foo{GLOB};     # Same as \*foo
$ioref     = *STDIN{IO};     # Er...

--------------

splutter(*STDOUT);
splutter(*STDOUT{IO});

sub splutter {
    my $fh = shift;
    print $fh "her um well a hmmm\n";
}

######################################################################
8:References/Using Hard References/Using a Variable as a Variable Name
######################################################################

$foo         = "three humps";
$scalarref   = \$foo;         # $scalarref is now a reference to $foo
$camel_model = $$scalarref;   # $camel_model is now "three humps"

--------------

$bar = $$scalarref;

push(@$arrayref, $filename);
$$arrayref[0] = "January";            # Set the first element of @$arrayref
@$arrayref[4..6] = qw/May June July/; # Set several elements of @$arrayref

%$hashref = (KEY => "RING", BIRD => "SING");  # Initialize whole hash
$$hashref{KEY} = "VALUE";                     # Set one key/value pair
@$hashref{"KEY1","KEY2"} = ("VAL1","VAL2");   # Set several pairs

&$coderef(1,2,3);

print $handleref "output\n";

--------------

$refrefref = \\\"howdy";
print $$$$refrefref;

######################################################################
8:References/Using Hard References/Using a BLOCK as a Variable Name
######################################################################

$bar = ${$scalarref};
push(@{$arrayref}, $filename);
${$arrayref}[0] = "January";
@{$arrayref}[4..6] = qw/May June July/;
${$hashref}{"KEY"} = "VALUE";
@{$hashref}{"KEY1","KEY2"} = ("VAL1","VAL2");
&{$coderef}(1,2,3);

--------------

$refrefref = \\\"howdy";
print ${${${$refrefref}}};

--------------

&{ $dispatch{$index} }(1, 2, 3);

###########################################################
8:References/Using Hard References/Using the Arrow Operator
###########################################################

$  $arrayref  [2] = "Dorian";         #1
${ $arrayref }[2] = "Dorian";         #2
   $arrayref->[2] = "Dorian";         #3

$  $hashref  {KEY} = "F#major";       #1
${ $hashref }{KEY} = "F#major";       #2
   $hashref->{KEY} = "F#major";       #3

&  $coderef  (Presto => 192);         #1
&{ $coderef }(Presto => 192);         #2
   $coderef->(Presto => 192);         #3

--------------

print $array[3]->{"English"}->[0];

--------------

$array[3]->{"English"}->[0] = "January";

--------------

$dispatch{$index}(1, 2, 3);
$array[3]{"English"}[0] = "January";

--------------

$answer[$x][$y][$z] += 42;

--------------

 $listref->[2][2] = "hello";    # Pretty clear
$$listref[2][2]   = "hello";    # A bit confusing

--------------

$listref[2]->[$greeting] = "hello";

###############################################
8:References/Using Hard References/Pseudohashes
###############################################

$john = [ {age => 1, eyes => 2, weight => 3}, 47, "brown", 186 ];

--------------

$john->{weight}             # Treats $john as a hashref
$john->[3]                  # Treats $john as an arrayref

--------------

$john->[0]{height} = 4;     # height is to be element 4
$john->{height} = "tall";   # Or $john->[4] = "tall"

--------------

delete $john->[0]{height};  # Deletes from the underlying hash only
$john->{height};            # This now raises an exception
$john->[4];                 # Still prints "tall"

--------------

use fields;
$ph = fields::phash(age => 47, eyes => "brown", weight => 186);
print $ph->{age};

--------------

use fields;
$ph= fields::phash([qw(age eyes brown)], [47]);
$ph->{eyes} = undef;

print exists $ph->{age};     # True, 'age' was set in declaration.
print exists $ph->{weight};  # False, 'weight' has not been used.
print exists $ph->{eyes};    # True, your 'eyes' have been touched.

--------------

print exists $ph->[0]{age};   # True, 'page' is a valid field
print exists $ph->[0]{name};  # False, 'name' can't be used

--------------

print delete $ph->{age};     # Removes and returns $ph->[1], 47
print exists $ph->{age};     # Now false
print exists $ph->[0]{age};  # True, 'age' key still usable
print delete $ph->[0]{age};  # Now 'age' key is gone
print $ph->{age};            # Run-time exception

###############################################################################
8:References/Using Hard References/Other Tricks You Can Do with Hard References
###############################################################################

@reflist = (\$s, \@a, \%h, \&f);     # List of four references
@reflist = \($s,  @a   %h,  &f);     # Same thing

--------------

@reflist = \(@x);                    # Interpolate array, then get refs
@reflist = map { \$_ } @x;           # Same thing

--------------

@reflist = \(@x, (@y));            # But only single aggregates expand
@reflist = (\@x, map { \$_ } @y);    # Same thing

--------------

@envrefs = \@ENV{'HOME', 'TERM'};         # Backslashing a slice
@envrefs = \( $ENV{HOME},  $ENV{TERM} );  # Backslashing a list
@envrefs = ( \$ENV{HOME}, \$ENV{TERM} );  # A list of two references

--------------

@reflist = \fx();
@reflist = map { \$_ } fx();                # Same thing

@reflist = \( fx(), fy(), fz() );
@reflist = ( \fx(), \fy(), \fz() );         # Same thing
@reflist = map { \$_ } fx(), fy(), fz();    # Same thing

--------------

@reflist = \localtime();      # Ref to each of nine time elements
$lastref = \localtime();      # Ref to whether it's daylight savings time

--------------

$dateref = \scalar localtime();    # \"Sat Jul 16 11:42:18 2000"

--------------

sub sum {
    my $arrayref = shift;
    warn "Not an array reference" if ref($arrayref) ne "ARRAY";
    return eval join("+", @$arrayref);
}

--------------

print "My sub returned @{[ mysub(1,2,3) ]} that time.\n";

--------------

print "We need @{ [$n + 5] } widgets!\n";

--------------

print "mysub returns @{ [scalar mysub(1,2,3)] } now.\n";

###########################################
8:References/Using Hard References/Closures
###########################################

{
    my $critter = "camel";
    $critterref = \$critter;
}

--------------

{
    my $critter = "camel";
    $critterref = sub { return $critter };
}

--------------

sub make_saying  {
    my $salute = shift;
    my $newfunc = sub {
        my $target = shift;
        print "$salute, $target!\n";
    };
    return $newfunc;            # Return a closure
}

$f = make_saying("Howdy");      # Create a closure
$g = make_saying("Greetings");  # Create another closure

# Time passes...

$f->("world");
$g->("earthlings");

--------------

sub get_method_ref {
    my ($self, $methodname) = @_;
    my $methref = sub {
        # the @_ below is not the same as the one above!
        return $self->$methodname(@_);
    };
    return $methref;
}

my $dog = new Doggie::
            Name => "Lucky",
            Legs => 3,
            Tail => "clipped";

our $wagger = get_method_ref($dog, 'wag');
$wagger->("tail");        # Calls $dog->wag('tail').

##########################################################################
8:References/Using Hard References/Closures/Closures as function templates
##########################################################################

print "Be ", red("careful"), "with that ", green("light"), "!!!";

--------------

@colors = qw(red blue green yellow orange purple violet);
for my $name (@colors) {
    no strict 'refs';       # Allow symbolic references
    *$name = *{uc $name} = sub { "<FONT COLOR='$name'>@_</FONT>" };
}

--------------

*$name = sub ($) { "<FONT COLOR='$name'>$_[0]</FONT>" };

##############################################################
8:References/Using Hard References/Closures/Nested subroutines
##############################################################

sub outer {
    my $x = $_[0] + 35;
    local *inner = sub { return $x * 19 };
    return $x + inner();
}

--------------

sub outer {
    my $x = $_[0] + 35;
    my $inner = sub { return $x * 19 };
    return $x + $inner->();
}

################################
8:References/Symbolic References
################################

$name = "bam";
$$name = 1;                # Sets $bam
$name->[0] = 4;            # Sets the first element of @bam
$name->{X} = "Y";          # Sets the X element of %bam to Y
@$name = ();               # Clears @bam
keys %$name;               # Yields the keys of %bam
&$name;                    # Calls &bam

--------------

use strict 'refs';

--------------

no strict 'refs';

--------------

${identifier};    # Same as $identifier.
${"identifier"};  # Also $identifier, but a symbolic reference.

--------------

our $value  = "global";
{
    my $value = "private";
    print "Inside, mine is ${value}, ";
    print "but ours is ${'value'}.\n";
}
print "Outside, ${value} is again ${'value'}.\n";

##########################################
8:References/Braces, Brackets, and Quoting
##########################################

$push = "pop on ";
print "${push}over";

--------------

print ${push} . 'over';

--------------

print ${ push } . 'over';

--------------

$hash{ "aaa" }{ "bbb" }{ "ccc" }

--------------

$hash{ aaa }{ bbb }{ ccc }

--------------

$hash{aaa}{bbb}{ccc}

--------------

$hash{ shift }

--------------

$hash{  shift()  }
$hash{ +shift   }
$hash{  shift @_ }

#############################################################################
8:References/Braces, Brackets, and Quoting/References Don't Work as Hash Keys
#############################################################################

$x{ \$a } = $a;
($key, $value) = each %x;
print $$key;                # WRONG

--------------

$r = \@a;
$x{ $r } = $r;

--------------

use Tie::RefHash;
tie my %h, 'Tie::RefHash';
%h = (
    ["this", "here"]   => "at home",
    ["that", "there"]  => "elsewhere",
);
while ( my($keyref, $value) = each %h ) {
    print "@$keyref is $value\n";
}

#######################################################################################################
8:References/Braces, Brackets, and Quoting/Garbage Collection, Circular References, and Weak References
#######################################################################################################

{               # make $a and $b point to each other
    my ($a, $b);
    $a = \$b;
    $b = \$a;
}

--------------

{               # make $a point to itself
    my $a;
    $a = \$a;
}

#################################################################################################################
9:Data Structures/A Brief Tutorial:  Manipulating Arrays of Arrays/Creating and Accessing a Two-Dimensional Array
#################################################################################################################

# Assign a list of array references to an array.
@AoA = (
         [ "fred", "barney" ],
         [ "george", "jane", "elroy" ],
         [ "homer", "marge", "bart" ],
);

print $AoA[2][1];   # prints "marge"

--------------

# Create an reference to an array of array references.
$ref_to_AoA = [
    [ "fred", "barney", "pebbles", "bamm bamm", "dino", ],
    [ "homer", "bart", "marge", "maggie", ],
    [ "george", "jane", "elroy", "judy", ],
];

print $ref_to_AoA->[2][3];   # prints "judy"

--------------

$AoA[2][3]
$ref_to_AoA->[2][3]

--------------

$AoA[2]->[3]
$ref_to_AoA->[2]->[3]

--------------

$AoA[0][-2]

###################################################################################
9:Data Structures/A Brief Tutorial:  Manipulating Arrays of Arrays/Growing Your Own
###################################################################################

while (<>) {
    @tmp = split;           # Split elements into an array.
    push @AoA, [ @tmp ];    # Add an anonymous array reference to @AoA.
}

--------------

while (<>) {
    push @AoA, [ split ];
}

--------------

while (<>) {
    push @$ref_to_AoA, [ split ];
}

--------------

for $x (0 .. 9) {                       # For each row...
    for $y (0 .. 9) {                   # For each column...
        $AoA[$x][$y] = func($x, $y);    # ...set that cell
    }
}

for $x ( 0..9 ) {                       # For each row...
    $ref_to_AoA->[$x][3] = func2($x);   # ...set the fourth column
}

--------------

# Append new columns to an existing row.
push @{ $AoA[0] }, "wilma", "betty";

--------------

push $AoA[0], "wilma", "betty";  # WRONG!

######################################################################################
9:Data Structures/A Brief Tutorial:  Manipulating Arrays of Arrays/Access and Printing
######################################################################################

print $AoA[3][2];

--------------

print @AoA;         # WRONG

--------------

for $row ( @AoA ) {
    print "@$row\n";
}

--------------

for $i ( 0 .. $#AoA ) {
    print "row $i is: @{$AoA[$i]}\n";
}

--------------

for $i ( 0 .. $#AoA ) {
    for $j ( 0 .. $#{$AoA[$i]} ) {
        print "element $i $j is $AoA[$i][$j]\n";
    }
}

--------------

for $i ( 0 .. $#AoA ) {
    $row = $AoA[$i];
    for $j ( 0 .. $#{$row} ) {
        print "element $i $j is $row->[$j]\n";
    }
}

#########################################################################
9:Data Structures/A Brief Tutorial:  Manipulating Arrays of Arrays/Slices
#########################################################################

@part = ();
for ($y = 7; $y < 13; $y++) {
    push @part, $AoA[4][$y];
}

--------------

@part = @{ $AoA[4] } [ 7..12 ];

--------------

@newAoA = ();
for ($startx = $x = 4; $x <= 8; $x++) {
    for ($starty = $y = 7; $y <= 12; $y++) {
        $newAoA[$x - $startx][$y - $starty] = $AoA[$x][$y];
    }
}

--------------

for ($x = 4; $x <= 8; $x++) {
    push @newAoA, [ @{ $AoA[$x] } [ 7..12 ] ];
}

##################################################################################
9:Data Structures/A Brief Tutorial:  Manipulating Arrays of Arrays/Common Mistakes
##################################################################################

@AoA = ( [2, 3], [4, 5, 7], [0] );
print "@AoA";

--------------

print $AoA[1][2];

--------------

for $i (1..10) {
    @array = somefunc($i);
    $AoA[$i] = @array;       # WRONG!
}

--------------

for $i (1..10) {
    @array = somefunc($i);
    $AoA[$i] = \@array;      # WRONG AGAIN!
}

--------------

for $i (1..10) {
    @array = somefunc($i);
    $AoA[$i] = [ @array ];   # RIGHT!
}

--------------

for $i (1..10) {
    @array = somefunc($i);
    @{$AoA[$i]} = @array;
}

--------------

$AoA[3] = \@original_array;

--------------

@{$AoA[3]} = @array;

--------------

for $i (1..10) {
    my @array = somefunc($i);
    $AoA[$i] = \@array;
}

--------------

for $i (1..10) {
    $AoA[$i] = [ somefunc($i) ];
}

--------------

$AoA[$i] = [ @array ];   # Safest, sometimes fastest
$AoA[$i] = \@array;      # Fast but risky, depends on my-ness of array
@{ $AoA[$i] } = @array;  # Too tricky for most uses

##################################################################
9:Data Structures/Hashes of Arrays/Composition of a Hash of Arrays
##################################################################

# We customarily omit quotes when the keys are identifiers.
%HoA = (
    flintstones    => [ "fred", "barney" ],
    jetsons        => [ "george", "jane", "elroy" ],
    simpsons       => [ "homer", "marge", "bart" ],
);

--------------

$HoA{teletubbies} = [ "tinky winky", "dipsy", "laa-laa", "po" ];

#################################################################
9:Data Structures/Hashes of Arrays/Generation of a Hash of Arrays
#################################################################

while ( <> ) {
    next unless s/^(.*?):\s*//;
    $HoA{$1} = [ split ];
}

while ( $line = <> ) {
    ($who, $rest) = split /:\s*/, $line, 2;
    @fields = split ' ', $rest;
    $HoA{$who} = [ @fields ];
}

--------------

for $group ( "simpsons", "jetsons", "flintstones" ) {
    $HoA{$group} = [ get_family($group) ];
}

for $group ( "simpsons", "jetsons", "flintstones" ) {
    @members = get_family($group);
    $HoA{$group} = [ @members ];
}

--------------

push @{ $HoA{flintstones} }, "wilma", "pebbles";

##########################################################################
9:Data Structures/Hashes of Arrays/Access and Printing of a Hash of Arrays
##########################################################################

$HoA{flintstones}[0] = "Fred";

--------------

$HoA{simpsons}[1] =~ s/(\w)/\u$1/;

--------------

for $family ( keys %HoA ) {
    print "$family: @{ $HoA{$family} }\n";
}

--------------

for $family ( keys %HoA ) {
    print "$family: ";
    for $i ( 0 .. $#{ $HoA{$family} } ) {
        print " $i = $HoA{$family}[$i]";
    }
    print "\n";
}

--------------

for $family ( sort { @{$HoA{$b}} <=> @{$HoA{$a}} } keys %HoA ) {
    print "$family: @{ $HoA{$family} }\n"
}

--------------

# Print the whole thing sorted by number of members and name.
for $family ( sort { @{$HoA{$b}} <=> @{$HoA{$a}} } keys %HoA ) {
    print "$family: ", join(", ", sort @{ $HoA{$family} }), "\n";
}

####################################################################
9:Data Structures/Arrays of Hashes/Composition of an Array of Hashes
####################################################################

@AoH = (
    {
       husband  => "barney",
       wife     => "betty",
       son      => "bamm bamm",
    },
    {
       husband => "george",
       wife    => "jane",
       son     => "elroy",
    },
    {
       husband => "homer",
       wife    => "marge",
       son     => "bart",
    },
  );

--------------

push @AoH, { husband => "fred", wife => "wilma", son => "junior" };

###################################################################
9:Data Structures/Arrays of Hashes/Generation of an Array of Hashes
###################################################################

while ( <> ) {
    $rec = {};
    for $field ( split ) {
        ($key, $value) = split /=/, $field;
        $rec->{$key} = $value;
    }
    push @AoH, $rec;
}

while ( <> ) {
    push @AoH, { split /[\s=]+/ };
}

--------------

while ( @fields = get_next_pair() ) {
    push @AoH, { @fields };
}

while (<>) {
    push @AoH, { get_next_pair($_) };
}

--------------

$AoH[0]{pet} = "dino";
$AoH[2]{pet} = "santa's little helper";

############################################################################
9:Data Structures/Arrays of Hashes/Access and Printing of an Array of Hashes
############################################################################

$AoH[0]{husband} = "fred";

--------------

$AoH[1]{husband} =~ s/(\w)/\u$1/;

--------------

for $href ( @AoH ) {
    print "{ ";
    for $role ( keys %$href ) {
         print "$role=$href->{$role} ";
    }
    print "}\n";
}

--------------

for $i ( 0 .. $#AoH ) {
    print "$i is { ";
    for $role ( keys %{ $AoH[$i] } ) {
         print "$role=$AoH[$i]{$role} ";
    }
    print "}\n";
}

##################################################################
9:Data Structures/Hashes of Hashes/Composition of a Hash of Hashes
##################################################################

%HoH = (
    flintstones => {
        husband   => "fred",
        pal       => "barney",
    },
    jetsons => {
        husband   => "george",
        wife      => "jane",
        "his boy" => "elroy",  # Key quotes needed.
    },
    simpsons => {
        husband   => "homer",
        wife      => "marge",
        kid       => "bart",
    },
);

--------------

$HoH{ mash } = {
    captain  => "pierce",
    major    => "burns",
    corporal => "radar",
};

#################################################################
9:Data Structures/Hashes of Hashes/Generation of a Hash of Hashes
#################################################################

while ( <> ) {
    next unless s/^(.*?):\s*//;
    $who = $1;
    for $field ( split ) {
        ($key, $value) = split /=/, $field;
        $HoH{$who}{$key} = $value;
    }
}

while ( <> ) {
    next unless s/^(.*?):\s*//;
    $who = $1;
    $rec = {};
    $HoH{$who} = $rec;
    for $field ( split ) {
        ($key, $value) = split /=/, $field;
        $rec->{$key} = $value;
    }
}

--------------

for $group ( "simpsons", "jetsons", "flintstones" ) {
    $HoH{$group} = { get_family($group) };
}

for $group ( "simpsons", "jetsons", "flintstones" ) {
    @members = get_family($group);
    $HoH{$group} = { @members };
}

sub hash_families {
    my @ret;
    for $group ( @_ ) {
        push @ret, $group, { get_family($group) };
    }
    @ret;
}
%HoH = hash_families( "simpsons", "jetsons", "flintstones" );

--------------

%new_folks = (
    wife => "wilma",
    pet  => "dino";
);
for $what (keys %new_folks) {
    $HoH{flintstones}{$what} = $new_folks{$what};
}

##########################################################################
9:Data Structures/Hashes of Hashes/Access and Printing of a Hash of Hashes
##########################################################################

$HoH{flintstones}{wife} = "wilma";

--------------

$HoH{jetsons}{'his boy'} =~ s/(\w)/\u$1/;

--------------

for $family ( keys %HoH ) {
    print "$family: ";
    for $role ( keys %{ $HoH{$family} } ) {
         print "$role=$HoH{$family}{$role} ";
    }
    print "\n";
}

--------------

while ( ($family, $roles) = each %HoH ) {
    print "$family: ";
    while ( ($role, $person) = each %$roles ) {
        print "$role=$person ";
    }
    print "\n";
}

--------------

for $family ( sort keys %HoH ) {
    print "$family: ";
    for $role ( sort keys %{ $HoH{$family} } ) {
         print "$role=$HoH{$family}{$role} ";
    }
    print "\n";
}

--------------

for $family ( sort { keys %{$HoH{$a}} <=> keys %{$HoH{$b}} } keys %HoH ) {
    print "$family: ";
    for $role ( sort keys %{ $HoH{$family} } ) {
         print "$role=$HoH{$family}{$role} ";
    }
    print "\n";
}

--------------

$i = 0;
for ( qw(husband wife son daughter pal pet) ) { $rank{$_} = ++$i }

for $family ( sort { keys %{$HoH{$a}} <=> keys %{$HoH{$b}} } keys %HoH ) {
    print "$family: ";
    for $role ( sort { $rank{$a} <=> $rank{$b} } keys %{ $HoH{$family} } ) {
        print "$role=$HoH{$family}{$role} ";
    }
    print "\n";
}

#####################################
9:Data Structures/Hashes of Functions
#####################################

if    ($cmd =~ /^exit$/i)     { exit }
elsif ($cmd =~ /^help$/i)     { show_help() }
elsif ($cmd =~ /^watch$/i)    { $watch = 1 }
elsif ($cmd =~ /^mail$/i)     { mail_msg($msg) }
elsif ($cmd =~ /^edit$/i)     { $edited++; editmsg($msg); }
elsif ($cmd =~ /^delete$/i)   { confirm_kill() }
else {
    warn "Unknown command: `$cmd'; Try `help' next time\n";
}

--------------

%HoF = (                           # Compose a hash of functions
    exit    =>  sub { exit },
    help    =>  \&show_help,
    watch   =>  sub { $watch = 1 },
    mail    =>  sub { mail_msg($msg) },
    edit    =>  sub { $edited++; editmsg($msg); },
    delete  =>  \&confirm_kill,
);

if   ($HoF{lc $cmd}) { $HoF{lc $cmd}->() }   # Call function
else { warn "Unknown command: `$cmd'; Try `help' next time\n" }

####################################################################################################
9:Data Structures/More Elaborate Records/Composition, Access, and Printing of More Elaborate Records
####################################################################################################

$rec = {
    TEXT      => $string,
    SEQUENCE  => [ @old_values ],
    LOOKUP    => { %some_table },
    THATCODE  => \&some_function,
    THISCODE  => sub { $_[0] ** $_[1] },
    HANDLE    => \*STDOUT,
};

--------------

print $rec->{TEXT};

--------------

print $rec->{SEQUENCE}[0];
$last = pop @{ $rec->{SEQUENCE} };

print $rec->{LOOKUP}{"key"};
($first_k, $first_v) = each %{ $rec->{LOOKUP} };

--------------

$that_answer = $rec->{THATCODE}->($arg1, $arg2);
$this_answer = $rec->{THISCODE}->($arg1, $arg2);

--------------

print { $rec->{HANDLE} } "a string\n";

--------------

use FileHandle;
$rec->{HANDLE}->autoflush(1);
$rec->{HANDLE}->print("a string\n");

#########################################################################################################
9:Data Structures/More Elaborate Records/Composition, Access, and Printing of Even More Elaborate Records
#########################################################################################################

%TV = (
    flintstones => {
        series   => "flintstones",
        nights   => [ "monday", "thursday", "friday" ],
        members  => [
            { name => "fred",    role => "husband", age  => 36, },
            { name => "wilma",   role => "wife",    age  => 31, },
            { name => "pebbles", role => "kid",     age  =>  4, },
        ],
    },

    jetsons     => {
        series   => "jetsons",
        nights   => [ "wednesday", "saturday" ],
        members  => [
            { name => "george",  role => "husband", age  => 41, },
            { name => "jane",    role => "wife",    age  => 39, },
            { name => "elroy",   role => "kid",     age  =>  9, },
        ],
     },

    simpsons    => {
        series   => "simpsons",
        nights   => [ "monday" ],
        members  => [
            { name => "homer", role => "husband", age => 34, },
            { name => "marge", role => "wife",    age => 37, },
            { name => "bart",  role => "kid",     age => 11, },
        ],
     },
  );

################################################################################
9:Data Structures/More Elaborate Records/Generation of a Hash of Complex Records
################################################################################

$rec = {};
$rec->{series} = "flintstones";
$rec->{nights} = [ find_days() ];

--------------

@members = ();
while (<>) {
     %fields = split /[\s=]+/;
     push @members, { %fields };
}
$rec->{members} = [ @members ];

--------------

$TV{ $rec->{series} } = $rec;

--------------

for $family (keys %TV) {
    my $rec = $TV{$family};   # temporary pointer
    @kids = ();
    for $person ( @{$rec->{members}} ) {
        if ($person->{role} =~ /kid|son|daughter/) {
            push @kids, $person;
        }
    }
    # $rec and $TV{$family} point to same data!
    $rec->{kids} = [ @kids ];
}

--------------

$TV{simpsons}{kids}[0]{age}++;

--------------

print $TV{simpsons}{members}[2]{age};

--------------

for $family ( keys %TV ) {
    print "the $family";
    print " is on ", join (" and ", @{ $TV{$family}{nights} }), "\n";
    print "its members are:\n";
    for $who ( @{ $TV{$family}{members} } ) {
        print " $who->{name} ($who->{role}), age $who->{age}\n";
    }
    print "children: ";
    print join (", ", map { $_->{name} } @{ $TV{$family}{kids} } );
    print "\n\n";
}

########################################
9:Data Structures/Saving Data Structures
########################################

use Data::Dumper;
$Data::Dumper::Purity = 1;       # since %TV is self-referential
open (FILE, "> tvinfo.perldata") or die "can't open tvinfo: $!";
print FILE Data::Dumper->Dump([\%TV], ['*TV']);
close FILE                       or die "can't close tvinfo: $!";

--------------

open (FILE, "< tvinfo.perldata") or die "can't open tvinfo: $!";
undef $/;                        # read in file all at once
eval <FILE>;                     # recreate %TV
die "can't recreate tv data from tvinfo.perldata: $@" if $@;
close FILE                       or die "can't close tvinfo: $!";
print $TV{simpsons}{members}[2]{age};

--------------

do "tvinfo.perldata"            or die "can't recreate tvinfo: $! $@";
print $TV{simpsons}{members}[2]{age};

###########
10:Packages
###########

$SIG{QUIT} = "Pkg::quit_catcher"; # fully qualified handler name
$SIG{QUIT} = "quit_catcher";      # implies "main::quit_catcher"
$SIG{QUIT} = *quit_catcher;       # forces current package's sub
$SIG{QUIT} = \&quit_catcher;      # forces current package's sub
$SIG{QUIT} = sub { print "Caught SIGQUIT\n" };   # anonymous sub

#########################
10:Packages/Symbol Tables
#########################

*sym = *main::variable;
*sym = $main::{"variable"};

--------------

foreach $symname (sort keys %main::) {
    local *sym = $main::{$symname};
    print "\$$symname is defined\n" if defined $sym;
    print "\@$symname is nonnull\n" if         @sym;
    print "\%$symname is nonnull\n" if         %sym;
}

--------------

$!@#$%           = 0;         # WRONG, syntax error.
${'!@#$%'}       = 1;         # Ok, though unqualified.

${'main::!@#$%'} = 2;         # Can qualify within the string.
print ${ $main::{'!@#$%'} }   # Ok, prints 2!

--------------

*dick = *richard;

--------------

*dick = \$richard;

--------------

*SomePack::dick = \&OtherPack::richard;

--------------

*units = populate() ;         # Assign \%newhash to the typeglob
print $units{kg};             # Prints 70; no dereferencing needed!

sub populate {
    my %newhash = (km => 10, kg => 70);
    return \%newhash;
}

--------------

%units = (miles => 6, stones => 11);  
fillerup( \%units );          # Pass in a reference
print $units{quarts};         # Prints 4

sub fillerup {
    local *hashsym = shift;   # Assign \%units to the typeglob
    $hashsym{quarts} = 4;     # Affects %units; no dereferencing needed!
}

--------------

*PI = \3.14159265358979;

--------------

use constant PI => 3.14159;

--------------

*PI = sub () { 3.14159 };

--------------

*sym =   *oldvar;
*sym =  \*oldvar;       # auto-dereference
*sym = *{"oldvar"};     # explicit symbol table lookup
*sym =   "oldvar";      # implicit symbol table lookup

--------------

*sym = \$frodo;
*sym = \@sam;
*sym = \%merry;
*sym = \&pippin;

--------------

*pkg::sym{SCALAR}      # same as \$pkg::sym
*pkg::sym{ARRAY}       # same as \@pkg::sym
*pkg::sym{HASH}        # same as \%pkg::sym
*pkg::sym{CODE}        # same as \&pkg::sym
*pkg::sym{GLOB}        # same as \*pkg::sym
*pkg::sym{IO}          # internal file/dir handle, no direct equivalent
*pkg::sym{NAME}        # "sym" (not a reference)
*pkg::sym{PACKAGE}     # "pkg" (not a reference)

--------------

sub identify_typeglob {
    my $glob = shift;
    print 'You gave me ', *{$glob}{PACKAGE}, '::', *{$glob}{NAME}, "\n";
}

identify_typeglob(*foo);
identify_typeglob(*bar::glarch);

#######################
10:Packages/Autoloading
#######################

sub AUTOLOAD {
    our $AUTOLOAD;
    warn "Attempt to call $AUTOLOAD failed.\n";
}

blarg(10);              # our $AUTOLOAD will be set to main::blarg
print "Still alive!\n";

--------------

sub AUTOLOAD {
    our $AUTOLOAD;
    return "I see $AUTOLOAD(@_)\n";
}

print blarg(20);        # prints: I see main::blarg(20)

--------------

sub AUTOLOAD {
    my $name = our $AUTOLOAD;
    *$AUTOLOAD = sub { print "I see $name(@_)\n" };
    goto &$AUTOLOAD;    # Restart the new routine.
}

blarg(30);              # prints: I see main::blarg(30)
glarb(40);              # prints: I see main::glarb(40)
blarg(50);              # prints: I see main::blarg(50)

--------------

sub AUTOLOAD {
    my $program = our $AUTOLOAD;
    $program =~ s/.*:://;  # trim package name
    system($program, @_);
}

--------------

date();
who('am', 'i');
ls('-l');
echo("Abadugabudabuda...");

--------------

sub date (;$$);       # Allow zero to two arguments.
sub who (;$$$$);      # Allow zero to four args.
sub ls;               # Allow any number of args.
sub echo ($@);        # Allow at least one arg.

date;
who "am", "i";
ls "-l";
echo "That's all, folks!";
########################
11:Modules/Using Modules
########################

use Fred;       # If Fred.pm has @EXPORT = qw(flintstone)
flintstone();   # ...this calls Fred::flintstone().

###########################
11:Modules/Creating Modules
###########################

package      Bestiary;
require      Exporter;

our @ISA       = qw(Exporter);
our @EXPORT    = qw(camel);    # Symbols to be exported by default
our @EXPORT_OK = qw($weight);  # Symbols to be exported on request
our $VERSION   = 1.00;         # Version number

### Include your variables and functions here

sub camel { print "One-hump dromedary" }

$weight = 1024;

1;

###########################################################
11:Modules/Creating Modules/Module Privacy and the Exporter
###########################################################

require Exporter;
our @ISA = ("Exporter");

--------------

our @EXPORT    = qw($camel %wolf ram);              # Export by default
our @EXPORT_OK = qw(leopard @llama $emu);           # Export by request
our %EXPORT_TAGS = (                                # Export as group
                     camelids => [qw($camel @llama)],
                     critters => [qw(ram $camel %wolf)],
                   );

--------------

use Bestiary;                    # Import @EXPORT symbols
use Bestiary ();                 # Import nothing
use Bestiary qw(ram @llama);     # Import the ram function and @llama array
use Bestiary qw(:camelids);      # Import $camel and @llama
use Bestiary qw(:DEFAULT);       # Import @EXPORT symbols
use Bestiary qw(/am/);           # Import $camel, @llama, and ram
use Bestiary qw(/^\$/);          # Import all scalars
use Bestiary qw(:critters !ram); # Import the critters, but exclude ram
use Bestiary qw(:critters !:camelids);
                                 # Import critters, but no camelids

--------------

BEGIN {
    require Bestiary;
    import Bestiary LIST;
}

##########################################################################################################
11:Modules/Creating Modules/Module Privacy and the Exporter/Exporting without using Export's import method
##########################################################################################################

package Bestiary;
@ISA = qw(Exporter);
@EXPORT_OK = qw ($zoo);

sub import {
    $Bestiary::zoo = "menagerie";
}

--------------

sub import {
    $Bestiary::zoo = "menagerie";
    Bestiary->export_to_level(1, @_);
}

############################################################################
11:Modules/Creating Modules/Module Privacy and the Exporter/Version checking
############################################################################

use Bestiary 3.14;   # The Bestiary must be version 3.14 or later
use Bestiary v1.0.4; # The Bestiary must be version 1.0.4 or later

####################################################################################
11:Modules/Creating Modules/Module Privacy and the Exporter/Managing unknown symbols
####################################################################################

sub export_fail {
    my $class = shift;
    carp "Sorry, these symbols are unavailable: @_";
    return @_;
}

##########################################################################################
11:Modules/Creating Modules/Module Privacy and the Exporter/Tag handling utility functions
##########################################################################################

%EXPORT_TAGS = (foo => [qw(aa bb cc)], bar => [qw(aa cc dd)]);

Exporter::export_tags('foo');     # add aa, bb and cc to @EXPORT
Exporter::export_ok_tags('bar');  # add aa, cc and dd to @EXPORT_OK

########################################
11:Modules/Overriding Built-in Functions
########################################

use subs qw(chdir chroot chmod chown);
chdir $somewhere;
sub chdir { ... }

--------------

*CORE::GLOBAL::glob = sub {
    my $pat = shift;
    my @got;
    local *D;
    if (opendir D, '.') {
        @got = grep /$pat/, readdir D;
        closedir D;
    }
    return @got;
}

package Whatever;

print <^[a-z_]+\.pm\$>;       # show all pragmas in the current directory

#######################################################################
12:Objects/Method Invocation/Method Invocation Using the Arrow Operator
#######################################################################

$mage = Wizard->summon("Gandalf");  # class method
$mage->speak("friend");             # instance method

--------------

Wizard->summon("Gandalf")->speak("friend");

--------------

$method = "summon";
$mage = Wizard->$method("Gandalf");  # Invoke Wizard->summon

$travel = $companion eq "Shadowfax" ? "ride" : "walk";
$mage->$travel("seven leagues");     # Invoke $mage->ride or $mage->walk

#####################################################################
12:Objects/Method Invocation/Method Invocation Using Indirect Objects
#####################################################################

$mage = summon Wizard "Gandalf";
$nemesis = summon Balrog home => "Moria", weapon => "whip";
move $nemesis "bridge";
speak $mage "You cannot pass";
break $staff;               # safer to use: break $staff ();

--------------

print STDERR "help!!!\n";

--------------

speak { summon Wizard "Gandalf" } "friend";

###################################################################
12:Objects/Method Invocation/Syntactic Snafus with Indirect Objects
###################################################################

enchant $sword ($pips + 2) * $cost;

--------------

($sword->enchant($pips + 2)) * $cost;

--------------

name $sword $oldname || "Glamdring";   # can't use "or" here!

--------------

$sword->name($oldname || "Glamdring");

--------------

speak $mage "friend" && enter();        # should've been "and" here!

--------------

$mage->speak("friend" && enter());

--------------

enter() if $mage->speak("friend");
$mage->speak("friend") && enter();
speak $mage "friend" and enter();

--------------

move $party->{LEADER};               # probably wrong!
move $riders[$i];                    # probably wrong!

--------------

$party->move->{LEADER};
$riders->move([$i]);

--------------

$party->{LEADER}->move;
$riders[$i]->move;

###################################################
12:Objects/Method Invocation/Package-Quoted Classes
###################################################

$obj = new ElvenRing;               # could be new("ElvenRing")
                                    # or even new(ElvenRing())
$obj = ElvenRing->new;              # could be ElvenRing()->new()

$obj = new ElvenRing::;             # always "ElvenRing"->new()
$obj = ElvenRing::->new;            # always "ElvenRing"->new()

--------------

$obj = new ElvenRing::
            name    => "Narya",
            owner   => "Gandalf",
            domain  => "fire",
            stone   => "ruby";

--------------

use ElvenRing;
require ElvenRing;

##############################
12:Objects/Object Construction
##############################

$obj = { };                 # Get reference to anonymous hash.
bless($obj);                # Bless hash into current package.
bless($obj, "Critter");     # Bless hash into class Critter.

--------------

package Critter;
sub spawn { bless {}; }

--------------

package Critter;
sub spawn {
    my     $self = {};       # Reference to an empty anonymous hash
    bless  $self, "Critter"; # Make that hash a Critter object
    return $self;            # Return the freshly generated Critter
}

--------------

$pet = Critter->spawn;      

#######################################################
12:Objects/Object Construction/Inheritable Constructors
#######################################################

--------------

sub spawn {
    my $class =  shift;       # Store the package name
    my $self  =  { };
    bless($self, $class);     # Bless the reference into that package
    return $self;
}

--------------

$vermin = Critter->spawn;
$shelob = Spider->spawn;

--------------

$type  = "Spider";
$shelob = $type->spawn;         # same as "Spider"->spawn

--------------

sub spawn {
    my $invocant = shift;
    my $class    = ref($invocant) || $invocant;  # Object or class name
    my $self     = { };
    bless($self, $class);
    return $self;
}

###########################################
12:Objects/Object Construction/Initializers
###########################################

$steed = Horse->new(name => "Shadowfax", color => "white");

--------------

sub new {
    my $invocant = shift;
    my $class = ref($invocant) || $invocant;
    my $self = { @_ };          # Remaining args become attributes
    bless($self, $class);       # Bestow objecthood
    return $self;
}

--------------

sub new {
    my $invocant = shift;
    my $class   = ref($invocant) || $invocant;
    my $self = {
        color  => "bay",
        legs   => 4,
        owner  => undef,
        @_,                 # Override previous attributes
    };
    return bless $self, $class;
}

$ed       = Horse->new;                    # A 4-legged bay horse
$stallion = Horse->new(color => "black");  # A 4-legged black horse

--------------

$steed  = Horse->new(color => "dun");
$foal   = $steed->clone(owner => "EquuGen Guild, Ltd.");

sub clone {
    my $model = shift;
    my $self  = $model->new(%$model, @_);
    return $self;     # Previously blessed by ->new
}

############################
12:Objects/Class Inheritance
############################

package Horse;
our @ISA = "Critter";

--------------

$steed->move(10);

########################################################
12:Objects/Class Inheritance/Inheritance through C<@ISA>
########################################################

package Mule;
our @ISA = ("Horse", "Donkey");

--------------

package Mule;
use base ("Horse", "Donkey");   # declare superclasses

--------------

package Mule;
BEGIN {
    our @ISA = ("Horse", "Donkey");
    require Horse;
    require Donkey;
}

#########################################################
12:Objects/Class Inheritance/Accessing Overridden Methods
#########################################################

$stallion = Horse->new(gender => "male");
$molly = Mule->new(gender => "female");
$colt = $molly->breed($stallion);

--------------

$colt = Horse::breed($molly, $stallion);

--------------

$colt = $molly->Horse::breed($stallion);

--------------

package Mule;
our @ISA = qw(Horse Donkey);
sub kick {
    my $self = shift;
    print "The mule kicks!\n";
    $self->SUPER::kick(@_);
}

--------------

sub speak {
    my $self = shift;
    print "The mule speaks!\n";
    $self->Donkey::speak(@_);
}

--------------

package Bird;
use Dragonfly;
sub Dragonfly::divebomb { shift->SUPER::divebomb(@_) }

--------------

package Bird;
use Dragonfly;
{
    package Dragonfly;
    sub divebomb { shift->SUPER::divebomb(@_) }
}

###################################################################
12:Objects/Class Inheritance/UNIVERSAL: The Ultimate Ancestor Class
###################################################################

use FileHandle;
if (FileHandle->isa("Exporter")) {
    print "FileHandle is an Exporter.\n";
}

$fh = FileHandle->new();
if ($fh->isa("IO::Handle")) {
    print "\$fh is some sort of IOish object.\n";
}
if ($fh->isa("GLOB")) {
    print "\$fh is really a GLOB.\n";
}

--------------

if ($invocant->can("copy")) {
    print "Our invocant can copy.\n";
}

--------------

$obj->snarl if $obj->can("snarl");

--------------

sub snarl {
    my $self = shift;
    print "Snarling: @_\n";
    my %seen;
    for my $parent (@ISA) {
        if (my $code = $parent->can("snarl")) {
            $self->$code(@_) unless $seen{$code}++;
        }
    }
}

--------------

use Thread 1.0;   # calls Thread->VERSION(1.0)
print "Running version ", Thread->VERSION, " of Thread.\n";

--------------

use Data::Dumper;   
use Carp;
sub UNIVERSAL::copy {
    my $self = shift;
    if (ref $self) {
        return eval Dumper($self);  # no CODE refs
    } else {
        confess "UNIVERSAL::copy can't copy class $self";
    }
}

###############################################
12:Objects/Class Inheritance/Method Autoloading
###############################################

sub AUTOLOAD {
    return if our $AUTOLOAD =~ /::DESTROY$/;
    ...
}

--------------

if ($obj->can("methname") || $obj->can("AUTOLOAD")) {
    $obj->methname();
}

--------------

package Goblin;
sub kick;
sub bite;
sub scratch;

--------------

package Goblin;
use subs qw(kick bite scratch);

############################################
12:Objects/Class Inheritance/Private Methods
############################################

# declare private method
my $secret_door = sub {
    my $self = shift;
    ....
};

--------------

sub knock {
    my $self = shift;
    if ($self->{knocked}++ > 5) {
        $self->$secret_door();
    }
}

###############################
12:Objects/Instance Destructors
###############################

package MailNotify;
sub DESTROY {
   my $self = shift;
   my $fh   = $self->{mailhandle};
   my $id   = $self->{name};
   print $fh "\n$id is signing off at " . localtime() . "\n";
   close $fh;  # close pipe to mailer
}

--------------

sub DESTROY {
    my $self = shift;
    # check for an overridden destructor...
    $self->SUPER::DESTROY if $self->can("SUPER::DESTROY");
    # now do your own thing before or after
}

#################################
12:Objects/Managing Instance Data
#################################

sub get_name {
    my $self = shift;
    return $self->{name};
}

sub set_name {
    my $self      = shift;
    $self->{name} = shift;
}

--------------

$him = Person->new();
$him->set_name("Frodo");
$him->set_name( ucfirst($him->get_name) );

--------------

sub name {
    my $self = shift;
    if (@_) { $self->{name} = shift }
    return $self->{name};
}

--------------

$him = Person->new();
$him->name("Frodo");
$him->name( ucfirst($him->name) );

--------------

sub name {
    my $self = shift;
    my $field = __PACKAGE__ . "::name";
    if (@_) { $self->{$field} = shift }
    return $self->{$field};
}

#######################################################################
12:Objects/Managing Instance Data/Field Declarations with C<use fields>
#######################################################################

sub new {
    my $invocant = shift;
    my $class = ref($invocant) || $invocant;
    return bless [], $class;
}

--------------

sub name {
    my $self = shift;
    if (@_) { $self->[0] = shift }
    return $self->[0];
}

sub race {
    my $self = shift;
    if (@_) { $self->[1] = shift }
    return $self->[1];
}

sub aliases {
    my $self = shift;
    if (@_) { $self->[2] = shift }
    return $self->[2];
}

--------------

package Person;
use fields qw(name race aliases);

--------------

package Person;
use fields qw(name race aliases);
sub new {
    my $type = shift;
    my Person $self = fields::new(ref $type || $type);
    $self->{name} = "unnamed";
    $self->{race}  = "unknown;
    $self->{aliases} = [];
    return $self;
}
sub name {
    my Person $self = shift;
    $self->{name} = shift if @_;
    return $self->{name};
}
sub race {
    my Person $self = shift;
    $self->{race} = shift if @_;
    return $self->{race};
}
sub aliases {
    my Person $self = shift;
    $self->{aliases} = shift if @_;
    return $self->{aliases};
}
1;

--------------

package Wizard;
use base "Person";
use fields qw(staff color sphere);

--------------

my Wizard $mage = fields::new("Wizard");

--------------

$mage->name("Gandalf");
$mage->color("Grey");

--------------

$mage->{name} = "Gandalf";
$mage->{color} = "Grey";

##########################################################################
12:Objects/Managing Instance Data/Generating Classes with C<Class::Struct>
##########################################################################

package Person;
use Class::Struct;
struct Person => {    # create a definition for a "Person"
    name    => '$',   #    name field is a scalar
    race    => '$',   #    race field is also a scalar
    aliases => '@',   #    but aliases field is an array ref
};
1;

--------------

use Person;
my $mage = Person->new();
$mage->name("Gandalf");
$mage->race("Istar");
$mage->aliases( ["Mithrandir", "Olorin", "Incanus"] );

#######################################################################
12:Objects/Managing Instance Data/Generating Accessors with Autoloading
#######################################################################

use Person;
$him = Person->new;
$him->name("Aragorn");
$him->race("Man");
$him->aliases( ["Strider", "Estel", "Elessar"] );
printf "%s is of the race of %s.\n", $him->name, $him->race;
print "His aliases are: ", join(", ", @{$him->aliases}), ".\n";

--------------

package Person;
use Carp;

my %fields = (
    "Person::name"  => "unnamed",
    "Person::race"   => "unknown",
    "Person::aliases"  => [],
);

# The next declaration guarantees we get our own autoloader.
use subs qw(name race aliases);

sub new {
    my $invocant = shift;
    my $class = ref($invocant) || $invocant;
    my $self  = { %fields, @_ };    # clone like Class::Struct
    bless $self, $class;
    return $self;
}

sub AUTOLOAD {
    my $self = shift;
    # only handle instance methods, not class methods
    croak "$self not an object" unless ref($invocant);
    my $name = our $AUTOLOAD;
    return if $name =~ /::DESTROY$/;
    unless (exists $self->{$name}) {
        croak "Can't access `$name' field in $self";
    }
    if (@_) { return $self->{$name} = shift }
    else    { return $self->{$name} }
}

####################################################################
12:Objects/Managing Instance Data/Generating Accessors with Closures
####################################################################

package Person;

sub new {
    my $invocant = shift;
    my $self = bless({}, ref $invocant || $invocant);
    $self->init();
    return $self;
}

sub init {
    my $self = shift;
    $self->name("unnamed");
    $self->race("unknown");
    $self->aliases([]);
}

for my $field (qw(name race aliases)) {
    my $slot = __PACKAGE__ . "::$field";
    no strict "refs";          # So symbolic ref to typeglob works.
    *$field = sub {
        my $self = shift;
        $self->{$slot} = shift if @_;
        return $self->{$slot};
    };
}

####################################################################
12:Objects/Managing Instance Data/Using Closures for Private Objects
####################################################################

package Person;
sub new {
    my $invocant  = shift;
    my $class = ref($invocant) || $invocant;
    my $data = {
       NAME     => "unnamed",
       RACE     => "unknown",
       ALIASES  => [],
    };
    my $self = sub {
       my $field = shift;
       #############################
       ### ACCESS CHECKS GO HERE ###
       #############################
       if (@_) { $data->{$field} = shift }
       return    $data->{$field};
    };
    bless($self, $class);
    return $self;
}
# generate method names
for my $field (qw(name race aliases)) {
    no strict "refs";  # for access to the symbol table
    *$field = sub {
        my $self = shift;
        return $self->(uc $field, @_);
    };
}

--------------

use Carp;
local $Carp::CarpLevel = 1;  # Keeps croak messages short
my ($cpack, $cfile) = caller();

--------------

croak "No valid field `$field' in object"
    unless exists $data->{$field};

--------------

carp "Unmediated access denied to foreign file"
    unless $cfile eq __FILE__;

--------------

carp "Unmediated access denied to foreign package ${cpack}::"
    unless $cpack eq __PACKAGE__;

--------------

carp "Unmediated access denied to unfriendly class ${cpack}::"
    unless $cpack->isa(__PACKAGE__);

############################################
12:Objects/Managing Instance Data/New Tricks
############################################

package Critter;

sub new {
    my $class = shift;
    my $self = { pups => 0, @_ };    # Override default.
    bless $self, $class;
}

sub pups : lvalue {                  # We'll assign to pups() later.
    my $self = shift;
    $self->{pups};
}

package main;
$varmint = Critter->new(pups => 4);
$varmint->pups *= 2;                 # Assign to $varmint->pups!
$varmint->pups =~ s/(.)/$1$1/;       # Modify $varmint->pups in place!
print $varmint->pups;                # Now we have 88 pups.

--------------

sub pups : locked method {
    ...
}

##############################
12:Objects/Managing Class Data
##############################

Critter->population()       # Access via class name
$gollum->population()       # Access via instance

--------------

package Critter;
our $Population = 0;
sub population { return $Population; }
sub DESTROY { $Population-- }
sub spawn {
    my $invocant = shift;
    my $class = ref($invocant) || $invocant;
    $Population++;
    return bless { name => shift || "anon" }, $class;
}
sub name {
    my $self = shift;
    $self->{name} = shift if @_;
    return $self->{name};
}

--------------

our $Debugging = 0;     # class datum
sub debug {
    shift;              # intentionally ignore invocant
    $Debugging = shift if @_;
    return $Debugging;
}

--------------

{
    my $Debugging = 0;          # lexically scoped class datum
    sub debug {
        shift;       # intentionally ignore invocant
        $Debugging = shift if @_;
        return $Debugging;
    }
}

--------------

sub debug {
    my $invocant = shift;
    my $class   = ref($invocant) || $invocant;
    my $varname = $class . "::Debugging";
    no strict "refs";       # to access package data symbolically
    $$varname = shift if @_;
    return $$varname;
}

##############
13:Overloading
##############

print $object->as_string;
$new_object = $subject->add($object);

--------------

print $object;
$new_object = $subject + $object;

#####################################
13:Overloading/The C<overload> Pragma
#####################################

package MyClass;

use overload   '+' => \&myadd,            # coderef
               '<' => "less_than";        # named method
             'abs' => sub { return @_ },  # anonymous subroutine

################################
13:Overloading/Overload Handlers
################################

package ClipByte;

use overload '+' => \&clip_add,
             '-' => \&clip_sub;

sub new {
    my $class = shift;
    my $value = shift;
    return bless \$value => $class;
}

sub clip_add {
    my ($x, $y) = @_;
    my ($value) = ref($x) ? $$x : $x;
    $value     += ref($y) ? $$y : $y;
    $value = 255 if $value > 255;
    $value =   0 if $value < 0;
    return bless \$value => ref($x);
}

sub clip_sub {
    my ($x, $y, $swap) = @_;
    my ($value) = (ref $x) ? $$x : $x;
    $value     -= (ref $y) ? $$y : $y;
    if ($swap) { $value = -$value }
    $value = 255 if $value > 255;
    $value =   0 if $value < 0;
    return bless \$value => ref($x);
}

package main;

$byte1 = ClipByte->new(200);
$byte2 = ClipByte->new(100);

$byte3 = $byte1 + $byte2;    # 255
$byte4 = $byte1 - $byte2;    # 100
$byte5 = 150 - $byte2;       # 50

#####################################
13:Overloading/Overloadable Operators
#####################################

package Person;

use overload q("") => \&as_string;

sub new {
    my $class = shift;
    return bless { @_ } => $class;
}

sub as_string {
    my $self = shift;
    my ($key, $value, $result);
    while (($key, $value) = each %$self) {
        $result .= "$key => $value\n";
    }
    return $result;
}

$obj = Person->new(height => 72, weight => 165, eyes => "brown");

print $obj;

--------------

package ShiftString;

use overload
    '>>' => \&right_shift,
    '""' => sub { ${ $_[0] } };

sub new {
    my $class = shift;
    my $value = shift;
    return bless \$value => $class;
}

sub right_shift {
    my ($x, $y) = @_;
    my $value = $$x;
    substr($value, -$y) = "";
    return bless \$value => ref($x);
}

$camel = ShiftString->new("Camel");
$ram = $camel >> 2;
print $ram;            # Cam

--------------

package MagicDec;

use overload
    q(--) => \&decrement,
    q("") => sub { ${ $_[0] } };

sub new {
    my $class = shift;
    my $value = shift;
    bless \$value => $class;
}

sub decrement {
    my @string = reverse split(//, ${ $_[0] } );
    my $i;
    for ($i = 0; $i < @string; $i++ ) {
        last unless $string[$i] =~ /a/i;
        $string[$i] = chr( ord($string[$i]) + 25 );
    }
    $string[$i] = chr( ord($string[$i]) - 1 );
    my $result = join('', reverse @string);
    $_[0] = bless \$result => ref($_[0]);
}

package main;

for $normal (qw/perl NZ Pa/) {
    $magic = MagicDec->new($normal);
    $magic--;
    print "$normal goes to $magic\n";
}

--------------

package LuckyDraw;
use overload
    '<>' => sub {
                my $self = shift;
                return splice @$self, rand @$self, 1;
            };
sub new {
    my $class = shift;
    return bless [@_] => $class;
}
package main;
$lotto = new LuckyDraw 1 .. 51;
for (qw(1st 2nd 3rd 4th 5th 6th)) {
    $lucky_number = <$lotto>;
    print "The $_ lucky number is: $lucky_number.\n";
}
$lucky_number = <$lotto>;
print "\nAnd the bonus number is: $lucky_number.\n";

--------------

package PsychoHash;

use overload '%{}' => \&as_hash;

sub as_hash {
    my ($x) = shift;
    return { @$x };
}

sub new {
    my $class = shift;
    return bless [ @_ ] => $class;
}

$critter = new PsychoHash( height => 72, weight => 365, type => "camel" );

print $critter->{weight};   # prints 365

--------------

use overload '+' => sub { bless [ \$_[0], \$_[1] ] };

##########################################
13:Overloading/The Copy Constructor (C<=>)
##########################################

$copy = $scalar_ref;
++$$copy;             # changes $$scalar_ref

--------------

$copy = $scalar_ref;
$copy = $copy + 1;

--------------

$copy = $scalar_ref;
...
++$copy;

--------------

$copy = $scalar_ref;
...
$copy = $copy->clone(undef, "");
$copy->incr(undef, "");

####################################
13:Overloading/Overloading Constants
####################################

sub import { overload::constant ( integer => \&integer_handler,
                                  float   => \&float_handler,
                                  binary  => \&oct_and_hex_handler,
                                  q       => \&string_handler,
                                  qr      => \&regex_handler ) }

--------------

$year = cube(12) + 1;
$pi   = 3.14159265358979;

--------------

package DigitDoubler;    # A module to be placed in DigitDoubler.pm
use overload;

sub import { overload::constant ( integer => \&integer_handler,
                                  float   => \&float_handler ) }

sub integer_handler {
    my ($orig, $interp, $context) = @_;
    return $interp * 2;          # double all constant integers
}

1;

--------------

use DigitDoubler;

$trouble = 123;      # trouble is now 246

###################################
13:Overloading/Run-time Overloading
###################################

eval " use overload '+' => \&my_add ";

--------------

eval " no overload '+', '--', '<=' ";

###############################
14:Tied Variables/Tying Scalars
###############################

#!/usr/bin/perl
package Centsible;
sub TIESCALAR { bless \my $self, shift }
sub STORE { ${ $_[0] } = $_[1] }  # do the default thing
sub FETCH { sprintf "%.02f", ${ my $self = shift } } # round value

package main;
tie $bucks, "Centsible";
$bucks = 45.00;
$bucks *= 1.0715; # tax
$bucks *= 1.0715; # and double tax!
print "That will be $bucks, please.\n";

####################################################
14:Tied Variables/Tying Scalars/Scalar Tying Methods
####################################################

use ScalarFile;       # load ScalarFile.pm
tie $camel, "ScalarFile", "/tmp/camel.lot";

--------------

$dromedary = $camel;

--------------

$dromedary = (tied $camel)->FETCH():

--------------

$clot = tie $camel, "ScalarFile", "/tmp/camel.lot";
$dromedary = $camel;          # through the implicit interface
$dromedary = $clot->FETCH();  # same thing, but explicitly

--------------

package ScalarFile;
use Carp;                # Propagates error messages nicely.
use strict;              # Enforce some discipline on ourselves.
use warnings;            # Turn on lexically scoped warnings.
use warnings::register;  # Allow user to say "use warnings 'ScalarFile'".
my $count = 0;           # Internal count of tied ScalarFiles.

--------------

sub TIESCALAR {           # in ScalarFile.pm
    my $class    = shift;
    my $filename = shift;
    $count++;             # A file-scoped lexical, private to class.
    return bless \$filename, $class;
}

--------------

sub TIESCALAR { bless \$_[1], $_[0] }    # WRONG, could refer to global.

--------------

sub TIESCALAR {           # in ScalarFile.pm
    my $class    = shift;
    my $filename = shift;
    my $fh;
    if (open $fh, "<", $filename or
        open $fh, ">", $filename)
    {
        close $fh;
        $count++;
        return bless \$filename, $class;
    }
    carp "Can't tie $filename: $!" if warnings::enabled();
    return;
}

--------------

tie ($string, "ScalarFile", "camel.lot") or die;

--------------

sub FETCH {
    my $self  = shift;
    confess "I am not a class method" unless ref $self;
    return unless open my $fh, $$self;
    read($fh, my $value, -s $fh);  # NB: don't use -s on pipes!
    return $value;
}

--------------

tie($string, "ScalarFile", "camel.lot");
print $string;

--------------

sub STORE {
    my($self,$value) = @_;
    ref $self                   or confess "not a class method";
    open my $fh, ">", $$self    or croak "can't clobber $$self: $!";
    syswrite($fh, $value) == length $value
                                or croak "can't write to $$self: $!";
    close $fh                   or croak "can't close $$self: $!";
    return $value;
}

--------------

tie($string, "ScalarFile", "camel.lot");
$string  = "Here is the first line of camel.lot\n";
$string .= "And here is another line, automatically appended.\n";

--------------

sub DESTROY {
    my $self = shift;
    confess "wrong type" unless ref $self;
    $count--;
}

--------------

sub count {
    # my $invocant = shift;
    $count;
}

--------------

if (ScalarFile->count) {
    warn "Still some tied ScalarFiles sitting around somewhere...\n";
}


Tuesday, April 17, 2012

Looping through list in SQL


If we have a comma separated list and the requirement is to loop through the list of items one by one or to pass these items to a stored procedure. The easiest and simple way to do this is given below with coments.

--comma separated list
Declare @S varchar(20)
set @S ='abc,def,ghi,jkl' 


--loop through each item
while len(@S) > 0
Begin

--get the first item form the list
declare @S1 varchar(20)
set @S1 = left(@S, charindex(',' , @S+',')-1)

--Print it
Print @S1

--Delete the item from the list
set @S = Stuff(@S,1,charindex(',',@S+','),'')

End


Wednesday, April 11, 2012

TRANSACTION and Error Handling


Transactions are very useful when you are not sure if there could be a error or not. And if there is a error, the set of sql statements need not be executed or needs to be rolled back.In this case we can TRANSACTIONS that help us to ROLLBACK if there was any error while executing the sql statements.

The below example also shows simple error handling. If there is any error while updating the table then control is passed on to the CATCH block and the TRANSACTION is rolled back.

USE [PUBS]
GO

DECLARE @iError int

BEGIN TRANSACTION

    UPDATE table
    SET column = 'value'
    WHERE column = 'condtion'
   
    select @iError = @@ERROR
    IF (@iError <> 0) GOTO CATCH
   
COMMIT TRANSACTION

CATCH:
IF(@iError <> 0)
BEGIN
    PRINT 'Error message'
    ROLLBACK TRANSACTION
END