确定要访问的变量

时间:2014-05-23 12:42:47

标签: ruby

例如,我有一个包含@fahrenheit@celsius实例变量的Temperature类。

我还有两种转换温度的方法in_fahrenheitin_celsius

使用可以接受选项哈希的构造函数初始化实例变量。

是否有任何可能的方法以某种方式实现方法,以便rspec是

Temperature.new(:f => 212).in_celsius.should == 100

Temperature.new(:c => 50).in_celsius.should == 50

该方法可以判断正在访问哪个选项哈希并返回正确的哈希?

我知道的一种方法是删除@fahrenheit变量,然后根据选项哈希@celsius a include?或{ {1}}。

3 个答案:

答案 0 :(得分:3)

为什么不使用课程?您可以实现工厂方法并返回FahrenheitCelsius的实例,具体取决于提供的密钥:

module Temperature
  def self.parse(hash)
    if hash.has_key? :f
      Fahrenheit.new(hash[:f])
    elsif hash.has_key? :c
      Celsius.new(hash[:c])
    end
  end
end

用法:

Temperature.parse(f: 212)               #=> 212 °F
Temperature.parse(f: 212).in_celsius    #=> (100/1) °C
Temperature.parse(c: 50)                #=> 50 °C
Temperature.parse(c: 50).in_celsius     #=> 50 °C
Temperature.parse(c: 50).in_fahrenheit  #=> (122/1) °F

Temperature.parse(c: 100) == Temperature.parse(f: 212) #=> true

我在这里使用rational numbers来避免舍入错误。

上例中使用的FahrenheitCelsius类的实现:

require 'rational'

module Temperature

  class Fahrenheit
    attr_reader :value

    def initialize(value)
      @value = value
    end

    def ==(other)
      value == other.in_fahrenheit.value
    end

    def in_fahrenheit
      self
    end

    def in_celsius
      Celsius.new(Rational(5, 9) * (@value - 32))
    end

    def inspect
      "#{@value.inspect} °F"
    end
  end

  class Celsius
    attr_reader :value

    def initialize(value)
      @value = value
    end

    def ==(other)
      value == other.in_celsius.value
    end

    def in_fahrenheit
      Fahrenheit.new(Rational(9, 5) * @value + 32)
    end

    def in_celsius
      self
    end

    def inspect
      "#{@value.inspect} °C"
    end
  end

end

答案 1 :(得分:1)

你可以做一些简单的事情

def in_celsius
  result = @celsius
  result ||= (@fahrenheit - 32 ) * 5.0 / 9
  result
end

以及in_fahrenheit

的相关方法

您需要做的唯一事情就是初始化正确的实例变量@celsius@fahrenheit

例如

if opts[:f] != nil
  @fahrenheit = opts[:f]
elsif opts[:c] != nil
  @celsius = opts[:c]
end

答案 2 :(得分:1)

我会做这样的事情,因为我认为一个类应该总是以最简单的格式存储它的数据(在这种情况下是SI单位开尔文)。此外,我喜欢new方法,它们按预期工作(在这种情况下采用开尔文单位并使用哈希作为后备)。

class Temperatur
  attr_accessor :kelvin

  def initialize(degree)
    if degree.is_a?(Numeric)
      @kelvin = kelvin
    else
      @kelvin = from_celsius(args[:c]) || from_fahrenheit(args[:f])
    end
  end

  def fahrenheit
    @kelvin * 1,8 - 459,67
  end

  def celsius
    @kelvin + 273,15
  end

private

  def from_fahrenheit(fahrenheit)
    if fahrenheit
      (fahrenheit.to_f + 459,67) * 5 ⁄ 9
    end
  end

  def from_celsius(celsius)
    if celsius
      celsius.to_f - 273,15
    end
  end

end