views:

230

answers:

5

I have a Perl script (foo.pl) that loads Foo.pm from the same directory using the require mechanism:

require "./Foo.pm";
...
my $foo = new Foo::Bar;

The Foo.pm adheres to the standard module format:

package Foo::Bar;
...
1;

Rather than distributing my application as two files (foo.pl and Foo.pm) I'd like to distribute only one file. More specifically I'd like to make Foo.pm part of the foo.pl script.

How do I achieve that?

The trivial approach of simply merging the two files (cat foo.pl Foo.pm > foo2.pl) does not work.

+2  A: 

The overall scheme would be to replace your "require ..." with the contents of what you're requiring. There's more to it than that (BEGIN { } may be needed), and I'm not exactly sure what's involved. For sure, you'd want to automate it.

Here's an alternative: generate a single executable file where modules you depend on are packed inside it using PAR/pp

wrang-wrang
Hi wrang-wrang! Thanks for the tips. Unfortunately creating an executable is not an option since the same script will be used across multiple platforms.
knorv
knorv: If you're not including any modules with an XS/C/compiled component, PAR can create .par files which are cross-platform. This is NOT a binary executable as with "pp -o foo.exe foo.pl".
tsee
+3  A: 

Your code did not work (although it would have been helpful to state the error message(s) that you received) because you attempted to use Foo::Bar before it had been defined. Try this:

use strict;
use warnings;
my $foo = Foo::Bar->new();
# more code...

# end code

# begin definitions
BEGIN {
    package Foo::Bar;
    use strict;
    use warnings;
    # definitions...
    1;

    package Foo::Baz;
    # more stuff, if you need to define another class
}

Additions:

Ether
+4  A: 

A file can contain multiple packages. Put your class first, followed by the main script:

package Foo::Bar;

sub new { 
  my $class = shift;
  return bless {}, $class;
}

#...

package main;

my $foo = Foo::Bar->new();
print ref $foo;  # Foo::Bar
Michael Carman
The `package` statement does not create a new scope, so you may want to use `{ package Foo::Bar; REST_OF_THE_CODE }` to keep stuff from leaking between the two packages.
Chas. Owens
+2  A: 

You've already got a few good answers. In addition, it is possible to make a module than can be run directly as a script.

package Foo;

__PACKAGE__->run(@ARGV) unless caller();

sub run {
    # Do stuff here if you are running the Foo.pm as
    # a script rather than using it as a module.
}

For additional details, see brian d foy's How a Script Becomes a Module.

FM
+5  A: 

If you're interested in packing up your Perl script into a binary with all the modules it depends upon included, you can use PAR Packager:

pp -o binary_name foo.pl
Drew Stephens