Mar

Very little is needed to make a happy life; it is all within yourself, in your way of thinking. I’ve learned that asking questions isn’t a sign of weakness; rather, it demonstrates curiosity, engagement and intelligence."

Kerala Flood

...

Menu




PERL

Perl Quick Reference

The first step in learning to program is to teach the computer to say hello. With Perl, this is incredibly straightforward: you simply tell perl to execute the following code:
say "Hello World!"
The obvious question is: "How do I 'tell perl' to execute this code?" Depending on your operating system, you might need to download and install the 'perl' interpreter — a program which executes Perl code. (Note: uppercase "Perl" refers to the programming language while the lowercase "perl" means the interpreter itself.)
First, you should see if you already have perl installed and what version it is.
You'll need to open a command-line terminal. On OS X, use the finder to launch Applications -> Utilities -> Terminal. On Ubuntu, this is Applications -> Accessories -> Terminal. On Windows, click Start -> Run, typecmd into the prompt, and click OK.


At the command-line, type perl --version, hit Enter, and see if you get some output with a version number. If you get something like 'perl' is not recognized... or perl: command not found, or your version is less than 5.10.0, then you'll need to download and install perl.
With perl 5.10 installed, you may now rush headlong into programming by running:
  perl -E "say 'Hello World!'"
If your computer is a Mac or an older Linux distribution, you might already have perl 5.8.8 installed. This is a fine version of perl, but lacking some nice features which are only available in 5.10, starting with the sayfunction and the -E option!
Before 5.10, this sort of thing would have been done with -e and print:
 perl -e 'print "Hello World!\n"' 
This will still work in perl 5.10 (try it!) because new versions of Perl 5 never remove features. It also introduces the newline character and an important detail about quoting strings.
Now run the same command without the \n and see what happens.
 perl -e 'print "Hello World!"' 
The output gets crowded by the new prompt because it has no final newline. (Tip: Hit Ctrl+C to get a fresh, uncrowded prompt in your terminal.)
This is called string interpolation, where double-quoted strings do nifty things like translating backslashed characters into some special kind of output.
Another fun example (until your coworkers get upset) is print "\a" — the \a is the "bell" character (it makes your terminal beep.)
Notice that the say command in 5.10 is the same as print except it includes the newline for you (not to mention being slightly shorter and more conversational.) The capital -E (instead of -e) tells perl that you intend to use say and other 5.10-only features in your program.


Aside: Windows users will need to write this slightly differently due to the way in which the Windows cmd shell deals with quoting. In Windows, the command-line does not treat the single quote (') as a quote, so everything must be in double quotes ("). But, Perl has a way around this by using the qq{...} operator.
  perl -e "print qq{Hello World\n}"

Your First Perl Program

Once you have run these examples, you have actually just written your first program in Perl. The -E switch allows you to write complete programs directly at the command-line, but hassles with quoting can get in the way (as we saw earlier) and it is difficult to refer back to this "program" tomorrow. For longer-lived programs, it is much more convenient to save your code in a file.
To save a Perl script, you create a plain text file containing Perl code. You'll want to start a text editor now. (Note that a "word processor" is not what you want.)
If you're running Windows, click Start -> Programs -> Accessories -> Notepad. OS X users can useApplications -> TextEdit, but remember to click the menu Format -> Make Plain Text. On Linux, look for geditor kwrite in your launcher menu.
Now type the following program into your editor and save it as hello.pl.
  #!/usr/bin/env perl

  use v5.10.0;
  use warnings;
  use strict;

  say "Hello World!";
Once you have saved the program, tell perl to run it:
  perl hello.pl
Now we're running the perl interpreter by telling it the name of the program to run. We also have three new 'use' statements which you'll include in all of your programs. The first, use v5.10.0 tells Perl that you want all of the features of 5.10.0 (and notifies an earlier perl such as 5.8.8 that it is not modern enough to understand this code.) The use strict and use warnings statements help catch typos and other simple programming errors. By starting all of your Perl programs this way, you let perl make your life easier.

Shebang!

Notice that our program starts with what is called the "shebang" line. This is a special kind of comment on the first line which tells the operating system that this is a Perl program (except on windows.) By including the shebang line and setting the executable bit (chmod +x hello.pl), you turn the plaintext file into an executable program. Now you don't need to include 'perl' on the command line to run the program (but you do need to use ./ to reference it unless this program is in a directory in your $PATH.



Congratulations! You've just created and executed your first Perl program. You also learned how to write short programs directly on the command line, a bit about your command-line shell, and quoted strings. Now you have everything you need to begin programming in Perl.


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

What Is a Module?

Modules are an important and powerful part of the Perl programming language. A module is a named container for a group of variables and subroutines which can be loaded into your program. By naming this collection of behaviors and storing it outside of the main program, you are able to refer back to them from multiple programs and solve problems in manageable chunks.
Modular programs are more easily tested and maintained because you avoid repeating code, so you only have to change it in one place. Perl modules may also contain documentation, so they can be used by multiple programmers without each programmer needing to read all of the code. Modules are the foundation of the CPAN, which contains thousands of ready-to-use modules, many of which you will likely use on a regular basis.

Exploring Existing Modules

Before you begin writing your own modules, you need to know how to use modules and how perl finds modules to load. The Perl core distribution comes with many useful modules, so we'll take one called Digest::MD5 as an example and see how to use it.


Using your terminal, run the command `perldoc Digest::MD5`. You should see something like the picture. What you see there is the documentation for the Digest::MD5 module. Notice the example:
  use Digest::MD5 'md5_hex';
  ...
  $digest = md5_hex($data);

About the MD5 Digest

The MD5 algorithm is a cryptographic hash function, meaning that it reliably generates a fixed-length "fingerprint" given arbitrarily large data as input. Further, the fingerprint cannot easily be generated from someother input, which makes this fingerprint very useful in login systems. When you implement a login system (such as a user on a website or a multi-user computer), you want the user to know their password, but it's best if that password isn't left lying around somewhere on the computer where others might find it. A cryptographic hash like the MD5 digest is a way to verify that the user's password is correct without storing it. You store adigest of Jim's password. When Jim tries to login, compare a digest of the password he types to the one you have stored. Because the digest is irreversible, anyone who gets access to your password file or database will not be able to simply login as Jim.
Aside: This algorithm is also a good example of why modules are important. When your code uses theDigest::MD5 module, you know that it will always create MD5 digests in the same way. Without modules, different programs might contain duplicate code or various re-implementations of the algorithm.

Loading Modules

You may now need to hit the 'q' key to exit the perldoc viewer. Note that the documentation contains a description of the module, examples of how to use it, and an overview of what it does.
Most module documentation will include an example section like this which shows a typical use statement. The use command tells perl to find and load the module named Digest::MD5 and then to invokeDigest::MD5->import('md5_hex'). That import() installs the function Digest::MD5::md5_hex into your current program. Open your text editor and create the following md5sum.pl file.
  #!/usr/bin/env perl

  use v5.10.0;
  use warnings;
  use strict;

  use Digest::MD5 'md5_hex';

  say md5_hex("somethingsomething");
Now try running it. On a unix-like system, you should also have a binary named 'md5sum' available. Notice how the outputs of our md5sum.pl and the system command are the same (except that the system md5sum outputs a '-' representing the "filename" of the piped-in data.)


Behind the Curtain

When you use a module, perl is following a built-in plan for how to find and load the correct package. The first thing it does is to search for a .pm ("Perl Module") file in the directories listed in the global @INC array. Let's print that array and see what it contains. (Yours will likely be different than mine.)
  $ perl -E 'say for @INC'
  /usr/local/lib/perl/5.10.0
  /usr/local/share/perl/5.10.0
  /usr/lib/perl5
  /usr/share/perl5
  /usr/lib/perl/5.10
  /usr/share/perl/5.10
  /usr/local/lib/site_perl
  .
The @INC array is set when perl is compiled, but can be altered by the program, with the -I command-line switch, or by the PERL5LIB environment variable.
  $ PERL5LIB=also perl -Ilib -E 'say for @INC'
  lib
  also
  /usr/local/lib/perl/5.10.0
  /usr/local/share/perl/5.10.0
  /usr/lib/perl5
  /usr/share/perl5
  /usr/lib/perl/5.10
  /usr/share/perl/5.10
  /usr/local/lib/site_perl
  .
When we say use Digest::MD5, perl starts at the first @INC entry and searches for a Digest/MD5.pm file. Note that module names are always written with '::' separators in code, but on your filesystem this becomes the directory separator (e.g. '/'.)
If there are more Digest/MD5.pm files later in @INC, perl will simply ignore them. This masking effect allows you to install a newer version of a module which will take precedence over the one shipped with Perl.
Once perl finds and loads your module, it stores the full filename for the loaded module in the global %INChash. You can look in this hash to see which file was loaded (very handy when you want to read the module's source code.)
  $ perl -MDigest::MD5 -E 'say $INC{"Digest/MD5.pm"}'
  /usr/lib/perl/5.10/Digest/MD5.pm

Creating a Login System

If we're building a login system, one thing we'll need is a password data file which contains a login and hashed-password for each valid user. Use your editor to create the file 'passwords' with a 'jim' user and our md5_hex output for the password 'somethingsomething'.


Now we need some code to challenge a user to login and check whether they are 1) a valid user and 2) know the correct password.
  #!/usr/bin/env perl

  use v5.10.0;
  use warnings;
  use strict;

  use Digest::MD5 'md5_hex';

  open(my $fh, '<', 'passwords') or die "cannot open passwords file $!";
  my %passwords = map({chomp; split(/:/, $_, 2)} <$fh>);

  my $user;
  while (1) {
    print "Username: ";
    chomp($user = <>);
    print "Password: ";
    chomp(my $pass = <>);

    # they must be a valid user and
    # their digested password must match the stored digest
    last if(
      $passwords{$user} and
      md5_hex($pass) eq $passwords{$user}
    );

    # otherwise, we're stuck in the loop
    say "Sorry!";
  }

  say "Congratulations $user!";
If the openmapchompsplit, and <> constructs are new to you, review the (todo: link) Text Processing Tutorial. The important thing to note here is that we have created a loop which will continue prompting until the user enters a correct login.


Now, we have created some behavior which will be useful to reuse: loading the password file and verifying a username/password. We want to package this whole idea into a module so it can be used whenever we need to check a user's credentials.
First, your module needs somewhere to live. Create a directory named lib/TestSite.
  $ mkdir -p lib/TestSite
Then use your editor to create the file lib/TestSite/Login.pm.
  package TestSite::Login;
  $VERSION = v0.0.1;

  use v5.10.0;
  use warnings;
  use strict;
  use Carp;

  use Digest::MD5 'md5_hex';

  open(my $fh, '<', 'passwords') or die "cannot open passwords file $!";
  my %passwords = map({chomp; split(/:/, $_, 2)} <$fh>);

  sub check_password {
    my ($user, $pass) = @_;

    return(
      $passwords{$user} and
      md5_hex($pass) eq $passwords{$user}
    );
  }

  1;
The module consists of a few more lines of declaration. First, we have the package statement, which declares the namespace of this module. The package name should match the file path (with the '/' exchanged for '::'.) Second, we have a $VERSION number, which every package should have (this helps when it comes time to deploy your code into the world.) After the version, we have the same set of use lines as our scripts, but we also include the Carp module, which helps with debugging. Jumping to the very end, every module must end in a true value (this satisfies a sanity check when it is loaded.)
Aside from the declarations, we've also migrated some code from the main program and changed the 'die' statement to croak() (this comes from the Carp module.) The only other change is to put our password-checking code into the check_password() subroutine.
Now we need to make some changes to our login.pl code to use this new module. We'll make a modification and name it login2.pl.
  #!/usr/bin/perl

  use v5.10.0;
  use warnings;
  use strict;

  use TestSite::Login;

  my $user;
  while (1) {
    print "Username: ";
    chomp($user = <>);
    print "Password: ";
    chomp(my $pass = <>);

    last if(TestSite::Login::check_password($user, $pass));

    # otherwise, we're stuck in the loop
    say "Sorry!";
  }

  say "Congratulations $user!";
Notice that we've removed the use Digest::MD5 ... line, because our new TestSite::Login module takes care of all of that.
When we run the new login2.pl, we need to tell perl to also look for modules in our lib directory so it will findlib/TestSite/Login.pm. You can install your module in one of the global @INC directories, but it is more convenient to use the -I switch when developing modules.


Now you have the same behavior as the original login.pl program, but the login2.pl program is shorter and focussed on the prompting while the TestSite::Login module is handling the details about how to validate a username and password. Even though we only use the TestSite::Login module in one program, it clarifies the code by separating the ideas and makes it easier to maintain. As you take on bigger programming challenges, modularizing behaviors helps to organize and simplify your code, while also allowing you to reuse it as needed.

--------------------------------------------------------------------------------------------------------------------------------------------------
How you configure and manage your Perl installation depends on your operating system, Perl version, and your work environment. A team building a publicly deployed application will often need a different configuration than your personal workstation or a shared web hosting environment.
This article covers the ins and outs of installing perl modules and configuring your installation.
  • The CPAN
  • CPAN Clients
  • Installing One or More Perls
  • Module Management with local::lib
  • Further Reading
  • Common Problems

The CPAN

The Comprehensive Perl Archive Network (CPAN) is a collection of freely available Perl modules contributed by thousands of authors. It is mirrored on hundreds of servers around the world. If you are trying to accomplish a common task in Perl, it is likely that someone else has already made a module which does most of the work for you. You simply have to find it and install it.

Distributions

Packages on the CPAN are called distributions, which are "tarballs" (.tar.gz archives) containing Perl modules and scripts, as well as build tools, documentation, tests, and license information. A distribution may contain just one module, or a set of modules.
A distribution may require modules from other distributions, either as part of its implementation or to extend another module's functionality. These are referred to as dependencies. Rather than rewriting code, module authors can simply reuse existing code from other modules. This helps reduce complexity and bugs (for you and the module authors) by organizing code into well-tested, reusable components. However, module A might depend on B, which depends on C, D, and E. This makes installation slightly more complicated, but there are tools to deal with that.

The Standard Build Process

A distribution on the CPAN comes with a Build.PL file (or Makefile.PL), which knows how to examine your system, check whether dependencies are satisfied, and generate a build file. The generated Build file (orMakefile) can then be used to build, test, and install the distribution's modules, scripts, documentation, and data.
Note: you will usually not need to go through this process manually (we'll get to that in the section on CPAN clients), but knowing how it all works will help when things go wrong.
If you download a distribution tarball from the CPAN and unpack it (tar -xzvf Foo-0.01.tar.gz, then cd Foo-0.01), the typical installation process is:
  perl Build.PL
  ./Build
  ./Build test
  ./Build install
Note: on Windows, use the backslash (.\Build) instead.
Or, if you only have a Makefile.PL:
  perl Makefile.PL
  make
  make test
  make install

The 4 Steps

perl Build.PL

This checks for dependencies, compatibility, and will print error messages if anything is wrong or missing. It may also print messages about optional dependencies (which would enable extra features for the module.) If something goes wrong at this point, you need to resolve the problem before continuing. In severe cases, the Build.PL script will refuse to create a Build file.

./Build

This step compiles any XS-based extension modules and does whatever heavy lifting is needed. In simple cases, it just copies some files into the ./blib/ "staging area" directory. When this step is complete, the files in ./blib/ are exactly what will be installed on your system.

./Build test

This is the all-important step where we find out if the code actually works. (You did want the code to work, right?) This will run all of the *.t files in the distribution's t/ directory. Testing verifies that the code works on your system and works as the author intended.
Most distributions will at least do a use Foo test to check for syntax errors or crippling problems. Many will have a full battery of tests which exercise the module's functionality. Some even have extra tests, which can optionally run more exhaustive tests, or test code which accesses a database, network connection, modem, etc.
For more info, see Test::Harness and the distribution's README file.

./Build install

Once the tests pass, you're ready to install the module to its permanent home. This copies the files from the./blib/ staging area into appropriate places — .pm files go in @INC, scripts in $PATH, and so on. Arguments given to perl Build.PL step (such as --installdirs=site) and settings from when your perl was built will control the exact locations.
You may need to run `sudo ./Build install` or set appropriate write permissions for the installation path.
For further reading, see the perldoc for perlmod, perlmodinstall, and perlmodlib.

External Dependencies

Some Perl modules depend on external libraries (such as the C libraries expat or libxml) which need to be installed before the module can be compiled. In some cases, the module will depend on a package in theAlien:: namespace — a special kind of distribution designed to automatically fulfill the dependency for you using the standard build process described above. But if you run the perl Build.PL step and get a message like "missing such-and-such library", you'll have to handle it yourself.
For debian/ubuntu, you can usually find and install the library in Synaptic (or aptitude). Look for a package named "lib$foo-dev", or "$foo-dev". Redhat systems would call it "lib$foo-devel". OS X users can use MacPorts or Fink. If you don't have prebuilt packages available for the library, you need to find the source, download it, run configure, make, and so on. Don't panic. The perl module's README or INSTALL file should have details about this sort of thing when necessary.

CPAN Clients

The four-step process is pretty simple, but actually has some hidden steps in the beginning where you find and download the distribution, unpack it, and cd into its directory. This can get especially tedious when the distribution has a dependency, which has a dependency, which has a dependency, and so on. This sounds like a job for the computer! A CPAN client is a program which knows how to fetch distributions from the CPAN and figure out all of their dependencies. Then it runs our 4-step process to build, test, and install everything while you check your mail and drink coffee.

CPAN

The cpan client comes with the core Perl distribution and is probably already installed on your system. But, it probably needs an upgrade if you are running an old Perl or are using the perl that came with your system. If you have installed perl 5.10 or newer, the client is ready to go with minimal configuration.
If you have an old cpan client, it may be easiest to download a tarball from the CPAN, unpack that, and go through the 4-step process. Upgrading from an old client can be painless if it is configured correctly and nearly impossible otherwise.

Client Configuration

The cpan program has an interactive shell for configuration, searching, and other functionality. When you run`cpan` at your terminal with no extra arguments, it starts in this interactive mode.
The first time you run the client, it starts by explaining its purpose and prompting you for configuration:
  $ cpan
  CPAN is the world-wide archive of perl resources. It ...

  If you prefer to enter a dialog instead, you can answer 'no' ...
  Would you like me to configure as much as possible automatically? [yes]
(Note that I have trimmed the output with '...' to keep this page short.)
When you hit 'Enter' here, the client will go through a series of checks and figure out how to operate on your system.
  ...
  Autoconfigured everything but 'urllist'.
  Please call 'o conf init urllist' to configure your CPAN server(s) now!

  commit: wrote '/home/yournamehere/CPAN/MyConfig.pm'

  cpan shell -- CPAN exploration and modules installation (v1.9402)
  Enter 'h' for help.

  cpan[1]> 
Now you're at the interactive prompt. Note that it prints out the location of your new config file. But you still need to select a mirror of the CPAN. You can simply step through the prompts and then pick a mirror.
  cpan[1]> o conf init urllist

  Now we need to know where your favorite CPAN sites are located.
  ...

  First, pick a nearby continent and country ...
  ...
  (6) North America
  ...
  Select your continent (or several nearby continents) [] 6

  ...
  (4) United States
  Select your country (or several nearby countries) [] 4

  (1) ftp://cpan-du.viaverio.com/pub/CPAN/
  ...
  38 more items, hit RETURN to show them
  ...
  (37) http://cpan.develooper.com/
  Select as many URLs as you like (by number),
  put them on one line, separated by blanks, hyphenated ranges allowed
   e.g. '1 4 5' or '7 1-4 8' [] 37

  Enter another URL or RETURN to quit: []
  New urllist
    http://cpan.develooper.com/

  Please remember to call 'o conf commit' to make the config permanent!
We're back at the prompt again, but the client did not write the config file!
  cpan[2]> o conf commit
  commit: wrote '/home/yournamehere/CPAN/MyConfig.pm'
Now you probably need to change a couple of important settings before trying to build anything. If your perl is installed in /usr/local, your non-root user does not have permission to write files there. So, you can configure the client to be root only when installing. (You won't need this setting if you installed a "personal" perl in your home directory.)
  cpan[3]> o conf make_install_make_command 'sudo /usr/bin/make'
    make_install_make_command [sudo /usr/bin/make]
  Please use 'o conf commit' to make the config permanent!

  cpan[4]> o conf mbuild_install_build_command 'sudo ./Build'
    mbuild_install_build_command [sudo ./Build]
  Please use 'o conf commit' to make the config permanent!
Note that it is still pestering us about this 'commit' business. Well, we can just make that automatic, so that whenever we change the configuration it immediately writes it to the config file.
  cpan[5]> o conf auto_commit 1
    auto_commit        [1]
  commit: wrote '/usr/local/share/perl/5.8.8/CPAN/Config.pm'
Another important setting is whether or not to prompt you about dependencies. It's best if the client just installs whatever a module needs. This way, when you come back from reading your mail it isn't sitting there waiting for you to answer "should I install some stuff so this will actually work?".
  cpan[6]> o conf prerequisites_policy follow
    prerequisites_policy [follow]
  commit: wrote '/usr/local/share/perl/5.8.8/CPAN/Config.pm'
Finally, we can use the client to install a module.
  cpan[7]> install Foo
  Fetching with LWP: ...

Everyday Usage

To install one or more modules from the CPAN, you can simply invoke the client with the names of the modules you want installed:
  $ cpan Foo Bar Baz

Tips

Upgrade the Tools

Code on the CPAN changes every day, but huge improvements to how the build tools work have happened since perl 5.8.8 came out. If you're running an older perl, you should at least upgrade your CPAN,ExtUtils::MakeMaker and Module::Build to the latest versions from the CPAN. This will ensure that everything works as-intended with current CPAN distributions.
You might notice that CPAN informs you at startup when a new version is available. When you see this, it is time to upgrade. You can upgrade the CPAN client by simply running 'install CPAN' from inside the cpan shell.

Install Bundle::CPAN

Installing the Bundle::CPAN distribution will add a lot of nice functionality to CPAN.pm.

Don't run cpan as root!

Use sudo only to install. It's possible for a test to make a mistake which deletes your entire filesystem (and maybe didn't affect the author.) This sort of thing is rare, but you don't want to risk it, so only use sudo for the installation phase — when you actually need root permissions to install the code. If you have previously runcpan as root or as sudo cpan, you might need to reconfigure or chown -R your ~/.cpan/ directory so you can use it again.

prefer_installer MB

If you upgraded from an older CPAN.pm, make sure your prefer_installer is set to 'MB'. This means that when a distribution has both Makefile.PL and Build.PL build tools that the client will use the Build.PL-based process. When a distribution has both, the Makefile.PL is actually only a wrapper on Build.PL to try to help the new system be compatible with old clients. Unfortunately, a series of old CPAN.pm versions would default this to 'MM' and if you had one of those once, it is still set that way. The default in a freshly installed CPAN.pm is 'MB'.
  cpan[1]> o conf prefer_installer MB
    prefer_installer   [MB]

o conf init whatever

You can run 'o conf' at the interactive shell (or read the config file) to see all of your client's settings. Running 'o conf init' would take you through the whole configuration process again, but 'o conf init whatever' will give you an explanation of the whatever setting and show you the options for it. Unfortunately, it doesn't tell you the factory default (the prompt default is now the current value from your config file.) If you want to get the factory defaults from your newly installed version, rename your config file and then run through the init process again.

CPAN::Mini

The CPAN::Mini module makes it possible to have a small local mirror of the CPAN, updated to have only the latest tarball of every module. This is nice to have on your laptop if you're working on an airplane or with spotty internet access. It also saves downloading time if you are installing modules on multiple computers in your network.

CPANPLUS

The cpanp client (in the CPANPLUS distribution) is a newer option which offers more configurable and advanced functionality over the venerable CPAN.pm.

Installing One or More Perls

If you have a large or important codebase, it's best to maintain your own perl installation rather than using whatever came with the system. An OS distribution (like RedHat, Debian, or OS X) often has made subtle changes to their 'perl' which may not be best for your uses. You should keep the system perl as-is because scripts that came with the system are tested only against the vendor's version. Install your own/usr/local/bin/perl, or even put it under a numbered 'prefix' such as /usr/local/perl-5.10.1/.
To install perl under a custom 'prefix', just run Configure with e.g. -Dprefix=/usr/local/perl-5.10.1/. See the installation howto for details.
Many CPAN developers keep a few different versions of perl on their machine for testing purposes. If you are writing C-based extensions, you'll want to build a debugging-enabled perl for running with gdb.
When your team is preparing to upgrade your product to a new perl version, it is good to be able to test the new version alongside the old one. Then you can just change the environment's $PATH to point at the new perl when everything is ready for the switch. It is much simpler to manage upgrades if you have a/usr/local/perl-5.8.8/bin/perl and /usr/local/perl-5.10.1/bin/perl, even for multiple codebases on different schedules.

Module Management with local::lib

The local::lib module is a way to create and use a tree of modules outside of perl's builtin @INC paths. It does this by setting some variables in your environment to adjust the installation targets and sets PERL5LIBaccordingly. This can be setup in your shell to make cpan install code under your home directory. It is very useful for shared hosting environments where you only have write access in your home directory, or other cases where you want to keep code from the CPAN in a specific place.
If you want to build a tree under ~/.perl (a hidden path under your home directory), download the tarball forlocal::lib, unpack it, and run its bootstrap setup as follows:
  $ perl Makefile.PL --bootstrap=~/.perl
  $ make test && make install

  $ echo 'eval $(perl -I$HOME/.perl/lib/perl5 -Mlocal::lib=$HOME/.perl)' >> ~/.bashrc
This last command adds the environment setup to your ~/.bashrc (which is run whenever you login.) You need to restart your shell (or source ~/.bashrc) to get your shell ready to run cpan with the new environment.
To see how this works, examine the pieces. The eval is a bash construct which is similar to Perl'seval($string), and the $() construct is the bash capture-output operator (like Perl's qx() or backticks). So this runs local::lib's import() method (see perlrun for -I and -M), which prints some bash code. If you run just the perl part, you can see how the sausage is made:
  $ perl -I$HOME/.perl/lib/perl5 -Mlocal::lib=$HOME/.perl/lib/perl5
  export MODULEBUILDRC="/home/you/.perl/lib/perl5/.modulebuildrc"
  export PERL_MM_OPT="INSTALL_BASE=/home/you/.perl/lib/perl5"
  export PERL5LIB="/home/you/.perl/lib/perl5/lib/perl5:$PERL5LIB"
  export PATH="/home/you/.perl/lib/perl5/bin:$PATH"
The first two variables are for Module::Build and ExtUtils::MakeMaker — this makes the installers target this tree. The PERL5LIB variable tells perl where to find the modules and the PATH variables tells your shell where to find the scripts. You could setup these pieces manually, or might want to set just thePERL5LIB variable in e.g. your Apache configs.
For more details and options, see the local::lib documentation.

Further Reading

The Perl module system and build tools are very flexible. Your situation can usually be handled simply by adjusting the configuration or environment.
  • perlmodlib
  • perlrun
  • perlvar/@INC
  • perlfunc/require
  • lib
  • CPAN
  • Module::Build
  • ExtUtils::MakeMaker
  • ExtUtils::Install
  • local::lib

Common Problems

Most of the problems people have using the CPAN comes down to configuring or upgrading their CPAN client. Either the client was pre-configured, or was never properly configured. It is usually something very simple, but you could be starting in one of thousands of possible situations. If in doubt, clean off the slate and start fresh.

Rusty Old Tools

If you cannot run on a new perl (why not?), you must upgrade CPAN.pm, install Module::Build, install ExtUtils::MakeMaker, install Bundle::CPAN, and you may need to reconfigure your CPAN client from a clean slate (o conf init). Various older CPAN clients will run into snags trying to self-upgrade (needing to be configured, restarted, upgraded, restarted, reconfigured, restarted, configured, etc.) Just scrap the old client and get a fresh tarball.

Crufty Old Config

If your CPAN client does not prompt you for configuration when you first run it, you might need to delete whatever configuration it is using. When you run 'o conf' from the interactive shell, it prints "$CPAN::Config options from 'somefile.pm'". Remove that file and try again.

Permissions

You might see a message like 'Cannot write some file ... permission denied' in the build output. When this happens, you have to track down which directories need which permissions and may need to use 'sudo' to fix it, setup your client to install elsewhere, or use local::lib.

Failing Tests

If you have upgraded and properly configured your CPAN client, but are still having trouble installing a module, it might be a bug in the module (or one of its dependencies.) Carefully read the output from the build process, find out which module is building when it fails, and isolate the problem.
You may need to run the 'look' command from the interactive shell to drill-down into the module and manually step through the build process. You'll either find something wrong with your system or a bug in the module (or its tests.) When you find a bug in a distribution on the CPAN, report it to the distribution author so it can be fixed. Often, the module's author is using a different platform and has not experienced the bug.

___________________________________________________________________________________

About wxPerl

The Wx module lets you use the wxWidgets cross-platform GUI (Graphical User Interface) toolkit with Perl. A GUI program draws buttons and other widgets on the screen and interacts with the user via the keyboard and mouse.

How GUI Toolkits Work

Graphical widgets are drawn on the screen as pixels, so a button is just a picture taking up some area on the screen. To detect when the user clicks the "button", the computer needs to keep track of the mouse cursor location, wait for a click from the mouse device, and check the current cursor coordinates against the button's screen area. This all gets rather complicated with even a few buttons on the screen, but there are already several layers of abstraction between you and the mouse click. Thus, a typical GUI application "stacked" some distance from the actual hardware:
  1. Device Driver: read/write electrical signals (from the mouse)
  2. Operating System: manages resources (the mouse "device")
  3. Windowing System: juggles multiple "windows" (and mouse "focus")
  4. Window Manager: window placement, focus
  5. Widget Toolkit: draws widgets, juggles "events"
  6. Your Application: reacts to events
You might think of layers 2-5 as "the operating system". On a Linux desktop, the layers are more clearly visible (e.g. kernel, X, gnome, and GTK.) The widget toolkit talks to the window manager to allow the user to drag our application's window around, minimize it, etc. The window manager assigns a "drawing area" to each application. It keeps your web browser from drawing on your text document and keeps track of which window receives the keyboard and mouse input. But, once you have your own drawing area and the mouse focus, you still need to draw the button and figure out whether the mouse click is inside the button.
This is where the widget toolkit comes in. It gives you a way to draw and use widgets (buttons, scrollbars, etc.) which look and behave like the widgets in other applications. It also listens for mouse and keyboard input and triggers events in your application which react to those inputs. Using a toolkit, GUI applications rarely need to work directly with pixels, mouse clicks, or keypresses.

How wxPerl Works

The wxWidgets toolkit runs on Windows, Mac, and Linux platforms and creates applications which have a "native" look-and-feel on each platform. It does this by building on top of each platform's native widget toolkit. So, a wxPerl button on Windows looks just like a button from a native windows application.
The wxPerl code links to the wxWidgets libraries, and provides an object-oriented Perl interface to the C++ code underneath. Because of this, wxPerl code looks very similar to C++ wxWidgets code. There is no perl-specific Wx documentation, but the extensive wxWidgets documentation contains several notes about where wxPerl usage differs from that of C++.

Event-Driven Programming

Wx is an object-oriented, event-driven toolkit. Each widget is an object, and any input from the user is treated as an event. You construct the objects, connect their events to some handler code in your application, and call the toolkit's MainLoop method. The main loop waits for an event, calls the corresponding event handler, and goes back to waiting for the next event.
A simple console-based application can also be event-driven, where the mainloop is just a while loop withreadline and the event handlers are just a dispatch table.
  my %handlers = (
    c => sub {say "you said c"},
    d => sub {say "you said d"},
    x => sub {say "you said x"; exit},
  );

  while(<>) {
    chomp;
    my $handler = $events{$_} or next;
    $handler->();
  }
Something similar goes on inside of the GUI toolkit's MainLoop, but with a more complicated dispatch table and multiple inputs. Note how the program resumes looping after running a handler, but cannot process further input until the handler completes.

Installing wxPerl

Installing the Wx module on your system should be as simple as:
  $ cpan Wx
Assuming that your CPAN client is correctly configured, this will download and install everything you need to run Wx. Its dependencies include the Alien::wxWidgets, which will download and compile the C++ wxWidgets toolkit for you. If you want to use an already-installed wxWidgets, you can manually build the Alien::wxWidgets against that (see the README file for instructions.)
Your system may have prebuilt wxPerl packages available (e.g. libwx-perl in Debian), though these may be somewhat older than the current version from the CPAN.

Your First wxPerl Application

Every wxPerl application must construct an object derived from Wx::App and call this object's MainLoopmethod. This object must define an OnInit method which instantiates the applications widgets. So, we always start with a subclass of Wx::App.
  1 #!/usr/bin/env perl
  2 
  3 use warnings;
  4 use strict;
  5 
  6 use Wx;
  7 
  8 package MyApp;
  9 
 10 use base 'Wx::App';
 11 
 12 sub OnInit {
 13   my $self = shift;
 14 
 15   my $frame = Wx::Frame->new(
 16     undef,
 17     -1,
 18     'A wxPerl Application',
 19     &Wx::wxDefaultPosition,
 20     &Wx::wxDefaultSize,
 21     &Wx::wxMAXIMIZE_BOX | &Wx::wxCLOSE_BOX
 22   );
 23 
 24   $frame->Show;
 25 }
 26 
 27 MyApp->new->MainLoop;

Wx Object Constructors

This constructs a frame and displays it on the screen. The wxFrame documentation explains the parameters in more detail. Because the API uses positional parameters, we have to pad-out the positions using the defaults (e.g. &Wx::wxDefaultPosition) to be able to set the window style. Wx provides several constants like this which correspond to the constants referenced in the wxWidgets documentation.
 15   my $frame = Wx::Frame->new(
 16     undef,                  # parent window
 17     -1,                     # window ID
 18     'A wxPerl Application', # window title
 19     &Wx::wxDefaultPosition, # window position
 20     &Wx::wxDefaultSize,     # window size
 21     &Wx::wxMAXIMIZE_BOX | &Wx::wxCLOSE_BOX   # window style
 22   );
Note how the 'style' parameter is made of two constants OR'd together with the | operator. This is common practice in C++ code (and wxPerl very closely mirrors the wxWidgets C++ API in Perl.) We'll frequently need to use combinations of these numeric constants to control objects.
If we just wanted the defaults, we could stop at the end of the required parameters.
 15   my $frame = Wx::Frame->new(
 16     undef,                  # parent window
 17     -1,                     # window ID
 18     'A wxPerl Application', # window title
 19   );
The window size parameter can be a wxSize object, but that's just an object holding two numbers. Conveniently, wxPerl allows us to use array references for this sort of thing in many places.
 15   my $frame = Wx::Frame->new(
 16     undef,                  # parent window
 17     -1,                     # window id
 18     'A wxPerl Application', # window title
 19     &Wx::wxDefaultPosition, # window position
 20     [800, 600],             # window size
 21   );
The result here is the same as if we had used Wx::Size->new(800,600) as the 'size' parameter.

Using Named Parameters

The wxPerl::Constructors module provides an alternate set of constructors for Wx::foo objects. This eliminates some of the argument-padding by using names for the optional parameters. If you install it (with `cpan wxPerl::Constructors`), our example becomes a bit simpler. The wxPerl::Frame->new method assumes that 'id' is -1 (i.e. just let Wx generate a new id) if it is not specified, so we only need the 'parent' and 'title' parameters here, plus whatever options.
  1 #!/usr/bin/env perl
  2 
  3 use warnings;
  4 use strict;
  5 
  6 use Wx;
  7 use wxPerl::Constructors;
  8 
  9 package MyApp;
 10 
 11 use base 'Wx::App';
 12 
 13 sub OnInit {
 14   my $self = shift;
 15 
 16   my $frame = wxPerl::Frame->new(undef, 'A wxPerl Application',
 17     style => &Wx::wxMAXIMIZE_BOX | &Wx::wxCLOSE_BOX
 18   );
 19 
 20   $frame->Show;
 21 }
 22 
 23 MyApp->new->MainLoop;
Or, just setting a size:
 16   my $frame = wxPerl::Frame->new(undef, 'A wxPerl Application',
 17     size => [800,600]
 18   );
Or, with just the defaults:
 16   my $frame = wxPerl::Frame->new(undef, 'A wxPerl Application');

Adding Widgets

Now we know how to create a frame (the top-level window), but we need to put some widgets on it to get a useful application. Every widget within the frame is going to be a child of the frame (or a child of a child, etc.) This allows the toolkit to keep track of every widget in terms of its top-level ancestor widget (the frame.)
  1 #!/usr/bin/env perl
  2 
  3 use warnings;
  4 use strict;
  5 
  6 use Wx;
  7 use wxPerl::Constructors;
  8 
  9 package MyApp;
 10 
 11 use base 'Wx::App';
 12 
 13 sub OnInit {
 14   my $self = shift;
 15 
 16   my $frame = wxPerl::Frame->new(undef, 'A wxPerl Application',
 17     style => &Wx::wxMAXIMIZE_BOX | &Wx::wxCLOSE_BOX
 18   );
 19 
 20   my $button = wxPerl::Button->new($frame, 'Click Me');
 21 
 22   $frame->Show;
 23 }
 24 
 25 MyApp->new->MainLoop;
Now we have a button, but it does not do anything except give visual feedback about being clicked (that is a builtin behavior.) To make it do our bidding, we need to hook a handler to the button's BUTTON event.
 20   Wx::Event::EVT_BUTTON($button, -1, sub {
 21     my ($b, $evt) = @_;
 22     $b->SetLabel('Clicked');
 23     $b->Disable;
 24   });
The wxButton documentation lists all of the events for that widget. In this case, there is onlyEVT_BUTTON(id, func). Note that the event usage listed in the C++ documentation is slightly different than the wxPerl usage: the first argument to an event mapping in perl is always the object ($button). So, you have to mentally transform the C++ usage to perl as: EVT_BUTTON($object, $id, $subref).
Now let's try our application with the button event connected:
  1 #!/usr/bin/env perl
  2 
  3 use warnings;
  4 use strict;
  5 
  6 use Wx;
  7 use wxPerl::Constructors;
  8 
  9 package MyApp;
 10 
 11 use base 'Wx::App';
 12 
 13 sub OnInit {
 14   my $self = shift;
 15 
 16   my $frame = wxPerl::Frame->new(undef, 'A wxPerl Application');
 17   $frame->SetMinSize([120,40]);
 18 
 19   my $button = wxPerl::Button->new($frame, 'Click Me');
 20   Wx::Event::EVT_BUTTON($button, -1, sub {
 21     my ($b, $evt) = @_;
 22     $b->SetLabel('Clicked');
 23     $b->Disable;
 24   });
 25 
 26   $frame->Show;
 27 }
 28 
 29 MyApp->new->MainLoop;
Note that the event handler (our anonymous subref) is called with the arguments $object, $event. In this case, $event does not contain anything of interest, though it will for other sorts of events.

Sizers

If you try to add another button to the frame in this example, it gets drawn on top of the first button and makes a mess of the layout. To organize the layout, wxWidgets uses sizers, which are stretchable containers that tell the toolkit how to layout a group of widgets and how to behave when the window is resized.
To put our new button below the other, we can use a wxBoxSizer with the wxVERTICAL orientation.
 18   my $sizer = Wx::BoxSizer->new(&Wx::wxVERTICAL);
Then, we need to add each button to the sizer as it is created. The 'proportion' argument to Add determines how the available space is split between each widget. In this case, the first button will be twice as big as the second.
 20   my $button = wxPerl::Button->new($frame, 'Click Me');
 21   $sizer->Add($button, 2, &Wx::wxEXPAND);
 22   my $button2 = wxPerl::Button->new($frame, 'DO NOT CLICK');
 23   $sizer->Add($button2, 1, &Wx::wxEXPAND);
Aside: You might have noticed that the Add method is not listed in the wxBoxSizer documentation. But, wxSizer is the first link in the 'Derived from' section at the top of the page. This means that anything not listed in the wxBoxSizer documentation is implemented (and documented) by its parent class. You'll frequently need to navigate up through the inheritance like this to find all of the methods for a given widget.
Finally, we need to connect this sizer to the frame.
 33   $frame->SetSizer($sizer);
 34   $frame->Show;
This adjusts the sizer whenever the frame changes. Putting this all together with an event handler hooked to our new button gives:
  1 #!/usr/bin/env perl
  2 
  3 use warnings;
  4 use strict;
  5 
  6 use Wx;
  7 use wxPerl::Constructors;
  8 
  9 package MyApp;
 10 
 11 use base 'Wx::App';
 12 
 13 sub OnInit {
 14   my $self = shift;
 15 
 16   my $frame = wxPerl::Frame->new(undef, 'A wxPerl Application');
 17   $frame->SetMinSize([120,80]);
 18   my $sizer = Wx::BoxSizer->new(&Wx::wxVERTICAL);
 19 
 20   my $button = wxPerl::Button->new($frame, 'Click Me');
 21   $sizer->Add($button, 2, &Wx::wxEXPAND);
 22   my $button2 = wxPerl::Button->new($frame, 'DO NOT CLICK');
 23   $sizer->Add($button2, 1, &Wx::wxEXPAND);
 24   Wx::Event::EVT_BUTTON($button, -1, sub {
 25     my ($b, $evt) = @_;
 26     $b->SetLabel('Clicked');
 27     $b->Disable;
 28   });
 29   Wx::Event::EVT_BUTTON($button2, -1, sub {
 30     &Wx::wxTheApp->ExitMainLoop;
 31   });
 32 
 33   $frame->SetSizer($sizer);
 34   $frame->Show;
 35 }
 36 
 37 MyApp->new->MainLoop;
Try resizing the window and see what happens. Experiment with the 'proportion' and 'flags' parameters to$sizer->Add to get a feel for how they change the layout.
Note that the code in OnInit is getting somewhat long and mostly involves children of the wxFrame object. To keep things manageable, you would typically write a MyMainFrame.pm and subclass Wx::Frame. This would allow you to reduce the code in OnInit to simply:
 16   my $frame = MyMainFrame->new(undef, 'A wxPerl Application');
 17   $frame->init;
 18   $frame->Show;
Then, you need to implement the init method in your MyMainFrame package and put the code to layout widgets and connect events in there. Whenever you are constructing a widget with some complex children, consider subclassing the widget and organizing your code into maintainable components.

GUI Builders

Once you know how to create widgets, connect them to events and use sizers to organize them, all you have to do is build up from there. You should find your way around the wxWidgets documentation and learn how the documented C++ API differs from the wxPerl API. Then, you can simply code-in all of your widgets, but this can lead to a lot of Perl code just to create and layout the widgets.
GUI builder applications like wxGlade or XRCed allow you to graphically layout and preview your application. With XRCed, you generate an XRC xml document and need to add code to your application to load-in the widget definitions and connect them to event handlers. With wxGlade, you can generate XRC or Perl code (but you still need to setup the event handlers.)
The graphical GUI builders are great for seeing what widgets are available and prototyping even if you do not directly use their outputs in your application. You may find the generated code mechanism to be difficult to maintain (this is what led me to create FreeTUIT as an alternative way to organize widget construction and layout.)

No comments:

Post a Comment