Acme-Chef
view release on metacpan or search on metacpan
lib/Acme/Chef.pm view on Meta::CPAN
}
return $dump;
}
# private function _get_paragraphs
sub _get_paragraphs {
my $self = shift;
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return split /\n{2,}/, $string;
}
# private function _paragraphsToRecipes
#
# Constructs recipes from an array ref of paragraphs.
sub _paragraphsToRecipes {
my $self = shift;
my $paragraphs = shift;
$paragraphs = shift if not defined $paragraphs or not ref $paragraphs;
while (chomp @$paragraphs) {}
my @recipes;
my $paragraph_no = 0;
while (@$paragraphs) {
my $recipe_name = shift @$paragraphs;
$paragraph_no++;
$recipe_name =~ /^[ ]*([\-\w][\- \w]*)\.[ ]*$/
or croak "Invalid recipe name specifier in paragraph no. $paragraph_no.";
$recipe_name = lc($1);
last unless @$paragraphs;
my $comments = shift @$paragraphs;
$paragraph_no++;
my $ingredients;
if ( $comments =~ /^[ ]*Ingredients\.[ ]*\n/ ) {
$ingredients = $comments;
$comments = '';
} else {
last unless @$paragraphs;
$ingredients = shift @$paragraphs;
$paragraph_no++;
}
last unless @$paragraphs;
my $cooking_time = shift @$paragraphs;
$paragraph_no++;
my $temperature;
if ($cooking_time =~ /^[ ]*Cooking time:[ ]*(\d+)(?: hours?| minutes?)\.[ ]*$/) {
$cooking_time = $1;
last unless @$paragraphs;
$temperature = shift @$paragraphs;
$paragraph_no++;
} else {
$temperature = $cooking_time;
$cooking_time = '';
}
my $method;
if ($temperature =~ /^[ ]*Pre-heat oven to (\d+) degrees Celsius(?: gas mark (\d+))?\.[ ]*$/) {
$temperature = $1;
$temperature .= ",$2" if defined $2;
last unless @$paragraphs;
$method = shift @$paragraphs;
$paragraph_no++;
} else {
$method = $temperature;
$temperature = '';
}
$method =~ /^[ ]*Method\.[ ]*\n/
or croak "Invalid method specifier in paragraph no. $paragraph_no.";
my $serves = '';
if (@$paragraphs) {
$serves = shift @$paragraphs;
if ($serves =~ /^[ ]*Serves (\d+)\.[ ]*$/) {
$serves = $1;
$paragraph_no++;
} else {
unshift @$paragraphs, $serves;
$serves = '';
}
}
push @recipes, Acme::Chef::Recipe->new(
name => $recipe_name,
comments => $comments,
ingredients => $ingredients,
cooking_time => $cooking_time,
temperature => $temperature,
method => $method,
serves => $serves,
);
}
return @recipes;
}
1;
__END__
=back
=head1 DESIGN PRINCIPLES
=over 2
lib/Acme/Chef.pm view on Meta::CPAN
=head2 Recipe Title
The recipe title describes in a few words what the program does. For
example: "Hello World Souffle", or "Fibonacci Numbers with Caramel Sauce".
The recipe title is always the first line of a Chef recipe, and is
followed by a full stop.
recipe-title.
=head2 Comments
Comments are placed in a free-form paragraph after the recipe title.
Comments are optional.
=head2 Ingredient List
The next item in a Chef recipe is the ingredient list. This lists the
ingredients to be used by the program. The syntax is
Ingredients.
[initial-value] [[measure-type] measure] ingredient-name
[further ingredients]
Ingredients are listed one per line. The intial-value is a number.
I<New specification: The initial-value is now optional. Attempting to
use an ingredient without a defined value is a run-time error.>
The optional measure can be any of the following:
=over 2
=item *
C<g> | C<kg> | C<pinch[es]> : These always indicate dry measures.
=item *
C<ml> | C<l> | C<dash[es]> : These always indicate liquid measures.
=item *
C<cup[s]> | C<teaspoon[s]> | C<tablespoon[s]> : These indicate measures
which may be either dry or liquid.
=back
The optional measure-type may be any of the following:
=over 2
=item *
C<heaped> | C<level> : These indicate that the measure is dry.
=back
The ingredient-name may be anything reasonable, and may include space
characters. The ingredient list is optional. If present, it declares
ingredients with the given initial values and measures.
=head2 Cooking Time
Cooking time: time (hour[s] | minute[s]).
The cooking time statement is optional. The time is a number.
=head2 Oven Temperature
Pre-heat oven to temperature degrees Celcius [(gas mark mark)].
Some recipes require baking. If so, there will be an oven
temperature statement. This is optional. The temperature and mark are
numbers.
=head2 Method
Method.
method statements
The method contains the actual recipe instructions. These are written
in sentences. Line breaks are ignored in the method of a recipe. Valid
method instructions are:
=over 2
=item *
C<Take ingredient from refrigerator.>
I<New specification!> This reads lines from STDIN until a
numerical value is found. This numerical value is put into the
ingredient overwriting any previous value.
=item *
C<Put ingredient into [nth] mixing bowl.>
This puts the ingredient into the nth mixing bowl.
=item *
C<Fold ingredient into [nth] mixing bowl.>
This removes the top value from the nth mixing bowl and places it in
the ingredient.
=item *
C<Add ingredient [to [nth] mixing bowl].>
This adds the value of ingredient to the value of the ingredient on top
of the nth mixing bowl and stores the result in the nth mixing bowl.
=item *
C<Remove ingredient [from [nth] mixing bowl].>
This subtracts the value of ingredient from the value of the ingredient
on top of the nth mixing bowl and stores the result in the nth mixing bowl.
=item *
C<Combine ingredient [into [nth] mixing bowl].>
( run in 0.355 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )