This is my take. It uses yet a different tool set than the two previous posts.
It does perhaps look a bit long, but that's because I've put some comments in the code to explain and motivate some of the code. Without the comments the code is 47 lines (including the empty lines). I admit though that some of the code I put there just to illustrate particular techniques and show what I believe is a healthy programming style.
use strict;
use warnings;
use Date::Calc::Object qw/ Month_to_Text /;
if (@ARGV < 2) {
die "$0 STARTDATE ENDDATE FILE\n";
# $0 is the program filename and the newline at the end
# makes perl not report filename and line number of the
# die call.
}
my ($start_str, $end_str, $file) = @ARGV;
# I prefer to get all parameters directly and don't mess
# with @ARGV (or @_ for subroutines) later on.
# I also chose to get the dates by parameters rather than
# prompting for it. I dislike prompting if parameter
# passing will work.
my $start = Date::Calc::Object::->new(split /-/, $start_str, 3)
or die "Invalid start date\n";
my $end = Date::Calc::Object::->new(split /-/, $end_str, 3)
or die "Invalid end date\n";
# Note the colons last in the class name. That helps you
# spot typos. (Try removing the use() line above.)
my $fh;
if (defined $file) { # Use defined() since '0' is a valid file nam
+e.
open $fh, '>', $file or die "Couldn't open $file for write: $!
+";
# Three-argument open is new for Perl 5.6, but recommended.
}
else {
$fh = \*STDOUT; # A reference to a GLOB. See "perldoc -f print
+"
# and perldata section "Typeglobs and Filehand
+les".
}
# I chose to set STDOUT as default.
# A slight change of data structure:
my %meals = (
breakfast => [ qw/bagel cereal toast yogurt/ ],
lunch => [ qw/sandwich milkshake pb&j hoagie/ ],
dinner => [ qw/pasta rice chicken steak/ ],
);
# The overloading of Date::Calc::Object objects makes
# it easy to use dates as regular counters.
for (my $date = $start->clone; $date <= $end; $date++) {
my $d = substr(Month_to_Text($date->month), 0, 3) . ' ' . $dat
+e->day;
print $fh "$d\n";
print '-' x length $d, "\n";
# Since I don't like to repeat myself I abstracted
# the meal names.
for (qw/ breakfast lunch dinner /) {
printf $fh "%-9s: %s\n",
ucfirst,
$meals{$_}->[rand @{$meals{$_}}] # Note the arrow!
;
# The arrow operator above is a dereferencing operator
# and you can learn more about references and dereferencin
+g
# in perlreftut and perlref.
# @{$meals{$_}} is also a deref expression and you'll lear
+n
# about that too in those two documents mentioned above!
}
print '-' x length $d, "\n\n";
}
Hope I've helped,
ihb