Datasheet
Chapter 1: Building Resources
28
The unit method actually has provisions not to consume the token. If the token is numerical, the parser
assumes it ’ s a continuation of the amount, resets the state, and returns
false so that the amount method
will take a crack at the same token. For example:
def unit(token)
if token.to_i > 0
self.state = :amount
return false
end
if UNITS.index(token) or UNITS.index(token.pluralize)
result.unit = token.pluralize
self.state = :ingredient
return true
else
self.state = :ingredient
return false
end
end
If the token is not numerical, then it ’ s checked against the list of known units maintained by the parser. If
there ’ s a match, then the token is consumed as the unit. If not, the token is not consumed. In either case,
the parser moves on to the ingredient itself. Here ’ s an example of how this works:
def ingredient(token)
ingredient_words < < token
if token.ends_with?(“,”)
ingredient_words[-1].chop!
self.state = :instruction
end
true
end
The ingredient name is assumed to continue until the parser runs out of tokens, or until a token ends in a
comma, as in
“ carrots, diced ” . Although none of the test cases expose it at this point, that ’ s easily
broken in the case where the ingredient is a list containing a comma. However, this error is handled
gracefully by the parser, and is also rather straightforward for the enterer to correct, so I chose not to beef
up the parser at this time.
Once you get past the comma, everything else is assumed to be part of the final instruction, as follows:
def instruction(token)
instruction_words < < token
true
end
To use this, a class method in Ingredient sets the defaults and invokes the parser like this:
def self.parse(str, recipe = nil, order = nil)
result = Ingredient.new(:recipe_id = > recipe.id,
:order_of = > order, :ingredient = > “”,
c01.indd 28c01.indd 28 1/30/08 4:02:29 PM1/30/08 4:02:29 PM