2016-02-02 15:48:20 -06:00
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
2016-02-02 15:48:20 -06:00
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
2016-02-27 20:23:14 -06:00
def change_formatter ( formatter )
@formatter = formatter
self
end
2016-02-02 15:48:20 -06:00
# 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
2016-02-02 15:48:20 -06:00
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