2016-01-14 15:22:15 -06:00
|
|
|
module UnitConversion
|
|
|
|
|
|
|
|
UNIT_PARSING_REGEX = /^(?<value>(?:-?[0-9]+)?(?:\.?[0-9]*)?)\s*(?<unit>[a-z\/.\-()0-9]+)$/
|
|
|
|
|
2016-01-15 09:41:24 -06:00
|
|
|
UNIT_ALIASES = {
|
|
|
|
cup: %w(cups c),
|
|
|
|
tablespoon: %w(tbsp tbs tablespoons),
|
|
|
|
teaspoon: %w(tsp teaspoons),
|
|
|
|
ounce: %w(oz ounces),
|
|
|
|
pound: %w(pounds lb lbs),
|
|
|
|
pint: %w(pints),
|
|
|
|
quart: %w(quarts),
|
|
|
|
gallon: %w(gallons ga),
|
|
|
|
|
|
|
|
gram: %w(grams g),
|
|
|
|
kilogram: %w(kilograms kg)
|
|
|
|
}
|
|
|
|
|
|
|
|
UNIT_ALIAS_MAP = Hash[UNIT_ALIASES.map { |unit, values| values.map { |v| [v, unit] } }.flatten(1)]
|
|
|
|
|
2016-01-14 15:22:15 -06:00
|
|
|
class UnparseableUnitError < StandardError
|
|
|
|
end
|
|
|
|
|
|
|
|
class UnknownUnitError < UnparseableUnitError
|
|
|
|
end
|
|
|
|
|
|
|
|
class << self
|
|
|
|
|
|
|
|
def parse(unit_string)
|
|
|
|
match = UNIT_PARSING_REGEX.match(unit_string.to_s.strip)
|
|
|
|
|
|
|
|
if match && match[:value].present? && match[:unit].present?
|
|
|
|
begin
|
|
|
|
Unitwise(match[:value].to_f, match[:unit])
|
|
|
|
rescue Unitwise::ExpressionError => err
|
|
|
|
raise UnknownUnitError, err.message
|
|
|
|
end
|
|
|
|
else
|
|
|
|
raise UnparseableUnitError, "'#{unit_string}' does not appear to be a valid measurement of the form <value> <units> (ie '5 cup' or '223 gram/cup')"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def density?(unit)
|
|
|
|
unit.compatible_with? Unitwise(1, 'g/ml')
|
|
|
|
end
|
|
|
|
|
2016-01-15 09:41:24 -06:00
|
|
|
def normalize_unit_names(unit_description)
|
|
|
|
result = unit_description.dup
|
|
|
|
|
|
|
|
result = result.downcase.gsub(/[a-z]+/) do |match|
|
|
|
|
UNIT_ALIAS_MAP[match] || match
|
|
|
|
end
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2016-01-14 15:22:15 -06:00
|
|
|
end
|
|
|
|
end
|