2012-07-02 2 views
4

Ruby에서 사용자 정의 setter 및 getter 메소드를 작성하는 표준 방법이 궁금합니다. 일반적으로, 나는 attr_accessor을 통해 이것을 할 것이지만 나는 DSL을 만드는 맥락에있다.Ruby를 하나의 메소드로 가져오고 설정하기

def duration(dur) 
@duration = dur 
end 

그러나 이것은 게터 a를 구현한다 : 그들은 이런 식으로 구현해야,

work do 
duration 15 
priority 5 
end 

을 따라서하십시오 DSL에서 세터가 (지역 변수를 생성 할 = 기호를 사용)과 같이 호출 bit tricky : 같은 이름이지만 인자가없는 메소드를 만들면 setter를 덮어 씁니다.

def duration(dur=nil) 
return @duration = dur if dur 
return @duration if @duration 
raise AttributeNotDefinedException, "Attribute '#{__method__}' hasn't been set" 
end 

이 그것에 대해 갈 수있는 좋은 방법입니다 :

그래서 나는 설정과 점점 둘 다 할 사용자 정의 방법을 썼다? 다음은 테스트 케이스와 요지는 다음과 같습니다

Ruby Custom Getters & Setters

감사합니다!

답변

9

단지이 방법을 사용하여 nil 다시 @duration을 설정할 수 없습니다 의미하기 때문에이 내가 일반적으로 할 것 인 것이다 기간을 0으로 설정하십시오. 나는이

def duration(*args) 
    @duration = args.first unless args.empty? 
    @duration 
end 

명이 인수의 수를 통과 수에 따라 무엇을 선택하도록 허용하고 두 가지 방법을 생각할 수있다. 둘 이상의 인수가 전달되면 예외를 발생시킬 수도 있습니다.

또 다른 방법이 기본 인수 조금을 이용

def duration(value = (getter=true;nil)) 
    @duration = value unless getter 
    @duration 
end 

입니다 : 그들은 꽤 많이 표현식이 될 수 있습니다.

인수가없는 경우 getter이 true로 설정되었지만 인수가 제공되면 (nil이더라도) 기본값은 평가되지 않습니다. 로컬 변수 범위가 작동하는 방법 때문에 getter은 끝이 없습니다.

약간 작은 영리하지만 방법 본체 자체가 깨끗합니다.

+0

이것은 "영리한"것일 수 있지만 꽤 잘 알려진 관용어이며, 그래서 나는 그것을 코드 리뷰에서 확실히 슬라이드시킬 것이다. –

+0

감사합니다. 이들은 훌륭한 아이디어입니다. 값을 0으로 설정하는 유스 케이스가 없지만 어쨌든 그것을 덮는 방법을 알고있는 것이 좋습니다. – abbottjam

0

값이 설정되지 않은 경우 오류가 발생한다는 것이 이상하게 보일지라도 나에게 좋을 것 같습니다.

def duration(dur=nil) 
@duration = dur if dur 
@duration 
end 

그러나 이것은 단순한 접근 방식은 당신이 까다 경우 사용자가 설정하려는 경우입니다

+0

되지 않음 오류 (즉, 너무 과감한 것) 미정 대체 할 수 할 수 있지만, 예외, 즉 입력은 불법이 아니라 거짓입니다. nil을 반환하는 예외를 발생시키는 것을 선호하는 이유는 호출자에게 전파되지 않고 메소드가 nil에서 호출 될 때와 반대로 즉각적으로 발견된다는 것입니다. [Watch screencast] (https://www.destroyallsoftware.com/screencasts/catalog/how-and-why-to-avoid-nil) – abbottjam

2

이렇게하려면 기본 클래스를 DSL에서 분리하는 편을 선호합니다. 즉, 보통 접근자인 Work 클래스를 durationduration=으로 만듭니다. 당신이 DSL을 통해 작업 클래스를 사용하여 원하는 목적지

class AccessorMultiplexer 

    def initialize(target) 
    @target = target 
    end 

    def method_missing(method, *args) 
    method = "#{method}=" unless args.empty? 
    @target.send method, *args 
    end 

end 

, 당신은 그것을 감싸는 것 : 그리고 DSL을 통해 그 클래스를 사용하는이 같은 상황에 의해 접근자를 호출 할 수있는 무언가로 작업 인스턴스를 포장 AccessorMultiplexer.new(work).

래퍼에서 메타 프로그래밍에 반대한다면 method_missing을 사용하지 않고도 동일한 작업을 수행하는 특정 WorkDSL 래퍼를 만들 수 있습니다. 그러나 그것은 분리를 유지하고 DSL 구문의 변덕에 의해 Work 클래스가 오염되지 않도록합니다. DSL이있는 코드에서 Work 클래스를 사용하는 것이 좋습니다. 갈퀴 또는 대본 또는 - 누가 알습니까.

( codereview에 내 대답에서 적응.)

+0

나는 이별에 대한 생각을 좋아한다. 그래서 나는이 생각들을 추구 할 것이다. 하지만 WorkDSL 래퍼에서'method_missing' 대신 무엇을 사용하겠습니까? 차라리 그 방법을 사용하지 않을 것입니다 -이 상황에 대해서는 너무나 '모두'보이는 것 같습니다. 감사! – abbottjam

0

내가 보통이

def duration dur='UNDEFINED' 
    @duration = dur if dur != 'UNDEFINED' 
    @duration 
end 

당신이 좋아하는 일에

관련 문제