A program, to my mind, is basically code which does something. A module or class on its own doesn't do anything. It's not a program. You need a program to use them and do something. However, the problem which I see all too often is programs which try to do too much. As a result, when I wrote grepl, I did not want any logic in there which belong in the App::Grepl class. Though grepl is powerful and does a lot, here's the entire program:
#!/usr/local/bin/perl
use strict;
use warnings;
use App::Grepl;
use Pod::Usage 1.12;
use Getopt::Long;
GetOptions(
"pattern=s" => \my $pattern,
"search=s" => \my $lookfor,
"warnings" => \my $warnings,
"l" => \my $filename_only,
'h|help|?' => sub { pod2usage( { -verbose => 1 } ); exit },
'H|man' => sub { pod2usage( { -verbose => 2 } ); exit },
);
$lookfor = [ split ',' => ( $lookfor || '' ) ];
$pattern ||= '';
my @search_in;
if ( !@ARGV ) {
@search_in = ( dir => '.' );
}
elsif ( 1 == @ARGV && -d $ARGV[0] ) {
@search_in = ( dir => $ARGV[0] );
}
else {
@search_in = ( files => [ @ARGV ] );
}
my $grepl = App::Grepl->new(
{
look_for => $lookfor,
pattern => $pattern,
warnings => $warnings,
filename_only => $filename_only,
@search_in,
}
);
$grepl->search;
Now that's how you write a program. The only logic is processing command line arguments and passing them to the application.
Yes, the constructor is doing a lot, but even that's fairly easy to manage. I have about 96% test coverage and I'm not worried about having code in my program which is difficult to test (unlike in, say, runtests).