HowTo: Create a Home Cooks Recipe Book using the Linux Shell and RunRev GUI Part 5
Novell Cool Solutions: Feature
By Stomfi
Reader Rating 
|
Digg This -
Slashdot This
Posted: 5 Jul 2005 |
This HowTo continues from Part One the creation of a home cook's recipe system using the shell and Runtime Revolution. Unlike MS Windows versions, it does not track nutritional information, as it is just for collecting favourite recipes, which you are going to eat because you like them. It does, however, attempt to give you a shopping list based on common package sizes, or where relevant a delicatessen quantity. It also has a space for a picture, which you can take to remind you what it should look like.
In this fourth part we finish developing the shopping list system. A shopping list is different from an ingredients list, which deals with cups and teaspoons, because its quantities are either in package sizes or piece quantities.
Special Offer for Cool Solutions Readers: Free Copy of Runtime Revolution |
|
Actually, what we are doing here is quite mind boggling as we are taking a recipe ingredient name and quantity, like "1/2 CUP Chopped Parsley" and changing it to read "1 bunch Parsley" in the shopping list. This is all about matching patterns, and what you apply here will help you to create other reports from arbitrarily worded information, formatted as knowledge. This type of shell scripting can be used to create contents and indexes.
This is a view of the recipe card for Tasmanian Prawns with American Pecan Pesto including picture.
You can see I've added a button for a Shopping List to this card.
Create a new card and name it SHOP. Here it is with a shopping list for the Prawn recipe.
Here is the card script.
on openCard global RECIPEIDX #get the picture from the recipe card put the filename of image "TPIC" of card "SHOWRECIPE" into PICFILE set the filename of image "TPIC" to PICFILE #fill the SHOPLIST field put ($HOME & "/cookbook/bin/shoplist.sh" && RECIPEIDX) into GETLIST replace return with empty in GETLIST put the shell of GETLIST into field "SHOPLIST" end openCard
Here is the Print button script.
on mouseUp
put ($HOME & "/cookbook/printlist.txt") into PRINTLIST
#Make sure the printlist file exists
put ("touch" && PRINTLIST) into TPRINT
put the shell of TPRINT into DUNTOUCH
open file PRINTLIST for write
write field "SHOPLIST" to file PRINTLIST
close file PRINTLIST
#Use lpr to print the file. If you have more than one printer, you can specify
#which one with "lpr -P PrinterName" Have a look at "man lpr"
put ("lpr" && PRINTLIST) into PRSHELL
put the shell of PRSHELL into DUNPR
end mouseUp
Finally, we look at the shell script that does all the work. It's probably the biggest script we have written. When developing this script I inserted lines at the end of control structures like after a "fi" or before a "done" which said:
read "DEBUG"
and ran the script with the command:
sh -x ./shoplist.sh 2
This lets you see the results without having to run the whole script, and see if what you think should happen is actually happening. You have to press the Enter key to get past the "read DEBUG" command.
Sometimes, before the "read" command, you can put an "echo $VariableName" or a "cat $FileName" to see the results.
This is the shoplist.sh shell script:
#!/bin/bash
#
#shoplist.sh index
#
#Set the ingredients files
INGFILE="$HOME/cookbook/book/mingreds.txt"
INGQ="$HOME/cookbook/ingquant.txt"
INGN="$HOME/cookbook/ingname.txt"
INGTEMP="$HOME/cookbook/ingtemp.txt"
INGNTEMP="$HOME/cookbook/ingntemp.txt"
INGNEW="$HOME/cookbook/ingnew.txt"
INGNEWALL="$HOME/cookbook/ingnewall.txt"
rm -f $INGNEWALL $INGNEW
touch $INGNEWALL $INGNEW
#
#Set the shopping packages file
PACKFILE="$HOME/cookbook/book/shoppkgs.txt"
#
#For each ingredient check to see if it is in the packages file
#If it is, check the ingredient quantity and calculate the packages
#What we need is some way of calculating how big each measure quantity is
#So we need another file which tells us this info
#
MCALC="$HOME/cookbook/book/mcalc.txt"
#
#And another format for the ingredients file which can tell us solid or liquid
#and a mandatory measurement field using ONLY for arbitrary quantities
#The format for this file is
#"INDEX#Quantity#Measure#Name#S or L"
#
#Get the ingredients for this recipe
awk -F"#" -v IDX="$1" '{if($1 == IDX) print $0 }' $INGFILE > $INGTEMP
#
#Replace Measurements with shopping quantity calculation in $INGTEMP
#Find out how many records there are
NUMRECS=`wc "$INGTEMP" | awk '{print $1}'`
#
for (( n = 1; n <= $NUMRECS; n++ ))
do
#Empty out temporary calc variable
NEWQ=""
CALCMT=""
#Fill in the needed values
#Quantity
CALCQ=`awk -F"#" -v NUMREC=$n '{if(NR == NUMREC) print $2}' "$INGTEMP"`
#Measure
CALCT=`awk -F"#" -v NUMREC=$n '{if(NR == NUMREC) print $3}' "$INGTEMP"`
#Name
CALCN=`awk -F"#" -v NUMREC=$n '{if(NR == NUMREC) print $4}' "$INGTEMP"`
SOLID=`awk -F"#" -v NUMREC=$n '{if(NR == NUMREC) print $5}' "$INGTEMP"`
CONLY=`echo "$CALCT" | grep "ONLY"`
if [ "${#CONLY}" -lt 1 ]
then
#Not an ONLY
#First got to find out if the shopping quantity is 1
#as this will be a bunch or bulb or something
#Look for name in packfile and print quantity
PQUANT=`grep "$CALCN" $PACKFILE | awk -F"#" '{print $4}'`
#Check that there is one
if [ ${#PQUANT} -gt 0 ]
then
SQUANT="$PQUANT"
else
#The match might be restricted by a words like "finely chopped"
# so do another search without the first words
#Find out if there are words to chop off
#
#This is a new way to create a test right inside the if statement
#without first creating a variable holder
if [ `echo "$CALCN" | wc -w` -gt 2 ]
then
#Cut off all words after the third with -f3-
SHORTN=`echo "$CALCN" | cut -d" " -f3- `
else
#Cut off all words after the second
SHORTN=`echo "$CALCN" | cut -d" " -f2- `
fi
PQUANT=`grep -F "$SHORTN" $PACKFILE | awk -F"#" '{print $4}'`
#Check that there is one. There always should be but mistake do happen.
if [ ${#PQUANT} -gt 0 ]
then
SQUANT="$PQUANT"
#Set name to short name so we can find it later in the script
CALCN="$SHORTN"
else
SQUANT=0
fi
fi
if [ "$SQUANT" -gt 1 ]
then
#This is a package sized quantity
CALCB=`grep "$CALCT" $MCALC | grep "#$SOLID#"`
#Quantity
CALCMS=`echo $CALCB | cut -d"#" -f3`
#Measure
CALCMT=`echo $CALCB | cut -d"#" -f4`
#Use bc to calculate decimals
SNEWQ=`echo "scale = 2; $CALCQ*$CALCMS" | bc -l`
#Make into a whole number if a decimal
#Look for a decimal dot. Have to escape the dot with \ as it means any character by itself
ISDEC=`echo $SNEWQ | grep '\.' `
if [ ${#ISDEC} -gt 0 ]
then
#Divide it into two parts
DECPART=`echo "$SNEWQ" | cut -d"." -f2`
INTPART=`echo "$SNEWQ" | cut -d"." -f1`
if [ $DECPART -gt 0 ]
then
let NEWQ=($INTPART + 1)
else
let NEWQ=$INTPART
fi
else
#Not a decimal
NEWQ=$SNEWQ
fi
#Which is larger
if [ $SQUANT -gt $NEWQ ]
then
#Order this much
THISQU=$SQUANT
else
#Order enough to satisfy recipe
THISQU=$NEWQ
fi
#create shopping line
#Name
CALCMN=`grep "$CALCN" $PACKFILE | cut -d"#" -f1`
awk -F"#" -v NEWSQ=$THISQU -v NUMREC=$n -v NEWM="$CALCMT" \
-v NEWN="$CALCMN" 'BEGIN{OFS = " "}; \
{if(NR == NUMREC) {$2 = NEWSQ; $3 = NEWM; $4=NEWN; \
print $2, $3, $4}}' $INGTEMP > $INGNEW
#Save each line
cat $INGNEW >> $INGNEWALL
else
if [ "$SQUANT" -eq 1 ]
then
#SQUANT is 1 so use the Pack
#Look for name in packfile and print quantity and measure
NEWINGR=`grep "$CALCN" $PACKFILE | awk -F"#" '{print $4 " " $3 " " $1}'`
if [ ${#NEWINGR} -gt 0 ]
then
#Got a package for this ingredient
awk -F"#" -v NUMREC=$n -v NNAME="$NEWINGR" 'BEGIN{OFS = " "};\
{if(NR == NUMREC) print NNAME}' $INGTEMP > $INGNEW
#Save each line
cat $INGNEW >> $INGNEWALL
fi
else
if [ "$SQUANT" -eq 0 ]
then
#
#Look for name in packfile and print quantity and measure
NEWINGR=`grep "$CALCN" $PACKFILE | awk -F"#" '{print $4 " " $3 " " $1}'`
if [ ${#NEWINGR} -gt 0 ]
then
#Got a package for this ingredient
awk -F"#" -v NUMREC=$n -v NNAME="$NEWINGR" 'BEGIN{OFS = " "};\
{if(NR == NUMREC) print NNAME}' $INGTEMP > $INGNEW
#Save each line
cat $INGNEW >> $INGNEWALL
else
#No Package size. This is actually an error in the Package file like a missing package name.
awk -F"#" -v NUMREC=$n 'BEGIN{OFS = " "};\
{if(NR == NUMREC) print $2, $3, $4}' $INGTEMP > $INGNEW
#Save each line
cat $INGNEW >> $INGNEWALL
fi
fi
fi
fi
else
#Is an ONLY so create quantity from recipe quantity
#Unless there is a pack
#Look for name in packfile and print quantity, measure and name
NEWINGR=`grep "$CALCN" $PACKFILE | awk -F"#" '{print $4 " " $3 " " $1}'`
if [ ${#NEWINGR} -gt 0 ]
then
#Got a package for this ingredient
awk -F"#" -v NUMREC=$n -v NNAME="$NEWINGR" 'BEGIN{OFS = " "};\
{if(NR == NUMREC) print NNAME}' $INGTEMP > $INGNEW
#Save each line
cat $INGNEW >> $INGNEWALL
else
#No Package size
awk -F"#" -v NUMREC=$n 'BEGIN{OFS = " "};\
{if(NR == NUMREC) print $2, $3, $4}' $INGTEMP > $INGNEW
#Save each line
cat $INGNEW >> $INGNEWALL
fi
fi
done
#Print out all the saved lines
cat $INGNEWALL
I hope you can follow this script. I've started to show you some more advanced shell techniques in this script.
Don't worry, I'm taking it real easy as I want you to learn without any pressure. As you notice I keep on explaining what the script is trying to do.
All that's left is to save the RunRev stack and create the standalone, then work out the measurement calculations file, and fill the application up with all your favourite recipes, especially the easy ones you can impress your partner with, or your parents, friends, pets, and visitors from across the galaxy.
Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com
Learning to use Linux at Home and Work