[2021-07-13 Update: Didn't take long after my initial post to make some major changes. Embarassing that I didn't get it right the first time.]
Another Perl/Linux-based salve to the mental aberration I've mentioned in the past: using my meager coding skills as a hammer to whack down life's occasional slightly-annoying nails. Specifically, grocery shopping. It's partially my job. Mrs. Salad provides me with a handwritten list. A recent example:
Nice handwriting, right? Yes, she really calls those cookie dough packages "plunk & bake". And this example is neater than average, shorter than average, and pretty well organized. Still… Often I'll be finishing up shopping in Aisle 13 of the Dover, New Hampshire Hannaford … and suddenly realize that I missed getting something back in Aisle 2.
(Or sometimes not realizing I missed items until I get home.)
What I wanted was a list organized in the order in which I actually go through the store, separated into aisles (or departments) to make it easy to check that I've gotten (for example) all the Aisle 2 items before I move on to Aisles 3, 4, …
Something like this, an HTML table:
Loc/Aisle | Qty | Item | Notes |
---|---|---|---|
4 | Brownie Mix | ||
Jambalaya Mix | Large | ||
5 | Raisin Bran Crunch | ||
Pineapple Tidbits | |||
Rice Krispies | |||
6 | 2 | V8 | |
8 | Incredibites | Dry, Chicken | |
Back Wall | Milk | ||
Oatly | |||
11 | Bread | Artesano | |
13 | Cookie Dough | ||
Yogurt | |||
Pie Crust | |||
Ice Cream | Cherry Vanilla | ||
Outshine Coffee Bars |
In fact, exactly like that. You might notice I've added a couple items of my own; I'm in charge of keeping track of pet food, Raisin Bran Crunch, V-8, and a few other things.
Hence this script, listmaker
; it produces a suitable-for-printing HTML list
organizing the listed items into the order I traverse the store. Typically that's in ascending-aisle order,
but including the departments (Deli, Meat, Seafood, Bakery,…) on the store's periphery.
Before I leave (say) Aisle 2, it's easy to verify that I've picked up everything I was supposed
to get in Aisle 2.
The workflow is simple. First, I transcribe the handwritten list into a text file:
2 V8 Raisin Bran Crunch # Orange Juice # Eggs # Coffee Cookie Dough Milk Yogurt Oatly Pie Crust Brownie Mix Pineapple Tidbits Jambalaya Mix | Large Rice Krispies Bread|Artesano Ice Cream|Cherry Vanilla Outshine Coffee Bars Incredibites|Dry, Chicken
The syntax is simple, informal, and flexible:
- One "item" per line.
- Lines starting with a pound sign (#) are comments, and are ignored. Used for commonly-bought items; just remove the pound sign to include them, add one to exclude them.
- A leading digit string designating quantity is optional. Of course, a missing number implies quantity 1.
- An optional "Notes" field is text following a vertical bar (
|
). This can be used in many ways: specifying a brand, size, flavor,… Notes go in a separate column in the HTML table.
Once the list is transcribed, the script can be run. Example, assuming the
transcribed list above is in the file $HOME/Documents/mylist
:
$ listmaker ~/Documents/mylist
[HTML list saved at file:///home/pas/Documents/mylist.html]
As a somewhat arbitrary design choice, the HTML output file is written to the
same directory containing the list, with the .html
extension
tacked on.
I use a "store configuration file" for store-specific details. It contains Perl initialization code for two hashes:
-
%ORDER
which specifies the order in which I visit aisles/departments:%ORDER = ( '10' => 14, '11' => 16, '12' => 17, '13' => 18, '1' => 4, '2' => 5, '3' => 6, '4' => 7, '5' => 8, '6' => 9, '7' => 10, '8' => 12, '9' => 13, 'Back Wall' => 15, 'Bakery' => 1, 'Deli' => 2, 'Front End' => 21, 'Hbc 4l' => 20, 'Meat' => 11, 'Pharm' => 19, 'Produce' => 0, 'Seafood' => 3, );
In this case: the visitation order is: Produce, Bakery, Deli, Seafood, Aisle 1, 2, … (I've used
perltidy
to prettify the actual file.) -
%HMAP
which maps item names to aisles/locations. It contains many lines, here's a sample:%HMAP = ( 'v8' => '6', 'raisin bran crunch' => '5', 'brownie mix' => '4', 'pastrami' => 'Deli', 'ice cream' => '13', […] );
This hash can get messy and possibly redundant, especially if you (like me) are not consistent or careful in how you specify items. It's easy enough (if somewhat tedious) to clean up with a text editor.
The configuration file is loaded into the script with a Perl do
command.
Some basic sanity checks are performed.
The default location for the configuration file is $HOME/etc/listmaker.cf
. The idea here is
that if you want to use this script for more than one store, you use different configuration
files. A non-default configuration file is specified to the script with the -s
option, for example:
$ listmaker -s ~/Walmart.cf mylist
This is a project in my Github repository; the script is here. Notes:
-
The script uses the
HTML::Template
CPAN module to produce its HTML output. The template is pretty straightforward and it is here. -
If there's an item on the script not found in the configuration file, the script will
ask that you provide an aisle/location for it. Good news: your response will be
used to update the configuration file, so you won't need to do that in the future.
(Specifically, the script uses the
Data::Dumper
Perl module to produce new initialization code for the hashes described above, written back out to the file.)