#!perl # # foodratio - calculate ingredient ratios use 5.26.0; use warnings; use Food::Ratio; use Getopt::Long 'GetOptions'; my ( $mass, @ratio_args, @weigh_args ); GetOptions( 'mass=f' => sub { die "foodratio: mass must be a positive number\n" unless $_[1] > 0; $mass = $_[1]; }, 'ratio=s' => sub { my ( $key, $value ) = split ':', $_[1], 2; die "foodratio: ratio key must be 'id' or 'group'\n" unless $key eq 'id' or $key eq 'group'; @ratio_args = ( $key, $value ); }, 'weigh=s' => sub { my ( $key, $value ) = split ':', $_[1], 2; die "foodratio: weigh key must be 'id' or 'group'\n" unless $key eq 'id' or $key eq 'group'; @weigh_args = ( $key, $value ); }, ) or exit 64; my $fr = Food::Ratio->new; while ( my $line = readline ) { last if $line =~ m/^-/; # so we can `foodratio | foodratio` chomp $line; my ( $mass, $name, @rest ) = split ' ', $line; # probably the 2nd column is ratios, assume name is in next column $name = shift @rest if $name =~ m/[%]/; $fr->add( $mass, $name, @rest ); } $fr->ratio(@ratio_args); $fr->weigh( $mass, @weigh_args ) if defined $mass; print $fr->string; __END__ =head1 NAME foodratio - calculate ingredient ratios =head1 SYNOPSIS $ cat recipe 1 egg wet 2 water wet 4 flour dry $ foodratio recipe $ foodratio --ratio id:flour recipe $ foodratio --mass 55 --weigh group:wet recipe =head1 DESCRIPTION Given a list of measurements of ingredients, foodratio will calculate the ratio between those various inputs, optionally using some ingredient (or group of ingredients) as the ratio key. The weights can be recalculated based on the measurement of a particular ingredient. The input should be in columns, with the mass (or whatever measurement) as the first column. This must be a strictly positive number. If the second column contains C<%> it will be ignored, on the presumption that that is a ratio. Thus the name (id) of the ingredient will come from either the second or third column. The remainder of the columns, if any, will be treated as group names that collect ingredients into groups, e.g. a custom C<flour> group for recipes with different types of flour, or so forth. Lines beginning with C<-> are ignored; this allows C<foodratio> output to be piped to C<foodratio>. =head2 Options =over 4 =item B<mass> I<positive-number> Sets the mass for the B<weigh> method; ingredient measurements will be recalculated based on this amount. =item B<ratio> I<key:value> Sets the ingredient or ingredient group to use as the key value for the ratio calculation, e.g. flour in a bread recipe and not the default total mass. I<key> must be C<id> or C<group>. By default the ratio is taken from the total of the ingredients. =item B<weigh> I<key:value> Sets the ingredient or ingredient group to use as the basis for the B<mass> argument. By default the weight is taken from the total of the ingredients. =back =head1 EXAMPLES Given a file containing 160 cornmeal flour dry 150 flour flour dry 11 bpowder dry 3.5 salt dry 30 sugar dry 250 milk wet 70 oil fat wet 58 egg wet one may weigh an egg and discover that it is 55 grams, and rescale the recipe based on that $ foodratio cornbread | grep cornmeal 160 21.84% cornmeal flour dry $ foodratio --mass 55 --weigh id:egg cornbread | grep cornmeal 151.7 21.84% cornmeal flour dry and know to use 152 grams of cornmeal instead of 160. To preserve the ratios (e.g. based on the flour, as is typical in baking) also add the I<--ratio> option: $ foodratio --mass 55 --weigh id:egg --ratio group:flour cornbread ... =head1 SEE ALSO L<Food::Ratio> =head1 COPYRIGHT AND LICENSE Copyright 2022 Jeremy Mates This program is distributed under the (Revised) BSD License: L<https://opensource.org/licenses/BSD-3-Clause> =cut