Still More Perl Lightning Articles

It has been common practice within the Perl community for ages to ship distributions with a Makefile.PL so that the user will be able to install the packages when he retrieves them, either via the shell which the CPAN/CPANPLUS modules offer or via manual CPAN download.

The Makefile.PL consists of meta-information, which in the case of the distribution HTML::Tagset is:

 # This -*-perl-*- program writes the Makefile for installing this distribution.
 #
 # See "perldoc perlmodinstall" or "perldoc ExtUtils::MakeMaker" for
 # info on how to control how the installation goes.

 require 5.004;
 use strict;
 use ExtUtils::MakeMaker;

 WriteMakefile(
     NAME            => 'HTML::Tagset',
     AUTHOR          => 'Andy Lester <andy@petdance.com>',
     VERSION_FROM    => 'Tagset.pm', # finds $VERSION
     ABSTRACT_FROM   => 'Tagset.pm', # retrieve abstract from module
     PMLIBDIRS       => [qw(lib/)],
     dist            => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
     clean           => { FILES => 'HTML-Tagset-*' },
 );

Of interest are the arguments to WriteMakefile(), because they influence the Makefile written by ExtUtils::MakeMaker after the user has invoked the usual build and install procedure:

 % perl Makefile.PL
 % make
 % make test
 # make install

Module::Build, Successor of ExtUtils::MakeMaker?

As Ken Williams grew tired of ExtUtils::MakeMaker and its portability issues, he invented Module::Build, a successor of ExtUtils::MakeMaker. One goal of Module::Build is to run smoothly on most operating systems, because it takes advantage of creating Perl-valid syntax files only and does not rely upon crufty Makefiles, which are often subject to misinterpretation, because so many incompatible flavors of make exist in the wild.

The current maintainer of ExtUtils::MakeMaker, Michael G. Schwern, elaborated about this problem in his talk reachable via “MakeMaker is DOOMED.”

Module::Build Distribution “Skeleton”

If you take in consideration the distribution HTML::Tagset again, the rough skeleton suitable for Module::Build having converted the Makefile.PL by Module::Build::Convert into a Build.PL, the output would be:

 # This -*-perl-*- program writes the Makefile for installing this distribution.
 #
 # See "perldoc perlmodinstall" or "perldoc ExtUtils::MakeMaker" for
 # info on how to control how the installation goes.
 # Note: this file has been initially generated by Module::Build::Convert 0.24_01

 require 5.004;
 use strict;
 use warnings;

 use Module::Build;

 my $build = Module::Build->new
   (
    module_name => 'HTML::Tagset',
    dist_author => 'Andy Lester <andy@petdance.com>',
    dist_version_from => 'Tagset.pm',
    add_to_cleanup => [
                        'HTML-Tagset-*'
                      ],
    license => 'unknown',
    create_readme => 1,
    create_makefile_pl => 'traditional',
   );

 $build->create_build_script;

As you can see, while ExtUtils::MakeMaker prefers uppercased arguments, Module::Build goes by entirely lowercased arguments, which obey the rule of least surprise by being as intuitive as a description can be.

The build and installation procedure for a Module::Build distribution is:

 % perl Build.PL
 % perl Build
 % perl Build test
 # perl Build install

Module::Build::Convert’s State of Operation

Module::Build::Convert actually does all of the background work and can be safely considered the back end, whereas make2build is the practical front-end utility. Module::Build::Convert currently exposes two kinds of operation: static approach and dynamic execution. The static approach parses the arguments contained within the Makefile.PL’s WriteMakefile() call, whereas dynamic execution runs the Makefile.PL and captures the arguments provided to WriteMakefile().

Module::Build::Convert parses statically by default, because the dynamic execution has the downside that code will be interpreted and the interpreted output will be written to the Build.PL, so you have to conclude that the user of the distribution will end up with predefined values computed on the author’s system. This is something to avoid, whenever possible! If the parsing approach fails, perhaps looping endlessly on input, Module::Build::Convert will reinitialize to perform dynamic execution of the Makefile.PL instead.

Data Section

Module::Build::Convert comes with a rather huge data section containing the argument conversion table, default arguments, sorting order, and begin and end code. If you wish to change this data, consider making a ~/.make2buildrc file by launching make2build with the -rc switch. Do not edit the Data section within Module::Build::Convert directly, unless you are sure you want to submit a patch.

Argument Conversion

On the left-hand side is the MakeMaker’s argument name, and on the right-hand side the Module::Build’s equivalent.

 NAME                  module_name
 DISTNAME              dist_name
 ABSTRACT              dist_abstract
 AUTHOR                dist_author
 VERSION               dist_version
 VERSION_FROM          dist_version_from
 PREREQ_PM             requires
 PL_FILES              PL_files
 PM                    pm_files
 MAN1PODS              pod_files
 XS                    xs_files
 INC                   include_dirs
 INSTALLDIRS           installdirs
 DESTDIR               destdir
 CCFLAGS               extra_compiler_flags
 EXTRA_META            meta_add
 SIGN                  sign
 LICENSE               license
 clean.FILES           @add_to_cleanup

Default Arguments

These are default Module::Build arguments to added. Arguments with a leading # are ignored.

 #build_requires       HASH
 #recommends           HASH
 #conflicts            HASH
 license               unknown
 create_readme         1
 create_makefile_pl    traditional

Sorting Order

This is the sorting order for Module::Build arguments.

 module_name
 dist_name
 dist_abstract
 dist_author
 dist_version
 dist_version_from
 requires
 build_requires
 recommends
 conflicts
 PL_files
 pm_files
 pod_files
 xs_files
 include_dirs
 installdirs
 destdir
 add_to_cleanup
 extra_compiler_flags
 meta_add
 sign
 license
 create_readme
 create_makefile_pl

Begin Code

Code that precedes converted Module::Build arguments. $(UPPERCASE) are stubs being substituted by Module::Build code.

 use strict;
 use warnings;

 use Module::Build;

 $MAKECODE

 my $b = Module::Build->new
 $INDENT(

End Code

Code that follows converted Module::Build arguments. $(UPPERCASE) are stubs being substituted by Module::Build code.

 $INDENT);

 $b->create_build_script;

 $MAKECODE

make2build Basic Usage

Using make2build is as easy as launching it in the directory of the distribution of which Makefile.PL you wish to convert.

For example:

% make2build

You may also provide the full path to the distribution, assuming, for example, you didn’t cd directly into the distribution directory.

% make2build /path/to/HTML-Tagset*

In both cases, the command will convert any found Makefile.PL files and will generate no output because make2build acts quiet by default.

make2build Switches

As make2build aims to be a proper script, it of course, provides both the -h (help screen) and -V (version) switches.

 % make2build -h
 % make2build -V

In case you end up with a mangled Build.PL written, you can examine the parsing process by launching make2build with the -d switch, enabling the pseudo-interactive debugging mode.

 % make2build -d

Should you not like the indentation length or judge it to be too small, increase it via the -l switch followed by an integer.

 % make2build -l length

If you don’t agree with the sorting order predefined in Module::Build::Convert, you may enforce the native sorting order, which strives to arrange standard arguments with those seen available in the Makefile.PL.

 % make2build -n

The argument conversion table, default arguments to add, the sorting order of the arguments, and the begin and end code aren’t absolute, either. Change them by invoking make2build with the -rc switch to create a resource configuration file in the home directory of the current user; that is likely ~/.make2build.rc.

 % make2build -rc

While make2build is quiet by default, there are two verbosity levels. To enforce verbosity level 1, launch make2build with -v. To enforce verbosity level 2, use -vv.

With -v, the code will warn about Makefile.PL options it does not understand or skips. With -vv, it will accumulate -v output and the entire generated Build.PL.

 % make2build -v
 % make2build -vv

You may execute the Makefile.PL in first place, but such usage is deprecated because Module::Build::Convert downgrades automatically when needed.

 % make2build -x (deprecated)

Swinging with Perl

Phil Crow

Perl does not have a native graphical user interface (GUI) toolkit. So we use all manner of existing GUI tools in front of our Perl applications. Often we use a web browser. We have long had Perl/Tk and other libraries based on C/C++. Now we can also use Java’s Swing toolkit with similar ease.

In my sample application, when the user presses a button, Perl evaluates an arithmetic expression from the input text box. The result appears in another text box. I’ll show the code for this application a piece at a time with a discussion after each piece. To see the whole thing, look in the examples directory of the Java::Swing distribution.

    #!/usr/bin/perl
    use strict; use warnings;

    BEGIN {
        $ENV{CLASSPATH} .= ':/path/to/Java/Swing/java'
    }

Java::Swing needs certain Java classes to be in the class path before it loads, so I’ve appended a path to those classes in a BEGIN block (this block must come before using Java::Swing).

    use Java::Swing;

This innocuous statement magically sets up namespaces for each Java Swing component, among other things.

    my $expression  = JTextField->new();
    my $answer      = JTextField->new( { columns => 10 } );
    my $submit      = JButton   ->new("Evaluate");
    my $frame       = JFrame    ->new();
    my $root_pane   = $frame->getContentPane();
    my $south_panel = JPanel->new();

After using Java::Swing, you can refer to Swing components as Perl classes. You can even pass named parameters to their constructors, as shown for the second JTextField.

    $south_panel->add(JLabel->new("Answer:"), "West");
    $south_panel->add($answer,                "Center");
    $south_panel->add($submit,                "East");

    $root_pane->add($expression,  "North");
    $root_pane->add($south_panel, "South");

    $frame->setSize(300, 100);
    $frame->show();

Most work with the components is the same as in any Java program. If you don’t understand the above code, consult a good book on Swing (like the one from O’Reilly).

    my $swinger = Java::Swing->new();

This creates a Java::Swing instance to connect event listeners and to control the event loop.

    $swinger->connect(
        "ActionListener", $submit, { actionPerformed => \&evaluate }
    );

    $swinger->connect(
        "WindowListener", $frame, { windowClosing => \&ending }
    );

Connection is simple. Pass the listener type, the object to listen to, and a hash of code references to call back as events arrive.

    $swinger->start();

Start the event loop. After this, the program passively waits for event callbacks. It stops when one of the callbacks stops the event loop.

    sub evaluate {
        my $sender_name = shift;
        my $event       = shift;

        $answer->setText(eval $expression->getText());
    }

My evaluation is simple. I retrieve the text from the expression JTextField, eval it, and pass the result to setText on the answer JTextField. Using eval raises possible security concerns, so use it wisely.

    sub ending {
        $swinger->stop();
    }

When the user closes the window, I stop the event loop by calling stop on the Java::Swing instance gained earlier. This kills the program.

With Java::Swing, you can build Swing apps in Perl with some important bits of syntactic sugar. First, you don’t need to have separate Java files or inline sections. Second, you can pass named arguments to constructors. Finally, you can easily connect event listeners to Perl callback code.

Scriptify Your Module

Josh McAdams

Recently during an MJD talk at Chicago.pm, I saw a little Perl trick that was so amazingly simple and yet so useful that it was hard to believe that more mongers in the crowd hadn’t heard of it. The trick involved taking your module and adding a driver routine to it so the module could run as a script.

To illustrate, start with an example module that contains two utility subroutines that convert weights between pounds and kilograms. The subroutines accept some number and multiplies it by a conversion factor.

  package WeightConverter;

  use strict;
  use warnings;
  use constant LB_PER_KG => 2.20462262;
  use constant KG_PER_LB => 1/LB_PER_KG;

  sub kilograms_to_pounds { $_[0] * LB_PER_KG; }

  sub pounds_to_kilograms { $_[0] * KG_PER_LB; }

Assuming that the real module has a little error checking and POD, this module would serve you just fine. However, what if you decided that we needed to be able to easily do weight conversions from the command line? One option would be to write a Perl script that used WeightConverter. If that seems like too much effort, there is a one-liner that would do conversions.

  perl -MWeightConverter -e 'print WeightConverter::kilograms_to_pounds(1),"\n"'

This would do the trick, but it is a lot to remember and isn’t very fun to type. There is a lot of benefit available from saving some form of script, and believe it or not, the module can hold that script. All that you have to do is write some driver subroutine and then call that subroutine if the module is not being used by another script. Here is an example driver for WeightConverter.

This example driver script just loops through the command-line arguments and tries to find instances where the argument contains either a k or p equal to some value. Based on whether or not you are starting with pounds or kilograms, it calls the appropriate subroutine and prints the results.

  sub run {
    for (@ARGV) {
      if(/^[-]{0,2}(k|p)\w*=(.+)$/) {
        $1 eq 'k' ?
          print "$2 kilograms is ", kilograms_to_pounds($2), " pounds\n" :
          print "$2 pounds is ", pounds_to_kilograms($2), " kilograms\n" ;
      }
    }
  }

Now all that is left is to tell the module to run the run subroutine if someone has run the module on its own. This is as easy as adding one line somewhere in the main body of the module.

  run unless caller;

All this statement does is execute the run subroutine unless the caller function returns a value. caller will only return true if WeightConverter is being used in another script. Now, this module is usable in other scripts as well as on the command line.

  $> perl WeightConverter.pm -kilos=2 -pounds=145 -k=.345
  2 kilograms is 4.40924524 pounds
  145 pounds is 65.7708937051548 kilograms
  .345 kilograms is 0.7605948039 pounds

Mocks in Your Test Fixtures

by chromatic

Since writing Test::MockObject, I’ve used it in nearly every complex test file I’ve written. It makes my life much easier to be able to control only what I need for the current group of tests.

I wish I’d written Test::MockObject::Extends earlier than I did; that module allows you to decorate an existing object with a mockable wrapper. It works just as the wrapped object does, but if you add any mocked methods, it will work like a regular mock object.

This is very useful when you don’t want to go through all of the overhead of setting up your own mock object but do want to override one or two methods. (It’s almost always the right thing to do instead of using Test::MockObject..)

Another very useful test module is Test::Class. It takes more work to understand and to use than Test::More, but it pays back that investment by allowing you to group, reuse, and organize tests in the same way you would group, reuse, and organize objects in your code. Instead of writing your tests procedurally, from the start to the end of a test file, you organize them into classes.

This is most useful when you’ve organized your code along similar lines. If you have a base class with a lot of behavior and a handful of subclasses that add and override a little bit of behavior, write a Test::Class-based test for the base class and smaller tests that inherit from the base test for the subclasses.

Goodbye, duplicate code.

Fixtures

Test::Class encourages you to group related tests into test methods. This allows you to override and extend those groups of tests in test subclasses. (Good OO design principles apply here; tests are still just code, after all.) One of the benefits of grouping tests in this way is that you can use test fixtures.

A test fixture is another method that runs before every test method. You can use them to set up the test environment–creating a new object to test, resetting test data, and generally making sure that tests don’t interfere with each other.

A standard test fixture might resemble:

  sub make_fixture :Test( setup )
  {
      my $self        = shift;
      $self->{object} = $self->test_class()->new();
  }

Assuming that there’s a test_class() method that returns the name of the class being tested, this fixture creates a new instance before every test method and stores it as the object attribute. The test methods can then fetch this as normal.

Putting Them Together

I recently built some tests for a large system using Test::Class. Some of the tests had mockable features–they dealt with file or database errors, for example. I found myself creating a lot of little Test::MockObject::Extends instances within most of the tests.

Then inspiration struck. Duplication is bad. Repetition is bad. Factor it out into one place.

The insight was quick and sudden. If Test::MockObject::Extends is transparent (and if it isn’t, please file a bug–I’ll fix it), I can use it in the test fixture all the time and then be able to mock whenever I want without doing any setup. I changed my fixture to:

  sub make_fixture :Test( setup )
  {
      my $self        = shift;
          my $object      = $self->test_class()->new();
      $self->{object} = Test::MockObject::Extends->new( $object );
  }

The rest of my code remained unchanged, except that now I could delete several identical lines from several test methods.

Do note that, for this to work, you must adhere to good OO design principles in the code being tested. Don’t assume that ref is always what you think it should be (and use the isa() method instead).

Sure, this is a one-line trick, but it removed a lot of busy work from my life and it illustrates two interesting techniques for managing tests. If you need simpler, more precise mocks, use Test::MockObject::Extends. If you need better organization and less duplication in your test files, use Test::Class. Like all good test modules, they work together almost flawlessly.

Tags

Feedback

Something wrong with this article? Help us out by opening an issue or pull request on GitHub