Skip to content

Instantly share code, notes, and snippets.

@apeiros
Last active August 13, 2016 23:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apeiros/9c9b9d39292bbeb86357f95961bcdd17 to your computer and use it in GitHub Desktop.
Save apeiros/9c9b9d39292bbeb86357f95961bcdd17 to your computer and use it in GitHub Desktop.
class Temperature
KelvinToCelsius = 273.15
KelvinToFahrenheit = 459.67
FahrenheitFactor = 5.0/9
def self.from_kelvin(kelvin) # could just alias
new(k: kelvin)
end
def self.from_celsius(celsius) # IMO should be just named "celsius"
new(c: celsius)
end
def self.from_fahrenheit(fahrenheit)
new(f: fahrenheit)
end
attr_reader :in_kelvin
def initialize(k: nil, c: nil, f: nil)
if (k && c) || (c && f) || (k && f)
raise ArgumentError, "Must only pass one of k, c or f"
elsif k
@in_kelvin = k
elsif c
@in_kelvin = (c + KelvinToCelsius)
elsif f
@in_kelvin = ((f + KelvinToFahrenheit) * FahrenheitFactor)
else
raise ArgumentError, "Must only pass at least one of kelvin, c or f"
end
end
def in_celsius
@in_kelvin - KelvinToCelsius
end
def in_fahrenheit
(@in_kelvin / FahrenheitFactor) - KelvinToFahrenheit
end
end
# @example
# Temperature.new(273.15).celsius # => 0.0
# Temperature.celsius(50).in_unit(:fahrenheit) # => (122/1)
# Temperature.from_unit(50, :celsius).to_s(:fahrenheit) # => "122.00 °F"
class Temperature
CelsiusSummand = 27315/100r
FahrenheitSummand = 45967/100r
FahrenheitFactor = 5/9r
@inspect_unit = :kelvin
class << self
attr_accessor :inspect_unit
end
def self.symbol(unit)
case unit
when :kelvin then "K"
when :celsius then "°C"
when :fahrenheit then "°F"
else raise ArgumentError, "Unknown unit #{unit.inspect}, expected :kelvin, :celsius or :fahrenheit"
end
end
def self.from_unit(value, unit)
case unit
when :kelvin then kelvin(value)
when :celsius then celsius(value)
when :fahrenheit then fahrenheit(value)
else raise ArgumentError, "Unknown unit #{unit.inspect}, expected :kelvin, :celsius or :fahrenheit"
end
end
def self.kelvin(kelvin)
new(kelvin)
end
def self.celsius(celsius)
new(celsius + CelsiusSummand)
end
def self.fahrenheit(fahrenheit)
new((fahrenheit + FahrenheitSummand) * FahrenheitFactor)
end
attr_reader :kelvin
def initialize(kelvin)
raise ArgumentError, "Invalid value, kelvin must be zero or positive" if kelvin < 0
@kelvin = kelvin
end
def celsius
@kelvin - CelsiusSummand
end
def fahrenheit
(@kelvin / FahrenheitFactor) - FahrenheitSummand
end
def in_unit(unit)
case unit
when :kelvin then kelvin
when :celsius then celsius
when :fahrenheit then fahrenheit
else raise ArgumentError, "Unknown unit #{unit.inspect}, expected :kelvin, :celsius or :fahrenheit"
end
end
def to_s(positional_unit=:kelvin, unit: nil, precision: 2)
unit ||= positional_unit
value = in_unit(unit)
sprintf "%.*f\u00a0%s", precision, value, self.class.symbol(unit)
end
def inspect
"<#{to_s(self.class.inspect_unit)}>"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment