2011-12-10 3 views
3

나는 추가 동작으로 float처럼 동작하려는 Angle 클래스를가집니다. float를 포함하는 클래스를 작성하고 알 수없는 모든 메소드를 프록시합니다.클래스 인스턴스를 Ruby에서 Float으로 자동 캐스팅하려면 어떻게해야합니까?

class Angle 
    include Math 
    def initialize(angle=0.0) 
    @angle = Float(angle) 

    # Normalize the angle 
    @angle = @angle.modulo(PI*2) 
    end 

    def to_f 
    @angle.to_f 
    end 

    # Other functionality... 

    def method_missing(message, *args, &block) 
    if block_given? 
     @angle.public_send(message, *args, &block) 
    else 
     @angle.public_send(message, *args) 
    end 
    end 
end 

잘 작동합니다. 그러나 trig 연산과 함께 사용하려고 할 때

> a = Angle.new(0.0) 
=> #<Angle:0x00000000cdb220 @angle=0.0> 
@angle=0.0 
> Math.cos(a) 
TypeError: can't convert Angle into Float 

가 나는의 (a) float로 변환하는 플로트를 사용할 수 알지만,이 클래스는 플로트처럼 행동 할 이후는 불편 :와 Math.cos, 내가 얻을. 이러한 경우 각도를 자동으로 부동으로 변환하는 방법이 있습니까?

답변

3

implementation of Math.cos에서 Need_Float라는 매크로 (which then calls a function rb_to_float)를 호출하는 것을 볼 수 있습니다. Line 2441 of rb_to_float checks to see if the object passed in is of type Numeric. 따라서 수학 함수 모음에서 부동 소수점 클래스로 동작하는 유일한 방법은 Numeric 또는 Numeric의 자손에서 상속받는 것입니다. 따라서, 코드의 수정이 예상대로 작동합니다

class Angle < Numeric 
    include Math 
    def initialize(angle=0.0) 
    @angle = Float(angle) 

    # Normalize the angle 
    @angle = @angle.modulo(PI*2) 
    end 

    def to_f 
    @angle.to_f 
    end 

    # Other functionality... 

    def method_missing(message, *args, &block) 
    if block_given? 
     @angle.public_send(message, *args, &block) 
    else 
     @angle.public_send(message, *args) 
    end 
    end 
end 

if __FILE__ == $0 
    a = Angle.new(0.0) 
    p Math.cos(a) 
end 

나는 숫자에서 상속 어떤 부작용이있을 것이다 모르겠지만, 불행하게도 이것이 당신의 코드가 작동 당신이 그것을 원하는 방법이 할 수있는 유일한 방법처럼 보인다 에.

+1

앵글을 구현 할 수 없습니다 : 수학은 내가 정말 관심있는 유일한 모듈이다, 그래서 그것을위한 프록시 할 수 있습니다 : 위의 각도 클래스 정의와 지금

module Stdlib; end ::Stdlib::Math = ::Math module AngleMath # Copy constants Stdlib::Math.constants.each do |c| self.const_set(c, ::Stdlib::Math.const_get(c)) end def self.map_angles_to_floats(args) args.map do |a| a.kind_of?(Angle)? a.to_f: a end end def self.method_missing(message, *args, &block) if block_given? ::Stdlib::Math.public_send(message, *map_angles_to_floats(args), &block) else ::Stdlib::Math.public_send(message, *map_angles_to_floats(args)) end end end ::Math = AngleMath 

을 to_float'? –

+0

to_ary 및 to_proc과 유사한 to_float 강제 변환 방법이있을 것으로 기대했지만 루비에는없는 것으로 나타났습니다. – phiggy

+0

흥미로운 해결 방법. 아마도 Float 메소드가 Numeric 메소드 대신 호출되도록해야 할 것입니다. –

0

이것은 내가 독자적으로 생각한 것입니다. `

a = Angle.new(0.0) 
# => #<Angle:0x00000000e6dc28 @angle=0.0> 
Math.cos(a) 
# => 1.0 
관련 문제