parsley/lib/unit_conversion/conversions.rb

84 lines
2.3 KiB
Ruby
Raw Normal View History

module UnitConversion
class Conversion
end
class ScaleConversion < Conversion
def initialize(parsed_factor)
@factor = parsed_factor
end
def convert(value_unit)
value = @factor.value * value_unit.value.value
ValueUnit.for(value, value_unit.unit, value_unit.formatter)
end
end
class ConvertConversion < Conversion
def initialize(parsed_unit, density_unit_value = nil)
@target_unit = parsed_unit
raise UnknownUnitError, "#{density_unit_value} is not a density" if density_unit_value && !density_unit_value.density?
@density = density_unit_value
end
def convert(value_unit)
input = value_unit.unitwise
if value_unit.volume? && @target_unit.mass?
raise MissingDensityError, "Cannot convert #{value_unit.unit} to #{@target_unit} without density" unless @density
input = input * @density.unitwise
elsif value_unit.mass? && @target_unit.volume?
raise MissingDensityError, "Cannot convert #{value_unit.unit} to #{@target_unit} without density" unless @density
input = input / @density.unitwise
end
input = input.convert_to @target_unit.unit
formatter = @target_unit.metric? ? DecimalFormatter.new : value_unit.formatter
ValueUnit.for(input.value, @target_unit, formatter)
end
end
class AutoUnitConversion < Conversion
def convert(value_unit)
unless known_auto_unit?(value_unit.unit)
return value_unit
end
value = value_unit.raw_value
unit = value_unit.unit.unit
new_unit = unit
unit_orders = UNIT_ORDERS.values.detect { |orders| orders.include?(unit.to_sym) }
unit_range = UNIT_RANGES[unit.to_sym]
if value < unit_range.first
unit_orders = unit_orders.reverse
end
idx = unit_orders.index(new_unit.to_sym)
while !unit_range.include?(value) && idx < (unit_orders.length - 1)
idx += 1
next_unit = unit_orders[idx]
value = Unitwise(value, new_unit).convert_to(next_unit).value
new_unit = next_unit.to_s
unit_range = UNIT_RANGES[new_unit.to_sym]
end
ValueUnit.for(value, new_unit, value_unit.formatter)
end
def known_auto_unit?(unit)
unit && UNIT_ORDERS.values.flatten.include?(unit.unit.to_sym)
end
end
end