2010-07-30 5 views
51

나는 날짜가 바뀔 때마다 루비 파일을 추출하는 루비 코드를 돌리고있다. 파일에서, 나는 다음과 같은 기능을 가지고 싶습니다 물론, 그들은 통역이 원치 않는 때마다 경고 "이미 일정 초기화"를 표시하게,경고없이 Ruby 상수를 재정의하는 방법은 무엇입니까?

Tau = 2 * Pi 

추천하고, 일정한 정의를, 그래서 :

Tau = 2 * Pi unless defined?(Tau) 

을하지만 우아하고 약간 젖은 (안 DRY) :

def_if_not_defined(:Tau, 2 * Pi) 
redef_without_warning(:Tau, 2 * Pi) 

이 같은 내 모든 상수 정의를 작성하여 경고를 피할 수 있습니다.

더 좋은 방법이 있습니까 def_if_not_defined? 그리고 어떻게 redef_without_warning에?

- 스티브에

솔루션 덕분에 :

class Object 
    def def_if_not_defined(const, value) 
    mod = self.is_a?(Module) ? self : self.class 
    mod.const_set(const, value) unless mod.const_defined?(const) 
    end 

    def redef_without_warning(const, value) 
    mod = self.is_a?(Module) ? self : self.class 
    mod.send(:remove_const, const) if mod.const_defined?(const) 
    mod.const_set(const, value) 
    end 
end 

A = 1 
redef_without_warning :A, 2 
fail 'unit test' unless A == 2 
module M 
    B = 10 
    redef_without_warning :B, 20 
end 
fail 'unit test' unless M::B == 20 

-

이 질문은 오래되었습니다. 위 코드는 Ruby 1.8에서만 필요합니다. Ruby 1.9에서 P3t3rU5의 대답은 경고를 표시하지 않고 단순히 더 나은 것입니다.

+5

왜 상수를 다시 정의 하시겠습니까? 자신의 클래스 나 모듈에 네임 스페이스 상수를 유지하는 것이 더 좋습니다. 이렇게하면 다른 상수와 충돌하지 않게됩니다. –

+1

자동 상수 코드 재 로더를 사용하지 않는 것처럼 자연스럽게 상수를 사용하기 때문에 상수를 다시 정의해야하므로 "상수를 사용하지 마십시오"라는 대답을 받아들이지 않을 것입니다. –

+2

'타우 = 2 * 파이가 정의되지 않았다면 (타우)'에 관해서는 무엇이 비천하고 DRY가 아닌가? – jrdioko

답변

58

다음 모듈은 원하는대로 할 수 있습니다. 이 솔루션

module RemovableConstants 

    def def_if_not_defined(const, value) 
    self.class.const_set(const, value) unless self.class.const_defined?(const) 
    end 

    def redef_without_warning(const, value) 
    self.class.send(:remove_const, const) if self.class.const_defined?(const) 
    self.class.const_set(const, value) 
    end 
end 

에 그리고

class A 
    include RemovableConstants 

    def initialize 
    def_if_not_defined("Foo", "ABC") 
    def_if_not_defined("Bar", "DEF") 
    end 

    def show_constants 
    puts "Foo is #{Foo}" 
    puts "Bar is #{Bar}" 
    end 

    def reload 
    redef_without_warning("Foo", "GHI") 
    redef_without_warning("Bar", "JKL") 
    end 

end 

a = A.new 
a.show_constants 
a.reload 
a.show_constants 

그것을 사용하는 예로서 몇 가지 포인터를 제공 할 수없는 경우 내가 어떤 깨진 한 경우

Foo is ABC 
Bar is DEF 
Foo is GHI 
Bar is JKL 

나를 용서 다음과 같은 출력을 제공합니다 루비 타부 (ruby tabuos) 여기에서 나는 여전히 내 머리 부분을 모듈 주위에 가지고있다. 모듈 : Rubey 내의 클래스 : Eigenclass 구조체

+0

확실히,이 대답의 열쇠는 Object.const_defined? ('Tau')'의 경우, Object.send (: remove_const, 'Tau')를 먼저 호출하는 것입니다.이 경우, 상수는 정의되지 않으므로 경고를 선점합니다. 훌륭한 접근 방식. – ghayes

+0

클래스 (인스턴스가 아님) 범위에 있다면'send (: remove_const, : CONST) if const_defined? (: CONST)'. – thewoolleyman

4

값을 재정의하려면 상수를 사용하지 말고 대신 전역 변수 ($ tau = 2 * Pi)를 사용하십시오. 그러나 이는 좋은 습관은 아닙니다. 적절한 클래스의 인스턴스 변수로 만들어야합니다.

다른 경우에는 Tau = 2 * Pi unless defined?(Tau)이 가장 정확하고 가장 읽기 쉽기 때문에 가장 세련된 솔루션입니다. (당신이 nil 또는 false로 설정 상수가 IE) 상수의 값이 꽤 이상한하지 않는 한

2

, 최선의 선택 조건 할당 연산자를 사용하는 것입니다 :이 경우 2π하는 타우를 설정합니다 Tau ||= 2*Pi

그것을 nil, false이거나 정의되지 않은 경우 혼자 남겨 둡니다.

+1

멋진 아이디어 ... 불행히도, 이식성이 좋지 않습니다. 루비 버전 및 구현 (루비/jruby)에 따라 상수에 대한 영향이 || =로 3 가지 다른 결과를 제공합니다. (jruby1.5) 의도적으로 조용하게 작동합니다. "초기화되지 않은 상수"오류 (ruby1.8)가 발생하거나 영향이없는 경우에도 경고가 표시됩니다 (jruby1.2). –

3

$ VERBOSE을 사용하여 경고를 표시하지 않는 또 다른 방법은 다음과 같습니다. http://mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/

+2

예. 당신의 링크에서 언급했듯이 Rails에는 silence_warnings의 더 나은 구현이 존재합니다 : http://api.rubyonrails.org/classes/Kernel.html#M002564 그러나이 접근법은 다른 접근법에 부작용이있을 수 있기 때문에 수용된 응답보다 열등합니다 스레드. –

1

다음은 어떻게됩니까?

TAU ||= 2 * Pi 

내가 작업중인 보석에서 작동합니다.

+5

이것은 상수를 다시 정의하지 않으므로 질문에 대한 대답이 아닙니다. 어떻게 8 표를 얻었습니까? – jrochkind

+1

글쎄, 그것은 def_if_not_defined (: Tau, 2 * Pi)에 답하고 원래의 질문이라고 확신하지 못했습니다. 오래 전이었습니다 – P3t3rU5

+1

또한 상수를 재정의하는 것은 할 수 있더라도 언어에 대한 남용입니다 , 반드시해야한다는 뜻은 아닙니다. – P3t3rU5

관련 문제