parsley/lib/unit_conversion/value_unit.rb

173 lines
3.6 KiB
Ruby
Raw Normal View History

module UnitConversion
class ValueUnit
def self.for(value_string, unit_string = nil, formatter = nil)
raise UnparseableUnitError, "value is empty" if value_string.blank?
2016-02-27 20:12:41 -06:00
if ValueUnit === value_string
return value_string
end
if String === value_string && unit_string.nil?
value_string, unit_string = parse_single_string(value_string)
end
if value_string.is_a?(ParsedNumber)
value = value_string
else
value = ParsedNumber.new(value_string)
end
unit = case unit_string
when nil
nil
when ->(u) { u.blank? }
nil
when ParsedUnit
unit_string
else
ParsedUnit.new(unit_string)
end
if unit.nil?
ValueNoUnit.new(value, formatter)
else
ValueUnit.new(value, unit, formatter)
end
end
def self.parse_single_string(value_unit_string)
match = UNIT_PARSING_REGEX.match(value_unit_string.to_s.strip)
if match && match[:value].present?
return match[:value], match[:unit]
else
raise UnparseableUnitError, "'#{value_unit_string}' does not appear to be a valid measurement of the form <value> <units> (ie '5 cup' or '223 gram/cup')"
end
end
attr_reader :formatter
def initialize(value, unit, formatter = nil)
@value = value
@unit = unit
@formatter = formatter || NumberFormatter.for(value, unit)
end
def to_s
"#{pretty_value} #{unit}"
end
def unit
@unit
end
def value
@value
end
def raw_value
@value.value
end
def unitwise
unit.unitwise(value.value)
end
# Returns a new ValueUnit scaled by the given factor
def scale(factor)
if factor.present?
parsed_factor = ParsedNumber.new(factor)
ScaleConversion.new(parsed_factor).convert(self)
else
self
end
end
# Returns a new ValueUnit with the given new_parsed_unit. If converting between mass and volume,
# also requires a density UnitValue
def convert(new_unit, density = nil)
new_parsed_unit = ParsedUnit.new(new_unit)
parsed_density = density ? ValueUnit.for(density) : nil
if new_parsed_unit.unit != self.unit.unit
ConvertConversion.new(new_parsed_unit, parsed_density).convert(self)
else
self
end
end
def auto_unit
AutoUnitConversion.new.convert(self)
end
2016-02-27 20:12:41 -06:00
def to_metric
MetricUnitConversion.new.convert(self)
end
def to_standard
StandardUnitConversion.new.convert(self)
end
def to_mass(density)
parsed_density = ValueUnit.for(density)
MassUnitConversion.new(parsed_density).convert(self)
end
def to_volume(density)
parsed_density = ValueUnit.for(density)
VolumeUnitConversion.new(parsed_density).convert(self)
end
def density?
unit.density?
end
def volume?
unit.volume?
end
def mass?
unit.mass?
end
def pretty_value
formatter.format(value.value)
end
end
class ValueNoUnit < ValueUnit
def initialize(value, formatter = nil)
@value = value
@formatter = formatter || NumberFormatter.for(value, unit)
end
def to_s
"#{pretty_value}"
end
def unit
nil
end
def unitwise
raise UnknownUnitError, "No unit value provided"
end
def convert(new_parsed_unit, density_unit_value = nil)
raise UnknownUnitError, "No unit value provided"
end
def density?
false
end
def volume?
false
end
def mass?
false
end
end
end