File Coverage

blib/lib/Convert/CookingTimes.pm
Criterion Covered Total %
statement 42 43 97.6
branch 5 8 62.5
condition 4 6 66.6
subroutine 7 7 100.0
pod 2 2 100.0
total 60 66 90.9


line stmt bran cond sub pod time code
1             package Convert::CookingTimes;
2              
3 1     1   22574 use 5.006;
  1         2  
  1         42  
4 1     1   6 use strict;
  1         2  
  1         49  
5 1     1   5 use warnings FATAL => 'all';
  1         6  
  1         53  
6              
7 1     1   6 use List::Util;
  1         1  
  1         75  
8 1     1   519 use Math::Round;
  1         6719  
  1         442  
9              
10             our $VERSION = '0.01';
11              
12             =head1 NAME
13              
14             Convert::CookingTimes - work out cooking times adjusted for temperature
15              
16              
17             =head1 SYNOPSIS
18              
19             Given a set of item names, temperatures and durations, works out the average
20             temperature and adjusts the times to suit that temperature, then returns a list
21             of suggested timings.
22              
23              
24             my ($temperature, @steps) = @steps = Convert::CookingTimes->adjust_times(
25             { name => 'Chicken breasts', temp => 200, time => 20 },
26             { name => 'Chips', temp => 220, time = 25 },
27             );
28             say "Warm oven up to $temperature degrees first.";
29             for my $step (@steps) {
30             say "Put $step->{name} in the oven, and wait for $step->{time_until_next}";
31             }
32              
33             # You can also feed the result of adjust_times to summarise_instructions to
34             # provide a simple set of instructions, e.g.:
35             say Convert::CookingTimes->summarise_instructions(
36             Convert::CookingTimes->adjust_times(\@items)
37             );
38              
39              
40             =head1 DESCRIPTION
41              
42             Often find yourself cooking a variety of things, the cooking instructions for
43             each requiring a different temperature and time?
44              
45             This module attempts to work out the appropriate oven temperature as an average
46             of all the items, and adjusts their cooking times based on that temperature -
47             so if they're going to be at a higher temperature the time is reduced and vice
48             versa.
49              
50             Results may vary - providing items with a wide variation of temperatures could
51             result in some foods being cooked at sub-optimal temperatures, and obviously you
52             need to sanity-check the results, and be particularly careful to check that meat
53             and poultry has reached a safe internal temperature etc. This is an algorhythm,
54             not a cook!
55              
56              
57             =head1 SUBROUTINES/METHODS
58              
59             =head2 adjust_times
60              
61             Takes a list or arrayref of hashrefs, each of which contains details of an
62             item being cooked, with the keys:
63              
64             =over
65              
66             =item name
67              
68             The name of the item
69              
70             =item temp
71              
72             The temperature the item's cooking instructions call for, in degrees Celcius
73              
74             =item time
75              
76             The cooking time the item's cooking instructions call for, in minutes
77              
78             =back
79              
80             Returns a suggested oven temperature, and an arrayref of cooking times adjusted
81             to suit that temperature.
82              
83             =cut
84              
85             sub adjust_times {
86 2     2 1 1229 my $class = shift;
87 2 50       6 my @items = ref $_[0] eq 'ARRAY' ? @{$_[0]} : @_;
  0         0  
88              
89             # First off: pick our desired temperature, as an average of all the
90             # temperatures, rounded to the nearest 10
91 6         22 my $desired_temp = Math::Round::nearest_ceil(10,
92 2         3 List::Util::sum(map { $_->{temp} } @items) / scalar @items
93             );
94              
95             # Now, for each item, work out its adjusted time and add to the output list:
96 2         21 my @times;
97 2         3 for my $item (@items) {
98 6         38 push @times, {
99             name => $item->{name},
100             adjusted_time => Math::Round::round(
101             ($item->{temp} * $item->{time}) / $desired_temp
102             ),
103             };
104             }
105              
106             # Finally, return the items, sorted by longest cooking duration first,
107             # with the time until the next item should be started included
108 2         10 my @output;
109 2         7 @times = sort { $b->{adjusted_time} <=> $a->{adjusted_time} } @times;
  6         8  
110 2         5 while (my $item = shift @times) {
111 6 100       7 if (my $next_item = $times[0]) {
112 4         6 $item->{time_until_next} = $item->{adjusted_time} - $next_item->{adjusted_time};
113             }
114 6         10 push @output, $item;
115             }
116            
117 2         6 return $desired_temp, \@output;
118             }
119              
120              
121             =item summarise_instructions
122              
123             Given the results of adjust_times, produce a list of instructions.
124              
125             For instance:
126              
127             - Warm oven up to 200 degrees
128             - Add Chicken Breasts, cook for 5 minutes
129             - Add Oven Chips, cook for 20 minutes
130              
131             Returns a list of instruction steps if called in list context, or that list
132             joined with newlines if called in scalar context.
133              
134             =cut
135              
136             sub summarise_instructions {
137 1     1 1 1 my $self = shift;
138 1         1 my $temp = shift;
139 1 50       3 my @items = ( ref $_[0] eq 'ARRAY' ? @{$_[0]} : @_ );
  1         2  
140            
141 3   66     9 my $total_mins = List::Util::sum(
142 1         2 map { $_->{time_until_next} // $_->{adjusted_time} } @items
143             );
144 1         2 my @instructions;
145 1         3 push @instructions, "Warm oven up to $temp degrees.";
146 1         7 push @instructions, "Cooking the whole meal will take $total_mins minutes.";
147              
148 1         2 for my $item (@items) {
149 3   66     11 push @instructions, sprintf "Add %s and cook for %d minutes",
150             $item->{name}, $item->{time_until_next} || $item->{adjusted_time};
151             }
152            
153 1 50       5 return wantarray ? @instructions : join "\n", @instructions;
154             }
155              
156              
157              
158             =head1 AUTHOR
159              
160             David Precious, C<< >>
161              
162             =head1 BUGS / CONTRIBUTING
163              
164             This module is developed on GitHub - bug reports, suggestions, and pull requests
165             welcomed:
166              
167             L
168              
169              
170              
171             =head1 SUPPORT
172              
173             You can find documentation for this module with the perldoc command.
174              
175             perldoc Convert::CookingTimes
176              
177              
178              
179             =head1 LICENSE AND COPYRIGHT
180              
181             Copyright 2015 David Precious.
182              
183             This program is free software; you can redistribute it and/or modify it
184             under the terms of the the Artistic License (2.0). You may obtain a
185             copy of the full license at:
186              
187             L
188              
189             Any use, modification, and distribution of the Standard or Modified
190             Versions is governed by this Artistic License. By using, modifying or
191             distributing the Package, you accept this license. Do not use, modify,
192             or distribute the Package, if you do not accept this license.
193              
194             If your Modified Version has been derived from a Modified Version made
195             by someone other than you, you are nevertheless required to ensure that
196             your Modified Version complies with the requirements of this license.
197              
198             This license does not grant you the right to use any trademark, service
199             mark, tradename, or logo of the Copyright Holder.
200              
201             This license includes the non-exclusive, worldwide, free-of-charge
202             patent license to make, have made, use, offer to sell, sell, import and
203             otherwise transfer the Package with respect to any patent claims
204             licensable by the Copyright Holder that are necessarily infringed by the
205             Package. If you institute patent litigation (including a cross-claim or
206             counterclaim) against any party alleging that the Package constitutes
207             direct or contributory patent infringement, then this Artistic License
208             to you shall terminate on the date that such litigation is filed.
209              
210             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
211             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
212             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
213             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
214             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
215             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
216             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
217             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
218              
219              
220             =cut
221              
222             1; # End of Convert::CookingTimes