@@ -59,4 +59,103 @@ export default class Recipe {
5959 // by just saying that every dish will serve 4 people no matter what.
6060 this . servings = 4 ;
6161 }
62+ 63+ parseIngredients ( ) {
64+ // We create 2 Maps where one map stores the units that can occur in plural form,
65+ // for eg: teaspoons, tablespoons, etc and then store their values into short-form
66+ // units, which are tsp, tbsp, etc, respectively. And another map for units that
67+ // can occur in singular form i.e., teaspoon, tablespoon, etc. We will convert all of
68+ // the singular units also into an their respective short-forms as show n above.
69+ const abbrUnits = [ 'tbsp' , 'tsp' , 'cup' , 'oz' , 'pound' ] ;
70+ 71+ const pluralUnits = new Map ( ) ;
72+ pluralUnits . set ( 'tablespoons' , abbrUnits [ 0 ] ) ;
73+ pluralUnits . set ( 'teaspoons' , abbrUnits [ 1 ] ) ;
74+ pluralUnits . set ( 'cups' , 'cup' ) ;
75+ pluralUnits . set ( 'ounces' , abbrUnits [ 3 ] ) ;
76+ pluralUnits . set ( 'pounds' , abbrUnits [ 4 ] ) ;
77+ 78+ const singularUnits = new Map ( ) ;
79+ singularUnits . set ( 'tablespoon' , abbrUnits [ 0 ] ) ;
80+ singularUnits . set ( 'teaspoon' , abbrUnits [ 1 ] ) ;
81+ singularUnits . set ( 'ounce' , abbrUnits [ 3 ] ) ;
82+ 83+ const newIngredients = this . ingredients . map ( el => {
84+ // 1. Uniform units
85+ let ingredient = el . toLowerCase ( ) ;
86+ for ( let [ key , value ] of pluralUnits . entries ( ) ) {
87+ if ( ingredient . includes ( key ) )
88+ ingredient = ingredient . replace ( key , value ) ;
89+ }
90+ 91+ for ( let [ key , value ] of singularUnits . entries ( ) ) {
92+ if ( ingredient . includes ( key ) )
93+ ingredient = ingredient . replace ( key , value ) ;
94+ }
95+ 96+ // 2. Remove Parentheses --- Regex taken from:
97+ // https://stackoverflow.com/questions/4292468/javascript-regex-remove-text-between-parentheses
98+ ingredient = ingredient . replace ( / \( [ ^ ) ] * \) / g, '' ) ;
99+ 100+ // 3. Parse ingredients into count, unit and ingredient
101+ // The hardest part of parsing the ingredients is to separate out the count and units.
102+ // That's because in the list of ingredients, some have the count in-front
103+ // and some don't. Therefore, we have to be clever about the way we decouple the quantity
104+ // and the unit of the ingredient. A good way is to use the index of the unit
105+ // and then decouple the quantity from the unit.
106+ const arrIng = ingredient . split ( ' ' ) ;
107+ const unitIndex = arrIng . findIndex ( el => abbrUnits . includes ( el ) ) ;
108+ 109+ let objIng ;
110+ if ( unitIndex > - 1 ) {
111+ // There is a unit -- the difficult one to implement.
112+ 113+ // first we pick the quantity(s) before the units
114+ // Ex. if arrIng is ['4, '1/2', 'cup', ...] => arrCount is ['4', 1/2']
115+ // Ex. if arrIng is ['4', 'cup', ...] => arrCount is ['4']
116+ const arrCount = arrIng . slice ( 0 , unitIndex ) ;
117+ 118+ let count ;
119+ if ( arrCount . length === 1 )
120+ count = eval ( arrIng [ 0 ] . replace ( '-' , '+' ) ) ; // For the strings which are like: '1-1/2 cup'
121+ else {
122+ // Now, we have the elements of arrCount as strings, but we are also sure that they are
123+ // strings that are numeric in nature. Therefore, whenever we have such a situation, we can
124+ // simply call the eval() method on the string (which is an arithmetic expression), so that it
125+ // can evaluate the arithmetic expression passed to it.
126+ count = eval ( arrCount . slice ( ) . join ( '+' ) ) ;
127+ 128+ // if arrCount is ['4', '1/2'], then the line above will convert into '4+1/2' and then that's
129+ // passed onto the eval() method which will then evaluate the expression as JS Code, and actually
130+ // the string as an arithmetic expression and return 4.5
131+ }
132+ 133+ objIng = {
134+ count,
135+ unit : arrIng [ unitIndex ] ,
136+ ingredient : arrIng . slice ( unitIndex + 1 ) . join ( ' ' )
137+ } ;
138+ 139+ } else if ( parseInt ( arrIng [ 0 ] , 10 ) ) {
140+ // There is NO unit, but 1st element is a number
141+ objIng = {
142+ count : parseInt ( arrIng [ 0 ] , 10 ) ,
143+ unit : '' ,
144+ ingredient : arrIng . slice ( 1 ) . join ( ' ' )
145+ } ;
146+ } else if ( unitIndex === - 1 ) {
147+ // There is NO unit and NO number in 1st position
148+ objIng = {
149+ count : 1 ,
150+ unit : '' ,
151+ ingredient // In ES6, to mention 'ingredient: ingredient', we need not assign it, we simply
152+ // mention it. Therefore, 'ingredient: ingredient' can be written as 'ingredient'
153+ } ;
154+ }
155+ 156+ return objIng ;
157+ } ) ;
158+ 159+ this . ingredients = newIngredients ;
160+ }
62161} ;
0 commit comments